ExPlasma.Transaction behaviour (ExPlasma v0.2.0)

Contains the base structure of transactions.

Link to this section Summary

Functions

Attempt to decode the given RLP list into a Transaction.

Encode the given Transaction into an RLP encodable list.

Throwing version of encode/2

Returns the hash of the transaction involved without the signatures

Signs the inputs of the transaction with the given keys in the corresponding order. Only signs transactions that implement the ExPlasma.TypedData protocol.

Maps the given RLP list into a transaction.

Encode the given Transaction into an RLP encodable list.

Statelessly validate a transation.

Recovers the witnesses as addresses and add them to the transaction struct under the witnesses key.

Link to this section Types

Link to this type

decoding_error()

Specs

decoding_error() :: :malformed_rlp | mapping_error()
Link to this type

encoding_error()

Specs

encoding_error() :: :unrecognized_transaction_type
Link to this type

mapping_error()

Specs

mapping_error() ::
  :malformed_transaction | :unrecognized_transaction_type | atom()

Specs

metadata() :: <<_::256>> | nil

Specs

nonce() :: ExPlasma.Crypto.hash_t() | nil

Specs

outputs() :: [ExPlasma.Output.t()] | []

Specs

t() :: %ExPlasma.Transaction{
  inputs: outputs(),
  metadata: metadata(),
  nonce: nonce(),
  outputs: outputs(),
  sigs: ExPlasma.Transaction.Signed.sigs(),
  tx_data: non_neg_integer(),
  tx_type: pos_integer(),
  witnesses: [ExPlasma.Transaction.Witness.t()]
}

Specs

tx_bytes() :: binary()

Specs

tx_hash() :: ExPlasma.Crypto.hash_t()

Link to this section Functions

Link to this function

decode(tx_bytes, opts \\ [])

Specs

decode(tx_bytes(), keyword()) :: {:ok, t()} | {:error, decoding_error()}

Attempt to decode the given RLP list into a Transaction.

If signed: false is given in the list of opts, expects the underlying RLP to not contain signatures.

Only validates that the RLP is structurally correct and that the tx type is supported. Does not perform any other kind of validation, use validate/1 for that.

Example

iex> rlp = <<248, 117, 192, 1, 225, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
...>  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 237, 1, 235, 148, 29, 246,
...>  47, 41, 27, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55, 0,
...>  110, 148, 46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65,
...>  226, 241, 55, 0, 110, 1, 128, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
...>  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
iex> ExPlasma.Transaction.decode(rlp)
{:ok,
  %ExPlasma.Transaction{
    inputs: [
      %ExPlasma.Output{
        output_data: nil,
        output_id: %{blknum: 0, oindex: 0, position: 0, txindex: 0},
        output_type: nil
      }
    ],
    metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
    outputs: [
      %ExPlasma.Output{
        output_data: %{
          amount: 1,
          output_guard: <<29, 246, 47, 41, 27, 46, 150, 159, 176, 132, 157, 153,
            217, 206, 65, 226, 241, 55, 0, 110>>,
          token: <<46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206,
            65, 226, 241, 55, 0, 110>>
        },
        output_id: nil,
        output_type: 1
      }
    ],
    witnesses: [],
    sigs: [],
    tx_data: 0,
    tx_type: 1
  }
}
Link to this function

encode(transaction, opts \\ [])

Specs

encode(t() | list(), keyword()) ::
  {:ok, tx_bytes()} | {:error, encoding_error()}

Encode the given Transaction into an RLP encodable list.

If signed: false is given in the list of opts, will encode the transaction without its signatures.

Example

iex> txn =
...>  %ExPlasma.Transaction{
...>    inputs: [
...>      %ExPlasma.Output{
...>        output_data: nil,
...>        output_id: %{blknum: 0, oindex: 0, position: 0, txindex: 0},
...>        output_type: nil
...>      }
...>    ],
...>    metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
...>    outputs: [
...>      %ExPlasma.Output{
...>        output_data: %{
...>          amount: 1,
...>          output_guard: <<29, 246, 47, 41, 27, 46, 150, 159, 176, 132, 157, 153,
...>            217, 206, 65, 226, 241, 55, 0, 110>>,
...>          token: <<46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206,
...>            65, 226, 241, 55, 0, 110>>
...>        },
...>        output_id: nil,
...>        output_type: 1
...>      }
...>    ],
...>    sigs: [],
...>    tx_data: 0,
...>    tx_type: 1
...>  }
iex> ExPlasma.Transaction.encode(txn, signed: :false)
{:ok, <<248, 116, 1, 225, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 237, 1, 235, 148, 29, 246, 47,
41, 27, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55, 0, 110,
148, 46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226,
241, 55, 0, 110, 1, 128, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>}
Link to this function

encode!(rlp_items, opts \\ [])

Throwing version of encode/2

Link to this function

hash(transaction)

Specs

hash(t() | tx_bytes()) :: {:ok, tx_hash()} | {:error, encoding_error()}

