Skip to content

Commit af47392

Browse files
hayesgmGeoff Hayes
authored and
Geoff Hayes
committed
Implement account interface and block interface
1 parent 7a17f24 commit af47392

File tree

6 files changed

+101
-5
lines changed

6 files changed

+101
-5
lines changed

lib/blockchain/account.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ defmodule Blockchain.Account do
471471
...> |> Blockchain.Account.get_machine_code(<<0x01::160>>)
472472
{:ok, <<1, 2, 3>>}
473473
"""
474-
@spec get_machine_code(EVM.state, EVM.address) :: {:ok, EVM.MachineState.t} | :not_found
474+
@spec get_machine_code(EVM.state, EVM.address) :: {:ok, binary()} | :not_found
475475
def get_machine_code(state, contract_address) do
476476
# TODO: Do we have a standard for default account values
477477
account = get_account(state, contract_address) || %__MODULE__{}

lib/blockchain/block.ex

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ defmodule Blockchain.Block do
112112

113113
@doc """
114114
Computes hash of a block, which is simply the hash of the serialized
115-
block after apply RLP.
115+
block after applying RLP encoding.
116116
117117
This is defined in Eq.(37) of the Yellow Paper.
118118
@@ -128,7 +128,7 @@ defmodule Blockchain.Block do
128128
"""
129129
@spec hash(t) :: EVM.hash
130130
def hash(block) do
131-
block.header |> Header.serialize() |> ExRLP.encode |> BitHelper.kec
131+
block.header |> Header.hash
132132
end
133133

134134
@doc """
@@ -191,6 +191,84 @@ defmodule Blockchain.Block do
191191
end
192192
end
193193

