Skip to content

Commit f553cd5

Browse files
authored
Merge pull request #107 from aeternity/GH-91
GH-91 Add list of transactions concerning account to chainstate (block_hash, tx_hash)
2 parents c328b5c + 4b66b5c commit f553cd5

File tree

2 files changed

+55
-19
lines changed

2 files changed

+55
-19
lines changed

apps/aecore/lib/aecore/chain/worker.ex

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ defmodule Aecore.Chain.Worker do
2323
genesis_block_map = %{genesis_block_hash => Block.genesis_block()}
2424
genesis_chain_state = ChainState.calculate_block_state(Block.genesis_block().txs)
2525
latest_block_chain_state = %{genesis_block_hash => genesis_chain_state}
26-
27-
initial_state = {genesis_block_map, latest_block_chain_state}
26+
txs_index = calculate_block_acc_txs_info(Block.genesis_block())
27+
initial_state = {genesis_block_map, latest_block_chain_state, txs_index}
2828

2929
{:ok, initial_state}
3030
end
@@ -70,13 +70,18 @@ defmodule Aecore.Chain.Worker do
7070
GenServer.call(__MODULE__, {:chain_state, latest_block_hash})
7171
end
7272

73+
@spec txs_index() :: map()
74+
def txs_index() do
75+
GenServer.call(__MODULE__, :txs_index)
76+
end
77+
7378
def handle_call(:get_latest_block_chain_state, _from, state) do
74-
{_, latest_block_chain_state} = state
79+
{_, latest_block_chain_state, _} = state
7580
{:reply, latest_block_chain_state, state}
7681
end
7782

7883
def handle_call({:get_block, block_hash}, _from, state) do
79-
{block_map, _} = state
84+
{block_map, _, _} = state
8085
block = block_map[block_hash]
8186

8287
if(block != nil) do
@@ -87,7 +92,7 @@ defmodule Aecore.Chain.Worker do
8792
end
8893

8994
def handle_call({:get_block_by_hex_hash, hash}, _from, state) do
90-
{chain, _} = state
95+
{chain, _, _} = state
9196
case(Enum.find(chain, fn{block_hash, _block} ->
9297
block_hash |> Base.encode16() == hash end)) do
9398
{_, block} ->
@@ -98,17 +103,19 @@ defmodule Aecore.Chain.Worker do
98103
end
99104

100105
def handle_call({:add_block, %Block{} = block}, _from, state) do
101-
{chain, chain_state} = state
102-
prev_block_chain_state = chain_state[block.header.prev_hash]
106+
{block_map, latest_block_chain_state, txs_index} = state
107+
prev_block_chain_state = latest_block_chain_state[block.header.prev_hash]
103108
new_block_state = ChainState.calculate_block_state(block.txs)
104-
new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state)
109+
new_chain_state =
110+
ChainState.calculate_chain_state(new_block_state, prev_block_chain_state)
105111

112+
new_block_txs_index = calculate_block_acc_txs_info(block)
113+
new_txs_index = update_txs_index(txs_index, new_block_txs_index)
106114
try do
107-
BlockValidation.validate_block!(block, chain[block.header.prev_hash], new_chain_state)
115+
BlockValidation.validate_block!(block, block_map[block.header.prev_hash], new_chain_state)
108116

109117
Enum.each(block.txs, fn(tx) -> Pool.remove_transaction(tx) end)
110118

111-
{block_map, latest_block_chain_state} = state
112119
block_hash = BlockValidation.block_header_hash(block.header)
113120
updated_block_map = Map.put(block_map, block_hash, block)
114121
has_prev_block = Map.has_key?(latest_block_chain_state, block.header.prev_hash)
@@ -121,10 +128,8 @@ defmodule Aecore.Chain.Worker do
121128
{latest_block_chain_state, %{}}
122129
end
123130

124-
new_block_state = ChainState.calculate_block_state(block.txs)
125-
new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_chain_state)
126-
127-
updated_latest_block_chainstate = Map.put(deleted_latest_chain_state, block_hash, new_chain_state)
131+
updated_latest_block_chainstate =
132+
Map.put(deleted_latest_chain_state, block_hash, new_chain_state)
128133