Returns the hash of the transaction involved without the signatures

Link to this function

sign(transaction, keys)

Signs the inputs of the transaction with the given keys in the corresponding order. Only signs transactions that implement the ExPlasma.TypedData protocol.

Returns

  • {:ok, %Transaction{}} with sigs when succesfuly signed
  • {:error, :not_signable} when the given transaction is not supported.

Example

iex> key = "0x79298b0292bbfa9b15705c56b6133201c62b798f102d7d096d31d7637f9b2382"
iex> txn = %ExPlasma.Transaction{tx_type: 1}
iex> ExPlasma.Transaction.sign(txn, [key])
{:ok, %ExPlasma.Transaction{
  sigs: [
        <<129, 213, 32, 15, 183, 218, 255, 22, 82, 95, 22, 86, 103, 227, 92, 109, 9,
          89, 7, 142, 235, 107, 203, 29, 20, 231, 91, 168, 255, 119, 204, 239, 44,
          125, 76, 109, 200, 196, 204, 230, 224, 241, 84, 75, 9, 3, 160, 177, 37,
          181, 174, 98, 51, 15, 136, 235, 47, 96, 15, 209, 45, 85, 153, 2, 28>>
      ],
  inputs: [],
  metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
  outputs: [],
  tx_type: 1,
  witnesses: [],
  tx_data: 0
}}

Specs

to_map(list()) :: {:ok, t()} | {:error, mapping_error()}

Maps the given RLP list into a transaction.

When the RLP list starts with a list, assumes it's the sigs and map it accordingly. If not starting with a list, assumes it's the transaction type.

Only validates that the RLP is structurally correct. Does not perform any other kind of validation, use validate/1 for that.

Link to this function

to_rlp(transaction, opts \\ [])

Specs

to_rlp(t(), keyword()) ::
  {:ok, list()} | {:error, :unrecognized_transaction_type}

Encode the given Transaction into an RLP encodable list.

If signed: false is given in the list of opts, will not prepend the signatures to the RLP list.

Example

iex> txn =
...>  %ExPlasma.Transaction{
...>    inputs: [
...>      %ExPlasma.Output{
...>        output_data: nil,
...>        output_id: %{blknum: 0, oindex: 0, position: 0, txindex: 0},
...>        output_type: nil
...>      }
...>    ],
...>    metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
...>    outputs: [
...>      %ExPlasma.Output{
...>        output_data: %{
...>          amount: 1,
...>          output_guard: <<29, 246, 47, 41, 27, 46, 150, 159, 176, 132, 157, 153,
...>            217, 206, 65, 226, 241, 55, 0, 110>>,
...>          token: <<46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206,
...>            65, 226, 241, 55, 0, 110>>
...>        },
...>        output_id: nil,
...>        output_type: 1
...>      }
...>    ],
...>    sigs: [],
...>    tx_data: <<0>>,
...>    tx_type: 1
...>  }
iex> ExPlasma.Transaction.to_rlp(txn)
{:ok, [
  [],
  <<1>>,
  [<<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>],
  [
    [
      <<1>>,
      [
        <<29, 246, 47, 41, 27, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55, 0, 110>>,
        <<46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55, 0, 110>>,
        <<1>>
      ]
    ]
  ],
  0,
  <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
]}
Link to this function

validate(transaction)

Statelessly validate a transation.

Example

iex> txn = %ExPlasma.Transaction{
...>  inputs: [
...>    %ExPlasma.Output{
...>      output_data: nil,
...>      output_id: %{blknum: 0, oindex: 0, position: 0, txindex: 0},
...>      output_type: nil
...>    }
...>  ],
...>  metadata: <<0::256>>,
...>  outputs: [
...>    %ExPlasma.Output{
...>      output_data: %{
...>        amount: <<0, 0, 0, 0, 0, 0, 0, 1>>,
...>        output_guard: <<29, 246, 47, 41, 27, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55, 0, 110>>,
...>        token: <<46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55, 0, 110>>
...>      },
...>      output_id: nil,
...>      output_type: 1
...>    }
...>  ],
...>  sigs: [],
...>  tx_data: 0,
...>  tx_type: 1
...>}
iex> :ok = ExPlasma.Transaction.validate(txn)
Link to this function

with_nonce(transaction, params)

Specs

with_nonce(t(), map()) :: {:ok, t()} | {:error, atom()}
Link to this function

with_witnesses(transaction)

Specs

with_witnesses(t()) ::
  {:ok, t()} | {:error, ExPlasma.Transaction.Witness.recovery_error()}

Recovers the witnesses as addresses and add them to the transaction struct under the witnesses key.

Link to this section Callbacks

Link to this callback

build_nonce(map)

Specs

build_nonce(map()) :: {:ok, nonce()} | {:error, atom()}

Specs

to_map(list()) :: {:ok, t()} | {:error, atom()}

Specs

to_rlp(t()) :: {:ok, list()} | {:error, atom()}

Specs

validate(t()) :: :ok | {:error, {atom(), atom()}}