Packages

A library for encoding, decoding and validating transactions used for the OMG Network Plasma contracts.

Current section

3 Versions

Jump to

Compare versions

43 files changed
+2899 additions
-1718 deletions
  @@ -0,0 +1,5 @@
1 + # Used by "mix format"
2 + [
3 + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
4 + line_length: 120
5 + ]
  @@ -0,0 +1,13 @@
1 + .PHONY: test
2 +
3 + test:
4 + mix test
5 +
6 + logs:
7 + docker-compose logs -f
8 + up:
9 + docker-compose up -d
10 + up-mocks:
11 + docker-compose -f docker-compose.yml -f docker-compose.conformance.yml up -d ganache mock-contracts
12 + down:
13 + docker-compose down
  @@ -1,10 +1,7 @@
1 - [![Coverage Status](https://coveralls.io/repos/github/omisego/ex_plasma/badge.svg?branch=master)](https://coveralls.io/github/omisego/ex_plasma?branch=master)
1 + ## ExPlasma
2 + [![Build Status](https://circleci.com/gh/omgnetwork/ex_plasma.svg?style=svg)](https://circleci.com/gh/omgnetwork/ex_plasma)
2 3
3 - # ExPlasma
4 -
5 - **TODO: Add description**
6 -
7 - (ExPlasma)[] is an elixir client library to interact with the OmiseGO Plasma contracts.
4 + ExPlasma is an Elixir library for encoding, decoding and validating transactions used for the OMG Network Plasma contracts.
8 5
9 6 ## Installation
10 7
  @@ -14,7 +11,7 @@ by adding `ex_plasma` to your list of dependencies in `mix.exs`:
14 11 ```elixir
15 12 def deps do
16 13 [
17 - {:ex_plasma, "~> 0.1.0"}
14 + {:ex_plasma, "~> 0.2.0"}
18 15 ]
19 16 end
20 17 ```
  @@ -23,31 +20,125 @@ You will also need to specify some configurations in your [config/config.exs]():
23 20
24 21 ```elixir
25 22 config :ex_plasma,
26 - authority_address: "0x22d491bde2303f2f43325b2108d26f1eaba1e32b",
27 - contract_address: "0xd17e1233a03affb9092d5109179b43d6a8828607",
28 - eth_vault_address: "0x1967d06b1faba91eaadb1be33b277447ea24fa0e",
29 - exit_game_address: "0x902719f192aa5240632f704aa7a94bab61b86550",
30 - gas: 1_000_000,
31 - gas_price: 1_000_000,
32 - standard_exit_bond_size: 14_000_000_000_000_000,
33 - eip_712_domain: [
34 - name: "ExPlasma",
35 - salt: "some-salt",
36 - verifying_contract: "contract_address",
23 + eip_712_domain: %{
24 + name: "OMG Network",
25 + salt: "0xfad5c7f626d80f9256ef01929f3beb96e058b8b4b0e3fe52d84f054c0e2a7a83",
26 + verifying_contract: "0xd17e1233a03affb9092d5109179b43d6a8828607",
37 27 version: "1"
38 - ]
28 + }
39 29 ```
40 30
41 - ## Setup (Mac OS)
31 + ## Setup
42 32
43 - 1. Clone the repo to your desktop `git@github.com:omisego/ex_plasma.git`
33 + `ExPlasma` requires Rust to be installed because it uses Rust NIFs for keccak hash and secp256k1.
34 +
35 + 1. Clone the repo to your desktop `git@github.com:omgnetwork/ex_plasma.git`
44 36 2. Run `mix compile` in your terminal.
45 37 3. If there are any unavailable dependencies, run `mix deps.get`.
46 - *If you run into any issues with* ***libsecp256k1_source***, *run* `brew install automake pkg-config libtool libffi gmp` *in your terminal.*
38 +
39 + ## Usage
40 +
41 + To build a transaction use `ExPlasma.Builder` module:
42 +
43 + ``` elixir
44 + {:ok, txn} =
45 + ExPlasma.payment_v1()
46 + |> ExPlasma.Builder.new()
47 + |> ExPlasma.Builder.add_input(blknum: 1, txindex: 0, oindex: 0)
48 + |> ExPlasma.Builder.add_output(output_type: 1, output_data: %{output_guard: <<1::160>>, token: <<0::160>>, amount: 1})
49 + |> ExPlasma.Builder.sign(["0x79298b0292bbfa9b15705c56b6133201c62b798f102d7d096d31d7637f9b2382"])
50 + {:ok,
51 + %ExPlasma.Transaction{
52 + inputs: [
53 + %ExPlasma.Output{
54 + output_data: nil,
55 + output_id: %{blknum: 1, oindex: 0, txindex: 0},
56 + output_type: nil
57 + }
58 + ],
59 + metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
61 + nonce: nil,
62 + outputs: [
63 + %ExPlasma.Output{
64 + output_data: %{
65 + amount: 1,
66 + output_guard: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 + 0, 1>>,
68 + token: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
69 + },
70 + output_id: nil,
71 + output_type: 1
72 + }
73 + ],
74 + sigs: [
75 + <<236, 177, 165, 5, 109, 208, 210, 116, 68, 176, 199, 17, 168, 29, 30, 198,
76 + 77, 45, 233, 147, 149, 38, 93, 136, 24, 98, 53, 218, 52, 177, 200, 127,
77 + 26, 6, 138, 17, 36, 52, 97, 152, 240, 222, ...>>
78 + ],
79 + tx_data: 0,
80 + tx_type: 1,
81 + witnesses: []
82 + }}
83 + ```
84 +
85 + You can encode a transaction using `ExPlasma.encode/2`:
86 +
87 + ``` elixir
88 + {:ok, rlp} = ExPlasma.encode(txn, signed: false)
89 + {:ok,
90 + <<248, 116, 1, 225, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 154, 202, 0, 238, 237, 1, 235, 148, 0, 0,
92 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 148, 0, 0, 0, 0, 0, 0,
93 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 128, 160, 0, 0, 0, 0, 0, 0, 0,
94 + 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>>}
95 + ```
96 +
97 + You can decode a transaction using `ExPlasma.decode/2`:
98 +
99 + ``` elixir
100 + {:ok, txn} = ExPlasma.decode(rlp, signed: false)
101 + {:ok,
102 + %ExPlasma.Transaction{
103 + inputs: [
104 + %ExPlasma.Output{
105 + output_data: nil,
106 + output_id: %{blknum: 1, oindex: 0, position: 1000000000, txindex: 0},
107 + output_type: nil
108 + }
109 + ],
110 + metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
112 + nonce: nil,
113 + outputs: [
114 + %ExPlasma.Output{
115 + output_data: %{
116 + amount: 1,
117 + output_guard: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 + 0, 1>>,
119 + token: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
120 + },
121 + output_id: nil,
122 + output_type: 1
123 + }
124 + ],
125 + sigs: [],
126 + tx_data: 0,
127 + tx_type: 1,
128 + witnesses: []
129 + }}
130 + ```
131 +
132 + You can validate a transaction using `ExPlasma.validate/1`:
133 +
134 + ``` elixir
135 + ExPlasma.validate(txn)
136 + ```
137 +
138 + View the [documentation](https://hexdocs.pm/ex_plasma)
47 139
48 140 ## Testing
49 141
50 -
51 142 You can run the tests by running;
52 143
53 144 ```sh
  @@ -56,21 +147,6 @@ mix credo
56 147 mix dialyzer
57 148 ```
58 149
59 - ### exvcr
60 -
61 - The test suite has network requests recorded by [exvcr](). To record new cassettes, spin up docker:
62 -
63 - ```sh
64 - docker-compose up
65 - ```
66 -
67 - Or alternatively, you can use the make command to spin up a detached docker compose.
68 -
69 - ```sh
70 - make up # docker-compose detached
71 - make logs # connects to logs from docker-compose
72 - ```
73 -
74 150 This will load up Ganche and the plasma contracts to deploy.
75 151
76 152
  @@ -86,18 +162,14 @@ mix test --only conformance
86 162
87 163 This will spin up ganache and deploy the mock contracts.
88 164
89 - ### Integration test
165 + ## Contributing
90 166
91 - We also have more integrated flows we need to test, such as the exit game. These use live interactions with
92 - the plasma framework contracts. To run those, you can execute:
167 + 1. [Fork it!](https://github.com/omgnetwork/ex_plasma)
168 + 2. Create your feature branch (`git checkout -b my-new-feature`)
169 + 3. Commit your changes (`git commit -am 'Add some feature'`)
170 + 4. Push to the branch (`git push origin my-new-feature`)
171 + 5. Create new Pull Request
93 172
94 - ```sh
95 - make up
96 - mix test --only integration
97 - ```
173 + ## License
98 174
99 - This will spin up ganache and deploy the plasma framework and run the integration suite.
100 -
101 - Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
102 - and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
103 - be found at [https://hexdocs.pm/ex_plasma](https://hexdocs.pm/ex_plasma).
175 + ExPlasma is released under the Apache-2.0 License.
  @@ -1,58 +1,69 @@
1 1 {<<"app">>,<<"ex_plasma">>}.
2 - {<<"build_tools">>,[<<"mix">>]}.
2 + {<<"build_tools">>,[<<"mix">>,<<"make">>]}.
3 3 {<<"description">>,
4 - <<"Elixir client library to the OmiseGO Plasma Framework">>}.
4 + <<"A library for encoding, decoding and validating transactions used for the OMG Network Plasma contracts.">>}.
5 5 {<<"elixir">>,<<"~> 1.8">>}.
6 6 {<<"files">>,
7 - [<<"lib">>,<<"lib/ex_plasma.ex">>,<<"lib/ex_plasma">>,
8 - <<"lib/ex_plasma/transaction.ex">>,<<"lib/ex_plasma/typed_data">>,
9 - <<"lib/ex_plasma/typed_data/utxo.ex">>,
10 - <<"lib/ex_plasma/typed_data/transactions.ex">>,<<"lib/ex_plasma/utxo">>,
11 - <<"lib/ex_plasma/block.ex">>,<<"lib/ex_plasma/transaction">>,
12 - <<"lib/ex_plasma/transaction/payment.ex">>,
13 - <<"lib/ex_plasma/transaction/deposit.ex">>,<<"lib/ex_plasma/client.ex">>,
14 - <<"lib/ex_plasma/typed_data.ex">>,<<"lib/ex_plasma/utxo.ex">>,
15 - <<"lib/ex_plasma/encoding.ex">>,<<"lib/ex_plasma/client">>,
16 - <<"lib/ex_plasma/client/config.ex">>,<<"lib/ex_plasma/client/event.ex">>,
17 - <<"lib/ex_plasma/client/state.ex">>,<<"mix.exs">>,<<"README.md">>,
18 - <<"LICENSE">>]}.
19 - {<<"licenses">>,[<<"Apache-2.0">>]}.
20 - {<<"links">>,[{<<"GitHub">>,<<"https://github.com/omisego/ex_plasma">>}]}.
7 + [<<"lib">>,<<"lib/ex_plasma">>,<<"lib/ex_plasma/in_flight_exit.ex">>,
8 + <<"lib/ex_plasma/typed_data">>,
9 + <<"lib/ex_plasma/typed_data/transaction.ex">>,
10 + <<"lib/ex_plasma/typed_data/output.ex">>,<<"lib/ex_plasma/signature.ex">>,
11 + <<"lib/ex_plasma/configuration.ex">>,<<"lib/ex_plasma/encoding.ex">>,
12 + <<"lib/ex_plasma/transaction.ex">>,<<"lib/ex_plasma/output">>,
13 + <<"lib/ex_plasma/output/position.ex">>,<<"lib/ex_plasma/output/position">>,
14 + <<"lib/ex_plasma/output/position/position_validator.ex">>,
15 + <<"lib/ex_plasma/output/type">>,
16 + <<"lib/ex_plasma/output/type/payment_v1.ex">>,
17 + <<"lib/ex_plasma/output/type/abstract_payment.ex">>,
18 + <<"lib/ex_plasma/output/type/empty.ex">>,
19 + <<"lib/ex_plasma/output/type/abstract_payment">>,
20 + <<"lib/ex_plasma/output/type/abstract_payment/abstract_payment_validator.ex">>,
21 + <<"lib/ex_plasma/output/type/fee.ex">>,<<"lib/ex_plasma/builder.ex">>,
22 + <<"lib/ex_plasma/utils">>,<<"lib/ex_plasma/utils/rlp_decoder.ex">>,
23 + <<"lib/ex_plasma/typed_data.ex">>,<<"lib/ex_plasma/output.ex">>,
24 + <<"lib/ex_plasma/configuration">>,
25 + <<"lib/ex_plasma/configuration/validator.ex">>,<<"lib/ex_plasma/block.ex">>,
26 + <<"lib/ex_plasma/crypto.ex">>,<<"lib/ex_plasma/merkle.ex">>,
27 + <<"lib/ex_plasma/transaction">>,
28 + <<"lib/ex_plasma/transaction/type_mapper.ex">>,
29 + <<"lib/ex_plasma/transaction/type">>,
30 + <<"lib/ex_plasma/transaction/type/payment_v1.ex">>,
31 + <<"lib/ex_plasma/transaction/type/fee">>,
32 + <<"lib/ex_plasma/transaction/type/fee/fee_validator.ex">>,
33 + <<"lib/ex_plasma/transaction/type/payment_v1">>,
34 + <<"lib/ex_plasma/transaction/type/payment_v1/payment_v1_validator.ex">>,
35 + <<"lib/ex_plasma/transaction/type/fee.ex">>,
36 + <<"lib/ex_plasma/transaction/witness.ex">>,
37 + <<"lib/ex_plasma/transaction/signed.ex">>,<<"lib/ex_plasma.ex">>,
38 + <<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>,
39 + <<"Makefile">>]}.
40 + {<<"licenses">>,[<<"Apache-2.0 License">>]}.
41 + {<<"links">>,[{<<"GitHub">>,<<"https://github.com/omgnetwork/ex_plasma">>}]}.
21 42 {<<"name">>,<<"ex_plasma">>}.
22 43 {<<"requirements">>,
23 - [[{<<"app">>,<<"ethereumex">>},
24 - {<<"name">>,<<"ethereumex">>},
25 - {<<"optional">>,false},
26 - {<<"repository">>,<<"hexpm">>},
27 - {<<"requirement">>,<<"~> 0.5.5">>}],
28 - [{<<"app">>,<<"ex_abi">>},
44 + [[{<<"app">>,<<"ex_abi">>},
29 45 {<<"name">>,<<"ex_abi">>},
30 46 {<<"optional">>,false},
31 47 {<<"repository">>,<<"hexpm">>},
32 - {<<"requirement">>,<<"~> 0.1.0">>}],
48 + {<<"requirement">>,<<"~> 0.5.1">>}],
33 49 [{<<"app">>,<<"ex_rlp">>},
34 50 {<<"name">>,<<"ex_rlp">>},
35 51 {<<"optional">>,false},
36 52 {<<"repository">>,<<"hexpm">>},
37 - {<<"requirement">>,<<"~> 0.5.2">>}],
38 - [{<<"app">>,<<"exth_crypto">>},
39 - {<<"name">>,<<"exth_crypto">>},
53 + {<<"requirement">>,<<"~> 0.5.3">>}],
54 + [{<<"app">>,<<"ex_keccak">>},
55 + {<<"name">>,<<"ex_keccak">>},
40 56 {<<"optional">>,false},
41 57 {<<"repository">>,<<"hexpm">>},
42 - {<<"requirement">>,<<"~> 0.1.0">>}],
43 - [{<<"app">>,<<"libsecp256k1">>},
44 - {<<"name">>,<<"libsecp256k1">>},
58 + {<<"requirement">>,<<"~> 0.1.2">>}],
59 + [{<<"app">>,<<"ex_secp256k1">>},
60 + {<<"name">>,<<"ex_secp256k1">>},
45 61 {<<"optional">>,false},
46 62 {<<"repository">>,<<"hexpm">>},
47 - {<<"requirement">>,<<"~> 0.1.0">>}],
63 + {<<"requirement">>,<<"~> 0.1.1">>}],
48 64 [{<<"app">>,<<"merkle_tree">>},
49 65 {<<"name">>,<<"merkle_tree">>},
50 66 {<<"optional">>,false},
51 67 {<<"repository">>,<<"hexpm">>},
52 - {<<"requirement">>,<<"~> 1.6.1">>}],
53 - [{<<"app">>,<<"ex_doc">>},
54 - {<<"name">>,<<"ex_doc">>},
55 - {<<"optional">>,false},
56 - {<<"repository">>,<<"hexpm">>},
57 - {<<"requirement">>,<<">= 0.0.0">>}]]}.
58 - {<<"version">>,<<"0.1.0">>}.
68 + {<<"requirement">>,<<"~> 2.0.0">>}]]}.
69 + {<<"version">>,<<"0.2.0">>}.
  @@ -4,141 +4,168 @@ defmodule ExPlasma do
4 4 """
5 5
6 6 alias ExPlasma.Transaction
7 - alias ExPlasma.Utxo
7 + alias ExPlasma.Transaction.TypeMapper
8 +
9 + # constants that identify payment types, make sure that
10 + # when we introduce a new payment type, you name it `paymentV2`
11 + # https://github.com/omisego/plasma-contracts/blob/6ab35256b805e25cfc30d85f95f0616415220b20/plasma_framework/docs/design/tx-types-dependencies.md
12 + @payment_v1 TypeMapper.tx_type_for(:tx_payment_v1)
13 + @fee TypeMapper.tx_type_for(:tx_fee_token_claim)
14 +
15 + @type transaction_type :: non_neg_integer()
8 16
9 17 @doc """
18 + Simple payment type V1
10 19
11 - Produces a RLP encoded transaction bytes for the given transaction data.
20 + ## Example
12 21
13 - ## Examples
14 -
15 - # Encode a transaction
16 - iex> {:ok, txn} = ExPlasma.Transaction.Payment.new(%{inputs: [], outputs: []})
17 - iex> ExPlasma.encode(txn)
18 - <<229, 1, 192, 192, 128, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
19 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
20 -
21 - # Encode a transaction rlp
22 - iex> rlp = [1, [], [], 0, <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>]
23 - iex> ExPlasma.encode(rlp)
24 - <<217, 128, 192, 192, 128, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25 - 0, 0, 0, 0>>
26 -
27 - Encode a signed transaction
28 - iex> {:ok, txn} = ExPlasma.Transaction.Payment.new(%{inputs: [], outputs: [], sigs: []})
29 - iex> ExPlasma.encode(txn)
30 - <<229, 1, 192, 192, 128, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
22 + iex> ExPlasma.payment_v1()
23 + 1
32 24 """
33 - @spec encode(Transaction.t() | Transaction.rlp()) :: <<_::632>>
34 - def encode(txn) when is_map(txn), do: Transaction.encode(txn)
35 -
36 - def encode(txn) when is_list(txn) do
37 - with {:ok, transaction} <- Transaction.new(txn), do: Transaction.encode(transaction)
38 - end
25 + @spec payment_v1() :: 1
26 + def payment_v1(), do: @payment_v1
39 27
40 28 @doc """
29 + Transaction fee claim V1
41 30
42 - ## Examples
31 + ## Example
43 32
44 - # Decodes an encoded transaction bytes
45 - iex> tx_bytes = <<229, 1, 192, 192, 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>>
46 - iex> ExPlasma.decode(tx_bytes)
47 - {:ok, %ExPlasma.Transaction{
48 - inputs: [],
49 - metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
51 - outputs: [],
52 - sigs: [],
53 - tx_data: "",
54 - tx_type: 1
55 - }
56 - }
33 + iex> ExPlasma.fee()
34 + 3
35 + """
36 + @spec fee() :: 3
37 + def fee(), do: @fee
57 38
58 - # Decodes a signed encoded transaction bytes
59 - iex> tx_bytes = <<239, 201, 136, 48, 120, 49, 50, 51, 52, 53, 54, 1, 192, 192, 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>>
60 - iex> ExPlasma.decode(tx_bytes)
61 - {:ok, %ExPlasma.Transaction{
62 - inputs: [],
63 - metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
65 - outputs: [],
66 - sigs: ["0x123456"],
67 - tx_data: "",
68 - tx_type: <<1>>
69 - }}
39 + @doc """
40 + Transaction types
70 41
71 - Decodes a transaction rlp data
72 - iex> rlp = [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, 0>>]
73 - iex> ExPlasma.decode(rlp)
74 - {:ok, %ExPlasma.Transaction{
75 - inputs: [],
76 - metadata: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
78 - outputs: [],
42 + ## Example
43 +
44 + iex> ExPlasma.transaction_types()
45 + [1, 3]
46 + """
47 + @spec transaction_types :: [1 | 3, ...]
48 + def transaction_types(), do: [payment_v1(), fee()]
49 +
50 + @doc """
51 + Encode the given Transaction into an RLP encodable list.
52 +
53 + If `signed: false` is given in the list of opts, will encode the transaction without its signatures.
54 +
55 + ## Example
56 +
57 + iex> txn =
58 + ...> %ExPlasma.Transaction{
59 + ...> inputs: [
60 + ...> %ExPlasma.Output{
61 + ...> output_data: nil,
62 + ...> output_id: %{blknum: 0, oindex: 0, position: 0, txindex: 0},
63 + ...> output_type: nil
64 + ...> }
65 + ...> ],
66 + ...> 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>>,
67 + ...> outputs: [
68 + ...> %ExPlasma.Output{
69 + ...> output_data: %{
70 + ...> amount: 1,
71 + ...> output_guard: <<29, 246, 47, 41, 27, 46, 150, 159, 176, 132, 157, 153,
72 + ...> 217, 206, 65, 226, 241, 55, 0, 110>>,
73 + ...> token: <<46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206,
74 + ...> 65, 226, 241, 55, 0, 110>>
75 + ...> },
76 + ...> output_id: nil,
77 + ...> output_type: 1
78 + ...> }
79 + ...> ],
80 + ...> sigs: [],
81 + ...> tx_data: 0,
82 + ...> tx_type: 1
83 + ...> }
84 + iex> ExPlasma.encode(txn, signed: false)
85 + {:ok, <<248, 116, 1, 225, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 237, 1, 235, 148, 29, 246, 47,
87 + 41, 27, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55, 0, 110,
88 + 148, 46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226,
89 + 241, 55, 0, 110, 1, 128, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>}
91 + """
92 + defdelegate encode(transaction, opts \\ []), to: Transaction
93 +
94 + @doc """
95 + Throwing version of encode/2
96 + """
97 + defdelegate encode!(transaction, opts \\ []), to: Transaction
98 +
99 + @doc """
100 + Attempt to decode the given RLP list into a Transaction.
101 +
102 + If `signed: false` is given in the list of opts, expects the underlying RLP to not contain signatures.
103 +
104 + Only validates that the RLP is structurally correct and that the tx type is supported.
105 + Does not perform any other kind of validation, use validate/1 for that.
106 +
107 + ## Example
108 +
109 + iex> rlp = <<248, 116, 1, 225, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
110 + ...> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 237, 1, 235, 148,
111 + ...> 29, 246, 47, 41, 27, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241,
112 + ...> 55, 0, 110, 148, 46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217,
113 + ...> 206, 65, 226, 241, 55, 0, 110, 1, 128, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 + ...> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
115 + iex> ExPlasma.decode(rlp, signed: false)
116 + {:ok,
117 + %ExPlasma.Transaction{
118 + inputs: [
119 + %ExPlasma.Output{
120 + output_data: nil,
121 + output_id: %{blknum: 0, oindex: 0, position: 0, txindex: 0},
122 + output_type: nil
123 + }
124 + ],
125 + 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>>,
126 + outputs: [
127 + %ExPlasma.Output{
128 + output_data: %{
129 + amount: 1,
130 + output_guard: <<29, 246, 47, 41, 27, 46, 150, 159, 176, 132, 157, 153,
131 + 217, 206, 65, 226, 241, 55, 0, 110>>,
132 + token: <<46, 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206,
133 + 65, 226, 241, 55, 0, 110>>
134 + },
135 + output_id: nil,
136 + output_type: 1
137 + }
138 + ],
139 + witnesses: [],
79 140 sigs: [],
80 141 tx_data: 0,
81 142 tx_type: 1
82 - }}
83 -
84 - # Decodes a utxo position
85 - iex> ExPlasma.decode(1000000000)
86 - {:ok,
87 - %ExPlasma.Utxo{
88 - amount: nil,
89 - blknum: 1,
90 - currency: nil,
91 - oindex: 0,
92 - output_type: 1,
93 - owner: nil,
94 - txindex: 0
95 - }}
96 -
97 - # Decodes an output utxo rlp data
98 - iex> rlp = [<<1>>, [<<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1>>, <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>, <<1>>]]
99 - iex> ExPlasma.decode(rlp)
100 - {:ok, %ExPlasma.Utxo{
101 - amount: 1,
102 - blknum: nil,
103 - currency: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
104 - oindex: nil,
105 - output_type: 1,
106 - owner: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1>>,
107 - txindex: nil
108 - }}
143 + }
144 + }
109 145 """
110 - @spec decode(Transaction.rlp() | Utxo.output_rlp() | Utxo.input_rlp()) ::
111 - {:ok, Transaction.t()} | {:ok, Utxo.t()} | Utxo.validation_tuples()
112 - def decode([_output_type, [_owner, _currency, _amount]] = output_rlp), do: Utxo.new(output_rlp)
113 -
114 - def decode([_tx_type, _inputs, _outputs, _tx_data, _metadata] = tx_rlp),
115 - do: Transaction.new(tx_rlp)
116 -
117 - def decode([_sigs, _tx_type, _inputs, _outputs, _tx_data, _metadata] = tx_rlp),
118 - do: Transaction.new(tx_rlp)
119 -
120 - def decode(utxo_pos) when is_integer(utxo_pos), do: Utxo.new(utxo_pos)
121 - def decode(tx_bytes) when is_binary(tx_bytes), do: Transaction.decode(tx_bytes)
146 + defdelegate decode(tx_bytes, opts \\ []), to: Transaction
122 147
123 148 @doc """
149 + Keccak hash the Transaction. This is used in the contracts and events to to reference transactions.
124 150
125 - ## Examples
126 151
127 - # Hash a transaction
128 - iex> {:ok, txn} = ExPlasma.Transaction.Payment.new(%{inputs: [], outputs: []})
129 - iex> ExPlasma.hash(txn)
130 - <<3, 225, 217, 46, 83, 133, 97, 248, 114, 1, 89, 94, 179, 68, 60,
131 - 39, 111, 80, 235, 153, 10, 175, 113, 195, 91, 188, 174, 39, 167,
132 - 20, 14, 81>>
152 + ## Example
133 153
134 - # Hash an encoded transaction bytes
135 - iex> tx_bytes = <<229, 1, 192, 192, 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>>
136 - iex> ExPlasma.hash(tx_bytes)
137 - <<3, 225, 217, 46, 83, 133, 97, 248, 114, 1, 89, 94, 179, 68, 60,
138 - 39, 111, 80, 235, 153, 10, 175, 113, 195, 91, 188, 174, 39, 167,
139 - 20, 14, 81>>
154 + iex> rlp = <<248, 74, 192, 1, 193, 128, 239, 174, 237, 1, 235, 148, 29, 246, 47, 41, 27,
155 + ...> 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55, 0, 110, 148, 46,
156 + ...> 38, 45, 41, 28, 46, 150, 159, 176, 132, 157, 153, 217, 206, 65, 226, 241, 55,
157 + ...> 0, 110, 1, 128, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
158 + ...> 0>>
159 + iex> ExPlasma.hash(rlp)
160 + {:ok, <<87, 132, 239, 36, 144, 239, 129, 88, 63, 88, 116, 147, 164, 200, 113, 191,
161 + 124, 14, 55, 131, 119, 96, 112, 13, 28, 178, 251, 49, 16, 127, 58, 96>>}
140 162 """
141 - @spec hash(Transaction.t() | binary()) :: <<_::256>>
142 - def hash(txn) when is_map(txn), do: Transaction.hash(txn)
143 - def hash(txn) when is_binary(txn), do: Transaction.hash(txn)
163 + defdelegate hash(transaction), to: Transaction
164 +
165 + @doc """
166 + Statelessly validate a transation.
167 +
168 + Returns :ok if valid or {:error, {atom, atom}} otherwise
169 + """
170 + defdelegate validate(transaction), to: Transaction
144 171 end
Loading more files…