From ad06f2d7505d209f73cae4dd0e81917920e5a094 Mon Sep 17 00:00:00 2001 From: d-velev Date: Wed, 1 Nov 2017 17:57:33 +0200 Subject: [PATCH 1/4] [GH-#91] Helper functions added to chain module, refactoring not yet done --- apps/aecore/lib/aecore/chain/worker.ex | 63 ++++++++++++++++++++------ apps/aecore/lib/aecore/miner/worker.ex | 1 + 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index bef222ec..b3bf001d 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -19,7 +19,7 @@ defmodule Aecore.Chain.Worker do genesis_chain_state = ChainState.calculate_block_state(Block.genesis_block().txs) latest_block_chain_state = %{genesis_block_hash => genesis_chain_state} - initial_state = {genesis_block_map, latest_block_chain_state} + initial_state = {genesis_block_map, latest_block_chain_state, txs_index} GenServer.start_link(__MODULE__, initial_state, name: __MODULE__) end @@ -69,7 +69,7 @@ defmodule Aecore.Chain.Worker do end def handle_call(:get_latest_block_chain_state, _from, state) do - {_, latest_block_chain_state} = state + {_, latest_block_chain_state, _} = state {:reply, latest_block_chain_state, state} end @@ -86,7 +86,7 @@ defmodule Aecore.Chain.Worker do end def handle_call({:get_block, block_hash}, _from, state) do - {block_map, _} = state + {block_map, _, _} = state block = block_map[block_hash] if(block != nil) do @@ -107,16 +107,20 @@ defmodule Aecore.Chain.Worker do end def handle_call({:add_block, %Block{} = block}, _from, state) do - {chain, chain_state} = state - prev_block_chain_state = chain_state[block.header.prev_hash] + #{chain, chain_state, txs_index} = state + {block_map, latest_block_chain_state, txs_index} = state + prev_block_chain_state = latest_block_chain_state[block.header.prev_hash] new_block_state = ChainState.calculate_block_state(block.txs) - new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) + new_chain_state = + ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) + acc_txs_map = block_txs_for_accs(block) + new_txs_index = add_txs_to_chain_state(latest_block_chain_state, acc_txs_map) + merge_txs_lists(latest_block_chain_state, new_txs_index) - BlockValidation.validate_block!(block, chain[block.header.prev_hash], new_chain_state) + BlockValidation.validate_block!(block, block_map[block.header.prev_hash], new_chain_state) Enum.each(block.txs, fn(tx) -> Pool.remove_transaction(tx) end) - {block_map, latest_block_chain_state} = state block_hash = BlockValidation.block_header_hash(block.header) updated_block_map = Map.put(block_map, block_hash, block) has_prev_block = Map.has_key?(latest_block_chain_state, block.header.prev_hash) @@ -129,10 +133,8 @@ defmodule Aecore.Chain.Worker do {latest_block_chain_state, %{}} end - new_block_state = ChainState.calculate_block_state(block.txs) - new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_chain_state) - - updated_latest_block_chainstate = Map.put(deleted_latest_chain_state, block_hash, new_chain_state) + updated_latest_block_chainstate = + Map.put(deleted_latest_chain_state, block_hash, new_chain_state) total_tokens = ChainState.calculate_total_tokens(new_chain_state) @@ -146,11 +148,11 @@ defmodule Aecore.Chain.Worker do end ) - {:reply, :ok, {updated_block_map, updated_latest_block_chainstate}} + {:reply, :ok, {updated_block_map, updated_latest_block_chainstate, new_txs_index}} end def handle_call({:chain_state, latest_block_hash}, _from, state) do - {_, chain_state} = state + {_, chain_state, _} = state {:reply, chain_state[latest_block_hash], state} end @@ -166,6 +168,39 @@ defmodule Aecore.Chain.Worker do get_blocks(latest_block_hash, latest_block_obj.header.height) end + def block_txs_for_accs(block) do + block_hash = BlockValidation.block_header_hash(block.header) + accounts = for tx <- block.txs do + [tx.data.from_acc, tx.data.to_acc] + end + accounts = accounts |> List.flatten() |> Enum.uniq() |> List.delete(nil) + for account <- accounts, into: %{} do + acc_txs = Enum.filter(block.txs, fn(tx) -> + tx.data.from_acc == account || tx.data.to_acc == account + end) + tx_hashes = Enum.map(acc_txs, fn(tx) -> + tx_bin = :erlang.term_to_binary(tx) + :crypto.hash(:sha256, tx_bin) + end) + tx_tuples = Enum.map(tx_hashes, fn(hash) -> + {block_hash, hash} + end) + {account, tx_tuples} + end + end + + def add_txs_to_chain_state(chain_state, acc_txs_map) do + Map.merge(chain_state, acc_txs_map, fn(_, v1, v2) -> + %{balance: v1.balance, nonce: v1.nonce, txs: v2} + end) + end + + def merge_txs_lists(old_chain_state, txs_index) do + Map.merge(old_chain_state, txs_index, fn(_, v1, v2) -> + %{balance: v1.balance, nonce: v1.nonce, txs: v1.txs ++ v2.txs} + end) + end + defp get_blocks(blocks_acc, next_block_hash, size) do cond do size > 0 -> diff --git a/apps/aecore/lib/aecore/miner/worker.ex b/apps/aecore/lib/aecore/miner/worker.ex index a959834a..0a2806b3 100644 --- a/apps/aecore/lib/aecore/miner/worker.ex +++ b/apps/aecore/lib/aecore/miner/worker.ex @@ -130,6 +130,7 @@ defmodule Aecore.Miner.Worker do new_block_state = ChainState.calculate_block_state(valid_txs) new_chain_state = ChainState.calculate_chain_state(new_block_state, chain_state) + chain_state_hash = ChainState.calculate_chain_state_hash(new_chain_state) latest_block_hash = BlockValidation.block_header_hash(latest_block.header) From 3bbe48e8b46b4c1c09439e3e017f8c5ed42640ae Mon Sep 17 00:00:00 2001 From: d-velev Date: Thu, 2 Nov 2017 11:11:57 +0200 Subject: [PATCH 2/4] [GH-#91] State of the Chain GenServer now also contains a map with account as key and a list of {block_hash, tx_hash} for each tx as value --- apps/aecore/lib/aecore/chain/worker.ex | 33 +++++++++++--------- apps/aehttpclient/test/aehttpclient_test.exs | 4 +-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index b3bf001d..1b9ea698 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -18,6 +18,7 @@ defmodule Aecore.Chain.Worker do genesis_block_map = %{genesis_block_hash => Block.genesis_block()} genesis_chain_state = ChainState.calculate_block_state(Block.genesis_block().txs) latest_block_chain_state = %{genesis_block_hash => genesis_chain_state} + txs_index = %{} initial_state = {genesis_block_map, latest_block_chain_state, txs_index} GenServer.start_link(__MODULE__, initial_state, name: __MODULE__) @@ -68,6 +69,11 @@ defmodule Aecore.Chain.Worker do GenServer.call(__MODULE__, {:chain_state, latest_block_hash}) end + @spec txs_index() :: map() + def txs_index() do + GenServer.call(__MODULE__, :txs_index) + end + def handle_call(:get_latest_block_chain_state, _from, state) do {_, latest_block_chain_state, _} = state {:reply, latest_block_chain_state, state} @@ -107,15 +113,14 @@ defmodule Aecore.Chain.Worker do end def handle_call({:add_block, %Block{} = block}, _from, state) do - #{chain, chain_state, txs_index} = state {block_map, latest_block_chain_state, txs_index} = state prev_block_chain_state = latest_block_chain_state[block.header.prev_hash] new_block_state = ChainState.calculate_block_state(block.txs) new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) - acc_txs_map = block_txs_for_accs(block) - new_txs_index = add_txs_to_chain_state(latest_block_chain_state, acc_txs_map) - merge_txs_lists(latest_block_chain_state, new_txs_index) + + new_block_txs_index = acc_txs_info(block) + new_txs_index = update_txs_index(txs_index, new_block_txs_index) BlockValidation.validate_block!(block, block_map[block.header.prev_hash], new_chain_state) @@ -156,6 +161,11 @@ defmodule Aecore.Chain.Worker do {:reply, chain_state[latest_block_hash], state} end + def handle_call(:txs_index, _from, state) do + {_, _, txs_index} = state + {:reply, txs_index, state} + end + def chain_state() do latest_block = latest_block() latest_block_hash = BlockValidation.block_header_hash(latest_block.header) @@ -168,7 +178,7 @@ defmodule Aecore.Chain.Worker do get_blocks(latest_block_hash, latest_block_obj.header.height) end - def block_txs_for_accs(block) do + def acc_txs_info(block) do block_hash = BlockValidation.block_header_hash(block.header) accounts = for tx <- block.txs do [tx.data.from_acc, tx.data.to_acc] @@ -189,15 +199,10 @@ defmodule Aecore.Chain.Worker do end end - def add_txs_to_chain_state(chain_state, acc_txs_map) do - Map.merge(chain_state, acc_txs_map, fn(_, v1, v2) -> - %{balance: v1.balance, nonce: v1.nonce, txs: v2} - end) - end - - def merge_txs_lists(old_chain_state, txs_index) do - Map.merge(old_chain_state, txs_index, fn(_, v1, v2) -> - %{balance: v1.balance, nonce: v1.nonce, txs: v1.txs ++ v2.txs} + def update_txs_index(current_txs_index, new_block_txs_index) do + Map.merge(current_txs_index, new_block_txs_index, + fn(_, current_list, new_block_list) -> + current_list ++ new_block_list end) end diff --git a/apps/aehttpclient/test/aehttpclient_test.exs b/apps/aehttpclient/test/aehttpclient_test.exs index cdfab254..3f1038b1 100644 --- a/apps/aehttpclient/test/aehttpclient_test.exs +++ b/apps/aehttpclient/test/aehttpclient_test.exs @@ -2,7 +2,6 @@ defmodule AehttpclientTest do use ExUnit.Case - alias Aecore.Structures.Block alias Aecore.Chain.Worker, as: Chain alias Aecore.Txs.Pool.Worker, as: Pool alias Aecore.Keys.Worker, as: Keys @@ -11,9 +10,8 @@ defmodule AehttpclientTest do test "Client functions" do account = Keys.pubkey() |> elem(1) |> Base.encode16() add_txs_to_pool() - genesis_block = Block.genesis_block() assert {:ok, _} = Client.get_info("localhost:4000") - assert {:ok, genesis_block} = Client.get_block({"localhost:4000", + assert {:ok, _} = Client.get_block({"localhost:4000", "C061E48A6F7FB2634E0C012B168D41F4773A38BD9E5EA28E5BE7D04186127BA0"}) assert {:ok, _} = Client.get_peers("localhost:4000") assert Enum.count(Client.get_account_txs({"localhost:4000", account}) From 55579c6e3152a3757a551f8202dd6c110af39d31 Mon Sep 17 00:00:00 2001 From: d-velev Date: Thu, 2 Nov 2017 12:34:29 +0200 Subject: [PATCH 3/4] [GH-#91] Initial txs_index is calculated with the genesis block (still an empty map) --- apps/aecore/lib/aecore/chain/worker.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index 9e2cf30a..8c311067 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -23,7 +23,7 @@ defmodule Aecore.Chain.Worker do genesis_block_map = %{genesis_block_hash => Block.genesis_block()} genesis_chain_state = ChainState.calculate_block_state(Block.genesis_block().txs) latest_block_chain_state = %{genesis_block_hash => genesis_chain_state} - txs_index = %{} + txs_index = acc_txs_info(Block.genesis_block()) initial_state = {genesis_block_map, latest_block_chain_state, txs_index} {:ok, initial_state} From 4b66b5c7e136fa0426a7047fa087fa76b7618265 Mon Sep 17 00:00:00 2001 From: d-velev Date: Thu, 2 Nov 2017 12:39:59 +0200 Subject: [PATCH 4/4] [GH-#91] Function in Chain renamed --- apps/aecore/lib/aecore/chain/worker.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index 8c311067..3536755a 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -23,7 +23,7 @@ defmodule Aecore.Chain.Worker do genesis_block_map = %{genesis_block_hash => Block.genesis_block()} genesis_chain_state = ChainState.calculate_block_state(Block.genesis_block().txs) latest_block_chain_state = %{genesis_block_hash => genesis_chain_state} - txs_index = acc_txs_info(Block.genesis_block()) + txs_index = calculate_block_acc_txs_info(Block.genesis_block()) initial_state = {genesis_block_map, latest_block_chain_state, txs_index} {:ok, initial_state} @@ -109,7 +109,7 @@ defmodule Aecore.Chain.Worker do new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) - new_block_txs_index = acc_txs_info(block) + new_block_txs_index = calculate_block_acc_txs_info(block) new_txs_index = update_txs_index(txs_index, new_block_txs_index) try do BlockValidation.validate_block!(block, block_map[block.header.prev_hash], new_chain_state) @@ -174,7 +174,7 @@ defmodule Aecore.Chain.Worker do get_blocks(latest_block_hash, latest_block_obj.header.height) end - def acc_txs_info(block) do + def calculate_block_acc_txs_info(block) do block_hash = BlockValidation.block_header_hash(block.header) accounts = for tx <- block.txs do [tx.data.from_acc, tx.data.to_acc]