194+
@doc """
195+
Returns a given block from the database, if the hash
196+
exists in the database.
197+
198+
See `Blockchain.Block.put_block/2` for details.
199+
200+
## Examples
201+
202+
# Legit, current block
203+
iex> db = MerklePatriciaTree.Test.random_ets_db()
204+
iex> block = %Blockchain.Block{
205+
...> transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: "hi"}],
206+
...> header: %Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}
207+
...> }
208+
iex> Blockchain.Block.put_block(block, db)
209+
iex> Blockchain.Block.get_block_hash_by_steps(block |> Blockchain.Block.hash, 0, db)
210+
{:ok, <<78, 28, 127, 10, 192, 253, 127, 239, 254, 179, 39, 34, 245, 44,
211+
152, 98, 128, 71, 238, 155, 100, 161, 199, 71, 243, 223, 172, 191,
212+
74, 99, 128, 63>>}
213+
214+
# Bad, in the future
215+
iex> db = MerklePatriciaTree.Test.random_ets_db()
216+
iex> block = %Blockchain.Block{
217+
...> transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: "hi"}],
218+
...> header: %Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}
219+
...> }
220+
iex> Blockchain.Block.put_block(block, db)
221+
iex> Blockchain.Block.get_block_hash_by_steps(block |> Blockchain.Block.hash, -1, db)
222+
:not_found
223+
224+
# Bad, before the dawn of time
225+
iex> db = MerklePatriciaTree.Test.random_ets_db()
226+
iex> block = %Blockchain.Block{
227+
...> transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: "hi"}],
228+
...> header: %Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}
229+
...> }
230+
iex> Blockchain.Block.put_block(block, db)
231+
iex> Blockchain.Block.get_block_hash_by_steps(block |> Blockchain.Block.hash, 6, db)
232+
:not_found
233+
234+
iex> Blockchain.Block.get_block_hash_by_steps(<<1, 2, 3>>, 0, nil)
235+
{:ok, <<1, 2, 3>>}
236+
237+
# Legit, back zero and one
238+
iex> db = MerklePatriciaTree.Test.random_ets_db()
239+
iex> block_1 = %Blockchain.Block{
240+
...> transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: "hi"}],
241+
...> header: %Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}
242+
...> }
243+
iex> {:ok, block_1_hash} = Blockchain.Block.put_block(block_1, db)
244+
iex> block_2 = %Blockchain.Block{
245+
...> transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: "hi"}],
246+
...> header: %Block.Header{number: 6, parent_hash: block_1_hash, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}
247+
...> }
248+
iex> Blockchain.Block.put_block(block_2, db)
249+
iex> Blockchain.Block.get_block_hash_by_steps(block_2 |> Blockchain.Block.hash, 0, db)
250+
{:ok, <<203, 210, 109, 46, 207, 246, 94, 33, 247, 97, 60, 56, 65, 134,
251+
203, 120, 62, 64, 59, 64, 101, 190, 181, 7, 242, 215, 247, 212,
252+
107, 12, 92, 9>>}
253+
iex> Blockchain.Block.get_block_hash_by_steps(block_2 |> Blockchain.Block.hash, 1, db)
254+
{:ok, <<78, 28, 127, 10, 192, 253, 127, 239, 254, 179, 39, 34, 245, 44,
255+
152, 98, 128, 71, 238, 155, 100, 161, 199, 71, 243, 223, 172, 191,
256+
74, 99, 128, 63>>}
257+
"""
258+
@spec get_block_hash_by_steps(EVM.hash, non_neg_integer(), DB.db) :: {:ok, EVM.hash} | :not_found
259+
def get_block_hash_by_steps(curr_block_hash, steps, db) do
260+
do_get_block_hash_by_steps(curr_block_hash, steps, db)
261+
end
262+
263+
@spec get_block_hash_by_steps(EVM.hash, non_neg_integer(), DB.db) :: {:ok, EVM.hash} | :not_found
264+
defp do_get_block_hash_by_steps(block_hash, 0, _db), do: {:ok, block_hash}
265+
defp do_get_block_hash_by_steps(_block_hash, steps, _db) when steps < 0 or steps > 256, do: :not_found
266+
defp do_get_block_hash_by_steps(block_hash, steps, db) do
267+
with {:ok, block} <- get_block(block_hash, db) do
268+
do_get_block_hash_by_steps(block.header.parent_hash, steps - 1, db)
269+
end
270+
end
271+
194272
@doc """
195273
Returns the parent node for a given block,
196274
if it exists.

lib/blockchain/interface/account_interface.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ defimpl EVM.Interface.AccountInterface, for: Blockchain.Interface.AccountInterfa
3131
end
3232
end
3333

34+
# TODO: Add test case
35+
@spec get_account_code(EVM.Interface.AccountInterface.t, EVM.state, EVM.address) :: nil | binary()
36+
def get_account_code(_account_interface, state, address) do
37+
case Blockchain.Account.get_machine_code(state, address) do
38+
{:ok, machine_code} -> machine_code
39+
:not_found -> nil
40+
end
41+
end
42+
3443
# TODO: Add test case
3544
@spec increment_account_nonce(EVM.Interface.AccountInterface.t, EVM.state, EVM.address) :: { EVM.state, integer() }
3645
def increment_account_nonce(_account_interface, state, address) do

lib/blockchain/interface/block_interface.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,13 @@ defimpl EVM.Interface.BlockInterface, for: Blockchain.Interface.BlockInterface d
4949
end
5050
end
5151

52+
# TODO: Add test case
53+
@spec get_block_by_number(EVM.Interface.BlockInterface.t, non_neg_integer()) :: Block.Header.t | nil
54+
def get_block_by_number(block_interface, steps) do
55+
case Blockchain.Block.get_block_hash_by_steps(block_interface.block_header |> Block.Header.hash, steps, block_interface.db) do
56+
{:ok, block_header} -> block_header
57+
:not_found -> nil
58+
end
59+
end
60+
5261
end

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ defmodule Blockchain.Mixfile do
4747
{:merkle_patricia_tree, "~> 0.2.5"},
4848
{:dialyxir, "~> 0.5", only: [:dev], runtime: false},
4949
{:ex_rlp, "~> 0.2.1"},
50-
{:evm, "~> 0.1.8"},
50+
{:evm, "~> 0.1.10"},
5151
{:poison, "~> 3.1.0"},
5252
]
5353
end

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"},
44
"earmark": {:hex, :earmark, "1.2.3", "206eb2e2ac1a794aa5256f3982de7a76bf4579ff91cb28d0e17ea2c9491e46a4", [:mix], [], "hexpm"},
55
"eleveldb": {:hex, :eleveldb, "2.2.20", "1fff63a5055bbf4bf821f797ef76065882b193f5e8095f95fcd9287187773b58", [:rebar3], [], "hexpm"},
6-
"evm": {:hex, :evm, "0.1.8", "2dd65a5cb388c93153820d51efef21f268d75032f26f66af4720d7a3c9200328", [:mix], [{:keccakf1600, "~> 2.0.0", [hex: :keccakf1600_orig, repo: "hexpm", optional: false]}, {:merkle_patricia_tree, "~> 0.2.5", [hex: :merkle_patricia_tree, repo: "hexpm", optional: false]}], "hexpm"},
6+
"evm": {:hex, :evm, "0.1.10", "3bb9355a563005af9233a5af3d5d6b411070ecb3b52c744f0242697179bb9f9d", [:mix], [{:keccakf1600, "~> 2.0.0", [hex: :keccakf1600_orig, repo: "hexpm", optional: false]}, {:merkle_patricia_tree, "~> 0.2.5", [hex: :merkle_patricia_tree, repo: "hexpm", optional: false]}], "hexpm"},
77
"ex_doc": {:hex, :ex_doc, "0.16.2", "3b3e210ebcd85a7c76b4e73f85c5640c011d2a0b2f06dcdf5acdb2ae904e5084", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
88
"ex_rlp": {:hex, :ex_rlp, "0.2.1", "bd320900d6316cdfe01d365d4bda22eb2f39b359798daeeffd3bd1ca7ba958ec", [:mix], [], "hexpm"},
99
"exleveldb": {:hex, :exleveldb, "0.11.1", "37c0414208a50d2419d8246305e6c4a33ed339c25c0bdfa27774795e1e089f7b", [:mix], [{:eleveldb, "~> 2.2.19", [hex: :eleveldb, repo: "hexpm", optional: false]}], "hexpm"},

0 commit comments

Comments
 (0)