129134
total_tokens = ChainState.calculate_total_tokens(new_chain_state)
130135

@@ -137,7 +142,7 @@ defmodule Aecore.Chain.Worker do
137142
## Block was validated, now we can send it to other peers
138143
Peers.broadcast_to_all({:new_block, block})
139144

140-
{:reply, :ok, {updated_block_map, updated_latest_block_chainstate}}
145+
{:reply, :ok, {updated_block_map, updated_latest_block_chainstate, new_txs_index}}
141146
catch
142147
{:error, message} ->
143148
Logger.error(fn ->
@@ -148,10 +153,15 @@ defmodule Aecore.Chain.Worker do
148153
end
149154

150155
def handle_call({:chain_state, latest_block_hash}, _from, state) do
151-
{_, chain_state} = state
156+
{_, chain_state, _} = state
152157
{:reply, chain_state[latest_block_hash], state}
153158
end
154159

160+
def handle_call(:txs_index, _from, state) do
161+
{_, _, txs_index} = state
162+
{:reply, txs_index, state}
163+
end
164+
155165
def chain_state() do
156166
latest_block = latest_block()
157167
latest_block_hash = BlockValidation.block_header_hash(latest_block.header)
@@ -164,6 +174,34 @@ defmodule Aecore.Chain.Worker do
164174
get_blocks(latest_block_hash, latest_block_obj.header.height)
165175
end
166176

177+
def calculate_block_acc_txs_info(block) do
178+
block_hash = BlockValidation.block_header_hash(block.header)
179+
accounts = for tx <- block.txs do
180+
[tx.data.from_acc, tx.data.to_acc]
181+
end
182+
accounts = accounts |> List.flatten() |> Enum.uniq() |> List.delete(nil)
183+
for account <- accounts, into: %{} do
184+
acc_txs = Enum.filter(block.txs, fn(tx) ->
185+
tx.data.from_acc == account || tx.data.to_acc == account
186+
end)
187+
tx_hashes = Enum.map(acc_txs, fn(tx) ->
188+
tx_bin = :erlang.term_to_binary(tx)
189+
:crypto.hash(:sha256, tx_bin)
190+
end)
191+
tx_tuples = Enum.map(tx_hashes, fn(hash) ->
192+
{block_hash, hash}
193+
end)
194+
{account, tx_tuples}
195+
end
196+
end
197+
198+
def update_txs_index(current_txs_index, new_block_txs_index) do
199+
Map.merge(current_txs_index, new_block_txs_index,
200+
fn(_, current_list, new_block_list) ->
201+
current_list ++ new_block_list
202+
end)
203+
end
204+
167205
defp get_blocks(blocks_acc, next_block_hash, size) do
168206
cond do
169207
size > 0 ->

apps/aehttpclient/test/aehttpclient_test.exs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ defmodule AehttpclientTest do
22

33
use ExUnit.Case
44

5-
alias Aecore.Structures.Block
65
alias Aecore.Chain.Worker, as: Chain
76
alias Aecore.Txs.Pool.Worker, as: Pool
87
alias Aecore.Keys.Worker, as: Keys
@@ -11,9 +10,8 @@ defmodule AehttpclientTest do
1110
test "Client functions" do
1211
account = Keys.pubkey() |> elem(1) |> Base.encode16()
1312
add_txs_to_pool()
14-
_genesis_block = Block.genesis_block()
1513
assert {:ok, _} = Client.get_info("localhost:4000")
16-
assert {:ok, _genesis_block} = Client.get_block({"localhost:4000",
14+
assert {:ok, _} = Client.get_block({"localhost:4000",
1715
"C061E48A6F7FB2634E0C012B168D41F4773A38BD9E5EA28E5BE7D04186127BA0"})
1816
assert {:ok, _} = Client.get_peers("localhost:4000")
1917
assert Enum.count(Client.get_account_txs({"localhost:4000", account})

0 commit comments

Comments
 (0)