From 6b124b7a7d7cd32b9ddb3121dce4670b34055a84 Mon Sep 17 00:00:00 2001 From: d-velev Date: Thu, 23 Nov 2017 16:30:14 +0200 Subject: [PATCH 01/12] [GH-#125] Added lock_time_block to TxData --- apps/aecore/lib/aecore/chain/chain_state.ex | 14 +++++++++----- apps/aecore/lib/aecore/keys/worker.ex | 6 +++--- apps/aecore/lib/aecore/structures/tx_data.ex | 13 +++++++++---- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/apps/aecore/lib/aecore/chain/chain_state.ex b/apps/aecore/lib/aecore/chain/chain_state.ex index 35a9364e..b8193951 100644 --- a/apps/aecore/lib/aecore/chain/chain_state.ex +++ b/apps/aecore/lib/aecore/chain/chain_state.ex @@ -80,12 +80,12 @@ defmodule Aecore.Chain.ChainState do Enum.all?() end - @spec update_block_state(map(), binary(), integer(), integer()) :: map() - defp update_block_state(block_state, account, value, nonce) do + @spec update_block_state(map(), binary(), integer(), integer(), integer()) :: map() + defp update_block_state(block_state, account, value, nonce, lock_time_block) do block_state_filled_empty = cond do !Map.has_key?(block_state, account) -> - Map.put(block_state, account, %{balance: 0, nonce: 0}) + Map.put(block_state, account, %{balance: 0, nonce: 0, locked: []}) true -> block_state @@ -100,7 +100,9 @@ defmodule Aecore.Chain.ChainState do end new_account_state = %{balance: block_state_filled_empty[account].balance + value, - nonce: new_nonce} + nonce: new_nonce, + locked: block_state_filled_empty.locked ++ + [%{amount: value, block: lock_time_block}]} Map.put(block_state_filled_empty, account, new_account_state) end @@ -124,7 +126,9 @@ defmodule Aecore.Chain.ChainState do v1.nonce end - %{balance: v1.balance + v2.balance, nonce: new_nonce} + %{balance: v1.balance + v2.balance, + nonce: new_nonce, + locked: v1.locked ++ v2.locked} end) end end diff --git a/apps/aecore/lib/aecore/keys/worker.ex b/apps/aecore/lib/aecore/keys/worker.ex index e7daac88..505eb822 100644 --- a/apps/aecore/lib/aecore/keys/worker.ex +++ b/apps/aecore/lib/aecore/keys/worker.ex @@ -39,10 +39,10 @@ defmodule Aecore.Keys.Worker do - value: The amount of a transaction """ - @spec sign_tx(binary(), integer(), integer(), integer()) :: {:ok, %SignedTx{}} - def sign_tx(to_acc, value, nonce, fee) do + @spec sign_tx(binary(), integer(), integer(), integer(), integer()) :: {:ok, %SignedTx{}} + def sign_tx(to_acc, value, nonce, fee, lock_time_block) do {:ok, from_acc} = pubkey() - {:ok, tx_data} = TxData.create(from_acc, to_acc, value, nonce, fee) + {:ok, tx_data} = TxData.create(from_acc, to_acc, value, nonce, fee, lock_time_block) {:ok, signature} = sign(tx_data) signed_tx = %SignedTx{data: tx_data, signature: signature} {:ok, signed_tx} diff --git a/apps/aecore/lib/aecore/structures/tx_data.ex b/apps/aecore/lib/aecore/structures/tx_data.ex index c7425c6f..d0df7988 100644 --- a/apps/aecore/lib/aecore/structures/tx_data.ex +++ b/apps/aecore/lib/aecore/structures/tx_data.ex @@ -15,11 +15,16 @@ defmodule Aecore.Structures.TxData do - to_acc: To account is the public address of the account receiving the transaction - value: The amount of a transaction """ - defstruct [:nonce, :from_acc, :to_acc, :value, :fee] + defstruct [:nonce, :from_acc, :to_acc, :value, :fee, :lock_time_block] use ExConstructor - @spec create(binary(), binary(), integer(), integer(), integer()) :: {:ok, %TxData{}} - def create(from_acc, to_acc, value, nonce, fee) do - {:ok, %TxData{from_acc: from_acc, to_acc: to_acc, value: value, nonce: nonce, fee: fee}} + @spec create(binary(), binary(), integer(), integer(), integer(), integer()) :: {:ok, %TxData{}} + def create(from_acc, to_acc, value, nonce, fee, lock_time_block) do + {:ok, %TxData{from_acc: from_acc, + to_acc: to_acc, + value: value, + nonce: nonce, + fee: fee, + lock_time_block: lock_time_block}} end end From bed3e5e6c0062faa4046e938bdae80bff6ce3d92 Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Thu, 23 Nov 2017 17:51:59 +0200 Subject: [PATCH 02/12] [GH-#125] Changed chain state calculation --- apps/aecore/lib/aecore/chain/chain_state.ex | 22 ++++++++++++++++++--- apps/aecore/lib/aecore/chain/worker.ex | 11 +++++++++-- apps/aecore/lib/aecore/miner/worker.ex | 16 +++++++++++---- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/apps/aecore/lib/aecore/chain/chain_state.ex b/apps/aecore/lib/aecore/chain/chain_state.ex index b8193951..8fb1000b 100644 --- a/apps/aecore/lib/aecore/chain/chain_state.ex +++ b/apps/aecore/lib/aecore/chain/chain_state.ex @@ -20,13 +20,14 @@ defmodule Aecore.Chain.ChainState do transaction.data.from_acc != nil -> update_block_state(block_state, transaction.data.from_acc, -(transaction.data.value + transaction.data.fee), - transaction.data.nonce) + transaction.data.nonce, transaction.data.lock_time_block) true -> block_state end - update_block_state(updated_block_state, transaction.data.to_acc, transaction.data.value, 0) + update_block_state(updated_block_state, transaction.data.to_acc, + transaction.data.value, 0, transaction.data.lock_time_block) end reduce_map_list(block_state) @@ -80,6 +81,21 @@ defmodule Aecore.Chain.ChainState do Enum.all?() end + @spec substract_locked_amounts_from_chain_state(map(), integer()) :: map() + def substract_locked_amounts_from_chain_state(chain_state, new_block_height) do + Enum.reduce(chain_state, %{}, fn({account, %{balance: balance, nonce: nonce, locked: locked}}, acc) -> + locked_amount = Enum.reduce(locked, 0, fn(%{amount: amount, block: lock_time_block}, amount_to_substract) -> + if(lock_time_block > new_block_height) do + amount_to_substract + amount + else + amount_to_substract + end + end) + + Map.put(acc, account, %{balance: balance - locked_amount, nonce: nonce, locked: locked}) + end) + end + @spec update_block_state(map(), binary(), integer(), integer(), integer()) :: map() defp update_block_state(block_state, account, value, nonce, lock_time_block) do block_state_filled_empty = @@ -101,7 +117,7 @@ defmodule Aecore.Chain.ChainState do new_account_state = %{balance: block_state_filled_empty[account].balance + value, nonce: new_nonce, - locked: block_state_filled_empty.locked ++ + locked: block_state_filled_empty[account].locked ++ [%{amount: value, block: lock_time_block}]} Map.put(block_state_filled_empty, account, new_account_state) end diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index bb4cf001..3223e8cf 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -75,11 +75,16 @@ defmodule Aecore.Chain.Worker do prev_block_chain_state = chain_state() 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_locked_amounts = + ChainState.substract_locked_amounts_from_chain_state(new_chain_state, latest_block.header.height + 1) + IO.puts("CHAIN:") + IO.inspect(new_chain_state) + IO.inspect(new_chain_state_locked_amounts) latest_header_hash = BlockValidation.block_header_hash(latest_block.header) blocks_for_difficulty_calculation = get_blocks(latest_header_hash, Difficulty.get_number_of_blocks()) - BlockValidation.validate_block!(block, latest_block, new_chain_state, blocks_for_difficulty_calculation) + BlockValidation.validate_block!(block, latest_block, new_chain_state_locked_amounts, blocks_for_difficulty_calculation) add_validated_block(block) end @@ -148,6 +153,8 @@ defmodule Aecore.Chain.Worker do 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_locked_amounts = + ChainState.substract_locked_amounts_from_chain_state(new_chain_state, block.header.height) new_block_txs_index = calculate_block_acc_txs_info(block) new_txs_index = update_txs_index(txs_index, new_block_txs_index) @@ -167,7 +174,7 @@ defmodule Aecore.Chain.Worker do end updated_latest_block_chainstate = - Map.put(deleted_latest_chain_state, block_hash, new_chain_state) + Map.put(deleted_latest_chain_state, block_hash, new_chain_state_locked_amounts) total_tokens = ChainState.calculate_total_tokens(new_chain_state) diff --git a/apps/aecore/lib/aecore/miner/worker.ex b/apps/aecore/lib/aecore/miner/worker.ex index eaa75d96..8bddb595 100644 --- a/apps/aecore/lib/aecore/miner/worker.ex +++ b/apps/aecore/lib/aecore/miner/worker.ex @@ -16,6 +16,7 @@ defmodule Aecore.Miner.Worker do require Logger @coinbase_transaction_value 100 + @coinbase_lock_time_block 10 @nonce_per_cycle 1 def start_link(_args) do @@ -106,13 +107,14 @@ defmodule Aecore.Miner.Worker do {:next_state, :idle, data} end - def get_coinbase_transaction(to_acc, total_fees) do + def get_coinbase_transaction(to_acc, total_fees, lock_time_block) do tx_data = %TxData{ from_acc: nil, to_acc: to_acc, value: @coinbase_transaction_value + total_fees, nonce: 0, - fee: 0 + fee: 0, + lock_time_block: lock_time_block } %SignedTx{data: tx_data, signature: nil} @@ -155,6 +157,8 @@ defmodule Aecore.Miner.Worker do end try do + IO.inspect("MINER:") + IO.inspect(chain_state) BlockValidation.validate_block!( latest_block, previous_block, @@ -172,12 +176,16 @@ defmodule Aecore.Miner.Worker do {_, pubkey} = Keys.pubkey() total_fees = calculate_total_fees(valid_txs) - valid_txs = [get_coinbase_transaction(pubkey, total_fees) | valid_txs] + valid_txs = [get_coinbase_transaction(pubkey, total_fees, + latest_block.header.height + 1 + + @coinbase_lock_time_block) | valid_txs] root_hash = BlockValidation.calculate_root_hash(valid_txs) 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) + new_chain_state_locked_amounts = + ChainState.substract_locked_amounts_from_chain_state(new_chain_state, latest_block.header.height + 1) + chain_state_hash = ChainState.calculate_chain_state_hash(new_chain_state_locked_amounts) latest_block_hash = BlockValidation.block_header_hash(latest_block.header) From c8e41c44c174c51959fb5b382bc07168aafedb65 Mon Sep 17 00:00:00 2001 From: d-velev Date: Fri, 24 Nov 2017 12:12:42 +0200 Subject: [PATCH 03/12] [GH-#125] Unlocking locked amounts in Chain State --- apps/aecore/lib/aecore/chain/chain_state.ex | 36 ++++++++++++++------- apps/aecore/lib/aecore/chain/worker.ex | 5 +-- apps/aecore/lib/aecore/miner/worker.ex | 2 -- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/apps/aecore/lib/aecore/chain/chain_state.ex b/apps/aecore/lib/aecore/chain/chain_state.ex index 8fb1000b..deb5b66e 100644 --- a/apps/aecore/lib/aecore/chain/chain_state.ex +++ b/apps/aecore/lib/aecore/chain/chain_state.ex @@ -69,30 +69,42 @@ defmodule Aecore.Chain.ChainState do @spec calculate_total_tokens(map()) :: integer() def calculate_total_tokens(chain_state) do - chain_state |> - Enum.map(fn{_account, data} -> data.balance end) |> - Enum.sum() + chain_state + |> Enum.map(fn{_account, data} -> data.balance + + Enum.reduce(data.locked, 0, fn(%{amount: amount}, locked_sum) -> + locked_sum + amount + end) + end) + |> Enum.sum() end @spec validate_chain_state(map()) :: boolean() def validate_chain_state(chain_state) do - chain_state |> - Enum.map(fn{_account, data} -> Map.get(data, :balance, 0) >= 0 end) |> - Enum.all?() + chain_state + |> Enum.map(fn{_account, data} -> Map.get(data, :balance, 0) >= 0 end) + |> Enum.all?() end @spec substract_locked_amounts_from_chain_state(map(), integer()) :: map() def substract_locked_amounts_from_chain_state(chain_state, new_block_height) do Enum.reduce(chain_state, %{}, fn({account, %{balance: balance, nonce: nonce, locked: locked}}, acc) -> - locked_amount = Enum.reduce(locked, 0, fn(%{amount: amount, block: lock_time_block}, amount_to_substract) -> - if(lock_time_block > new_block_height) do - amount_to_substract + amount - else - amount_to_substract + {locked_amount, updated_locked} = + Enum.reduce(locked, {0, []}, fn(%{amount: amount, block: lock_time_block}, {amount_update_value, updated_locked}) -> + cond do + lock_time_block > new_block_height -> + if(new_block_height == lock_time_block - 10) do + {amount_update_value - amount, updated_locked ++ [%{amount: amount, block: lock_time_block}]} + else + {amount_update_value, updated_locked ++ [%{amount: amount, block: lock_time_block}]} + end + lock_time_block == new_block_height -> + {amount_update_value + amount, updated_locked} + true -> + {amount_update_value, updated_locked} end end) - Map.put(acc, account, %{balance: balance - locked_amount, nonce: nonce, locked: locked}) + Map.put(acc, account, %{balance: balance + locked_amount, nonce: nonce, locked: updated_locked}) end) end diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index 3223e8cf..4d71b595 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -77,9 +77,6 @@ defmodule Aecore.Chain.Worker do new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) new_chain_state_locked_amounts = ChainState.substract_locked_amounts_from_chain_state(new_chain_state, latest_block.header.height + 1) - IO.puts("CHAIN:") - IO.inspect(new_chain_state) - IO.inspect(new_chain_state_locked_amounts) latest_header_hash = BlockValidation.block_header_hash(latest_block.header) @@ -176,7 +173,7 @@ defmodule Aecore.Chain.Worker do updated_latest_block_chainstate = Map.put(deleted_latest_chain_state, block_hash, new_chain_state_locked_amounts) - total_tokens = ChainState.calculate_total_tokens(new_chain_state) + total_tokens = ChainState.calculate_total_tokens(new_chain_state_locked_amounts) Logger.info(fn -> "Added block ##{block.header.height} with hash #{block.header diff --git a/apps/aecore/lib/aecore/miner/worker.ex b/apps/aecore/lib/aecore/miner/worker.ex index 8bddb595..da78fe7e 100644 --- a/apps/aecore/lib/aecore/miner/worker.ex +++ b/apps/aecore/lib/aecore/miner/worker.ex @@ -157,8 +157,6 @@ defmodule Aecore.Miner.Worker do end try do - IO.inspect("MINER:") - IO.inspect(chain_state) BlockValidation.validate_block!( latest_block, previous_block, From 2284e9a02c5e3b129f07861b6eec8184638fc309 Mon Sep 17 00:00:00 2001 From: d-velev Date: Fri, 24 Nov 2017 12:24:18 +0200 Subject: [PATCH 04/12] [GH-#125] Lock time block constant added to TxData --- apps/aecore/lib/aecore/miner/worker.ex | 3 +-- apps/aecore/lib/aecore/structures/tx_data.ex | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/aecore/lib/aecore/miner/worker.ex b/apps/aecore/lib/aecore/miner/worker.ex index da78fe7e..a7f6cd30 100644 --- a/apps/aecore/lib/aecore/miner/worker.ex +++ b/apps/aecore/lib/aecore/miner/worker.ex @@ -16,7 +16,6 @@ defmodule Aecore.Miner.Worker do require Logger @coinbase_transaction_value 100 - @coinbase_lock_time_block 10 @nonce_per_cycle 1 def start_link(_args) do @@ -176,7 +175,7 @@ defmodule Aecore.Miner.Worker do total_fees = calculate_total_fees(valid_txs) valid_txs = [get_coinbase_transaction(pubkey, total_fees, latest_block.header.height + 1 + - @coinbase_lock_time_block) | valid_txs] + TxData.get_lock_time_block()) | valid_txs] root_hash = BlockValidation.calculate_root_hash(valid_txs) new_block_state = ChainState.calculate_block_state(valid_txs) diff --git a/apps/aecore/lib/aecore/structures/tx_data.ex b/apps/aecore/lib/aecore/structures/tx_data.ex index d0df7988..60dffb4f 100644 --- a/apps/aecore/lib/aecore/structures/tx_data.ex +++ b/apps/aecore/lib/aecore/structures/tx_data.ex @@ -6,6 +6,8 @@ defmodule Aecore.Structures.TxData do alias Aecore.Structures.TxData @type tx_data() :: %TxData{} + @lock_time_block 10 + @doc """ Definition of Aecore TxData structure @@ -18,6 +20,9 @@ defmodule Aecore.Structures.TxData do defstruct [:nonce, :from_acc, :to_acc, :value, :fee, :lock_time_block] use ExConstructor + @spec get_lock_time_block() :: integer() + def get_lock_time_block(), do: @lock_time_block + @spec create(binary(), binary(), integer(), integer(), integer(), integer()) :: {:ok, %TxData{}} def create(from_acc, to_acc, value, nonce, fee, lock_time_block) do {:ok, %TxData{from_acc: from_acc, From 73d639368a7ae7e3ce0111b84be95c48af7f9467 Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Thu, 30 Nov 2017 12:11:55 +0200 Subject: [PATCH 05/12] [GH-#125] Fixed bug when substracting amounts from chain state; Refactored code and tests --- apps/aecore/config/dev.exs | 3 + apps/aecore/config/test.exs | 4 +- apps/aecore/lib/aecore/chain/chain_state.ex | 48 ++++--- apps/aecore/lib/aecore/chain/worker.ex | 12 +- apps/aecore/lib/aecore/miner/worker.ex | 6 +- apps/aecore/lib/aecore/peers/sync.ex | 6 +- apps/aecore/lib/aecore/peers/worker.ex | 1 - apps/aecore/lib/aecore/structures/tx_data.ex | 5 - .../utils/blockchain/block_validation.ex | 4 +- apps/aecore/test/aecore_chain_state_test.exs | 69 ++++++--- apps/aecore/test/aecore_chain_test.exs | 2 +- apps/aecore/test/aecore_keys_test.exs | 6 +- apps/aecore/test/aecore_tx_test.exs | 6 +- apps/aecore/test/aecore_txs_pool_test.exs | 10 +- apps/aecore/test/aecore_validation_test.exs | 12 +- .../test/multiple_transactions_test.exs | 135 +++++++++++++----- apps/aehttpclient/test/aehttpclient_test.exs | 8 +- 17 files changed, 235 insertions(+), 102 deletions(-) diff --git a/apps/aecore/config/dev.exs b/apps/aecore/config/dev.exs index 083f446e..bdf0cfa9 100644 --- a/apps/aecore/config/dev.exs +++ b/apps/aecore/config/dev.exs @@ -63,3 +63,6 @@ config :aecore, :pow, config :aecore, :peers, peers_target_count: 3, peers_max_count: 4 + +config :aecore, :tx_data, + lock_time_block: 10 diff --git a/apps/aecore/config/test.exs b/apps/aecore/config/test.exs index 008caf91..440daf9a 100644 --- a/apps/aecore/config/test.exs +++ b/apps/aecore/config/test.exs @@ -35,7 +35,7 @@ end config :aecore, :persistence, table: Path.absname(persistence_path) - + config :aecore, :pow, nif_path: Path.absname("apps/aecore/priv/aec_pow_cuckoo20_nif"), genesis_header: %{ @@ -64,3 +64,5 @@ config :aecore, :peers, peers_target_count: 2, peers_max_count: 4 +config :aecore, :tx_data, + lock_time_block: 0 diff --git a/apps/aecore/lib/aecore/chain/chain_state.ex b/apps/aecore/lib/aecore/chain/chain_state.ex index deb5b66e..cbdd4bd9 100644 --- a/apps/aecore/lib/aecore/chain/chain_state.ex +++ b/apps/aecore/lib/aecore/chain/chain_state.ex @@ -9,8 +9,8 @@ defmodule Aecore.Chain.ChainState do in the transactions a single block, returns a map with the accounts as key and their balance as value. """ - @spec calculate_block_state(list()) :: map() - def calculate_block_state(txs) do + @spec calculate_block_state(list(), integer()) :: map() + def calculate_block_state(txs, latest_block_height) do block_state = %{} block_state = @@ -20,14 +20,17 @@ defmodule Aecore.Chain.ChainState do transaction.data.from_acc != nil -> update_block_state(block_state, transaction.data.from_acc, -(transaction.data.value + transaction.data.fee), - transaction.data.nonce, transaction.data.lock_time_block) + transaction.data.nonce, transaction.data.lock_time_block, true) true -> block_state end - update_block_state(updated_block_state, transaction.data.to_acc, - transaction.data.value, 0, transaction.data.lock_time_block) + add_to_amount = latest_block_height + 1 != + transaction.data.lock_time_block - Application.get_env(:aecore, :tx_data)[:lock_time_block] + + update_block_state(updated_block_state, transaction.data.to_acc, transaction.data.value, + 0, transaction.data.lock_time_block, add_to_amount) end reduce_map_list(block_state) @@ -85,20 +88,17 @@ defmodule Aecore.Chain.ChainState do |> Enum.all?() end - @spec substract_locked_amounts_from_chain_state(map(), integer()) :: map() - def substract_locked_amounts_from_chain_state(chain_state, new_block_height) do + @spec update_chain_state_locked(map(), integer()) :: map() + def update_chain_state_locked(chain_state, new_block_height) do Enum.reduce(chain_state, %{}, fn({account, %{balance: balance, nonce: nonce, locked: locked}}, acc) -> - {locked_amount, updated_locked} = + {locked_amount, updated_locked} = Enum.reduce(locked, {0, []}, fn(%{amount: amount, block: lock_time_block}, {amount_update_value, updated_locked}) -> cond do lock_time_block > new_block_height -> - if(new_block_height == lock_time_block - 10) do - {amount_update_value - amount, updated_locked ++ [%{amount: amount, block: lock_time_block}]} - else - {amount_update_value, updated_locked ++ [%{amount: amount, block: lock_time_block}]} - end + {amount_update_value, updated_locked ++ [%{amount: amount, block: lock_time_block}]} lock_time_block == new_block_height -> {amount_update_value + amount, updated_locked} + true -> {amount_update_value, updated_locked} end @@ -108,8 +108,8 @@ defmodule Aecore.Chain.ChainState do end) end - @spec update_block_state(map(), binary(), integer(), integer(), integer()) :: map() - defp update_block_state(block_state, account, value, nonce, lock_time_block) do + @spec update_block_state(map(), binary(), integer(), integer(), integer(), boolean()) :: map() + defp update_block_state(block_state, account, value, nonce, lock_time_block, add_to_amount) do block_state_filled_empty = cond do !Map.has_key?(block_state, account) -> @@ -119,6 +119,12 @@ defmodule Aecore.Chain.ChainState do block_state end + new_balance = if(add_to_amount) do + block_state_filled_empty[account].balance + value + else + block_state_filled_empty[account].balance + end + new_nonce = cond do block_state_filled_empty[account].nonce < nonce -> nonce @@ -127,10 +133,16 @@ defmodule Aecore.Chain.ChainState do block_state_filled_empty[account].nonce end - new_account_state = %{balance: block_state_filled_empty[account].balance + value, + new_locked = if(value > 0) do + block_state_filled_empty[account].locked ++ [%{amount: value, block: lock_time_block}] + else + block_state_filled_empty[account].locked + end + + new_account_state = %{balance: new_balance, nonce: new_nonce, - locked: block_state_filled_empty[account].locked ++ - [%{amount: value, block: lock_time_block}]} + locked: new_locked} + Map.put(block_state_filled_empty, account, new_account_state) end diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index 4d71b595..8cdd95fd 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -27,7 +27,8 @@ defmodule Aecore.Chain.Worker do genesis_block_hash = BlockValidation.block_header_hash(Block.genesis_block().header) genesis_block_map = %{genesis_block_hash => Block.genesis_block()} - genesis_chain_state = ChainState.calculate_block_state(Block.genesis_block().txs) + genesis_chain_state = + ChainState.calculate_block_state(Block.genesis_block().txs, Block.genesis_block().header.height) latest_block_chain_state = %{genesis_block_hash => genesis_chain_state} txs_index = calculate_block_acc_txs_info(Block.genesis_block()) {genesis_block_map, latest_block_chain_state, txs_index} @@ -73,10 +74,10 @@ defmodule Aecore.Chain.Worker do latest_block = latest_block() prev_block_chain_state = chain_state() - new_block_state = ChainState.calculate_block_state(block.txs) + new_block_state = ChainState.calculate_block_state(block.txs, latest_block.header.height) new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) new_chain_state_locked_amounts = - ChainState.substract_locked_amounts_from_chain_state(new_chain_state, latest_block.header.height + 1) + ChainState.update_chain_state_locked(new_chain_state, latest_block.header.height + 1) latest_header_hash = BlockValidation.block_header_hash(latest_block.header) @@ -148,10 +149,11 @@ defmodule Aecore.Chain.Worker do def handle_call({:add_validated_block, %Block{} = block}, _from, state) do {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) + latest_block = block_map[block.header.prev_hash] + new_block_state = ChainState.calculate_block_state(block.txs, latest_block.header.height) new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) new_chain_state_locked_amounts = - ChainState.substract_locked_amounts_from_chain_state(new_chain_state, block.header.height) + ChainState.update_chain_state_locked(new_chain_state, block.header.height) new_block_txs_index = calculate_block_acc_txs_info(block) new_txs_index = update_txs_index(txs_index, new_block_txs_index) diff --git a/apps/aecore/lib/aecore/miner/worker.ex b/apps/aecore/lib/aecore/miner/worker.ex index a7f6cd30..5b2353b7 100644 --- a/apps/aecore/lib/aecore/miner/worker.ex +++ b/apps/aecore/lib/aecore/miner/worker.ex @@ -175,13 +175,13 @@ defmodule Aecore.Miner.Worker do total_fees = calculate_total_fees(valid_txs) valid_txs = [get_coinbase_transaction(pubkey, total_fees, latest_block.header.height + 1 + - TxData.get_lock_time_block()) | valid_txs] + Application.get_env(:aecore, :tx_data)[:lock_time_block]) | valid_txs] root_hash = BlockValidation.calculate_root_hash(valid_txs) - new_block_state = ChainState.calculate_block_state(valid_txs) + new_block_state = ChainState.calculate_block_state(valid_txs, latest_block.header.height) new_chain_state = ChainState.calculate_chain_state(new_block_state, chain_state) new_chain_state_locked_amounts = - ChainState.substract_locked_amounts_from_chain_state(new_chain_state, latest_block.header.height + 1) + ChainState.update_chain_state_locked(new_chain_state, latest_block.header.height + 1) chain_state_hash = ChainState.calculate_chain_state_hash(new_chain_state_locked_amounts) latest_block_hash = BlockValidation.block_header_hash(latest_block.header) diff --git a/apps/aecore/lib/aecore/peers/sync.ex b/apps/aecore/lib/aecore/peers/sync.ex index 5279bccb..14f289d3 100644 --- a/apps/aecore/lib/aecore/peers/sync.ex +++ b/apps/aecore/lib/aecore/peers/sync.ex @@ -5,9 +5,6 @@ defmodule Aecore.Peers.Sync do alias Aecore.Peers.Worker, as: Peers alias Aehttpclient.Client, as: HttpClient - alias Aecore.Chain.Worker, as: Chain - alias Aecore.Utils.Blockchain.BlockValidation - alias Aecore.Utils.Serialization use GenServer @@ -101,7 +98,7 @@ defmodule Aecore.Peers.Sync do |> Enum.shuffle |> Enum.reduce(0, fn(peer, acc) -> #if we have successfully added less then number_of_peers_to_add peers then try to add another one - if acc < number_of_peers_to_add do + if acc < number_of_peers_to_add do case Peers.add_peer(peer) do :ok -> acc+1 _ -> acc @@ -112,4 +109,3 @@ defmodule Aecore.Peers.Sync do end) end end - diff --git a/apps/aecore/lib/aecore/peers/worker.ex b/apps/aecore/lib/aecore/peers/worker.ex index 57c7bd75..f45e7558 100644 --- a/apps/aecore/lib/aecore/peers/worker.ex +++ b/apps/aecore/lib/aecore/peers/worker.ex @@ -10,7 +10,6 @@ defmodule Aecore.Peers.Worker do alias Aecore.Utils.Blockchain.BlockValidation alias Aehttpclient.Client, as: HttpClient alias Aecore.Utils.Serialization - alias Aecore.Peers.Sync require Logger diff --git a/apps/aecore/lib/aecore/structures/tx_data.ex b/apps/aecore/lib/aecore/structures/tx_data.ex index 60dffb4f..d0df7988 100644 --- a/apps/aecore/lib/aecore/structures/tx_data.ex +++ b/apps/aecore/lib/aecore/structures/tx_data.ex @@ -6,8 +6,6 @@ defmodule Aecore.Structures.TxData do alias Aecore.Structures.TxData @type tx_data() :: %TxData{} - @lock_time_block 10 - @doc """ Definition of Aecore TxData structure @@ -20,9 +18,6 @@ defmodule Aecore.Structures.TxData do defstruct [:nonce, :from_acc, :to_acc, :value, :fee, :lock_time_block] use ExConstructor - @spec get_lock_time_block() :: integer() - def get_lock_time_block(), do: @lock_time_block - @spec create(binary(), binary(), integer(), integer(), integer(), integer()) :: {:ok, %TxData{}} def create(from_acc, to_acc, value, nonce, fee, lock_time_block) do {:ok, %TxData{from_acc: from_acc, diff --git a/apps/aecore/lib/aecore/utils/blockchain/block_validation.ex b/apps/aecore/lib/aecore/utils/blockchain/block_validation.ex index dd7eda4b..9436ca1e 100644 --- a/apps/aecore/lib/aecore/utils/blockchain/block_validation.ex +++ b/apps/aecore/lib/aecore/utils/blockchain/block_validation.ex @@ -120,8 +120,8 @@ defmodule Aecore.Utils.Blockchain.BlockValidation do cond do tx_has_valid_nonce && from_account_has_necessary_balance -> - from_acc_new_state = %{balance: -tx.data.value, nonce: 1} - to_acc_new_state = %{balance: tx.data.value, nonce: 0} + from_acc_new_state = %{balance: -tx.data.value, nonce: 1, locked: []} + to_acc_new_state = %{balance: tx.data.value, nonce: 0, locked: []} chain_state_changes = %{tx.data.from_acc => from_acc_new_state, tx.data.to_acc => to_acc_new_state} updated_chain_state = ChainState.calculate_chain_state(chain_state_changes, chain_state) {true, updated_chain_state} diff --git a/apps/aecore/test/aecore_chain_state_test.exs b/apps/aecore/test/aecore_chain_state_test.exs index 5834aca5..0948b966 100644 --- a/apps/aecore/test/aecore_chain_state_test.exs +++ b/apps/aecore/test/aecore_chain_state_test.exs @@ -10,27 +10,47 @@ defmodule AecoreChainStateTest do alias Aecore.Structures.TxData, as: TxData alias Aecore.Structures.SignedTx, as: SignedTx alias Aecore.Chain.ChainState, as: ChainState + alias Aecore.Chain.Worker, as: Chain test "block state" do block = get_block() + lock_time_block = Enum.at(block.txs, 0).data.lock_time_block + latest_block = Chain.latest_block() - assert %{"a" => %{balance: 1, nonce: 102}, - "b" => %{balance: -2, nonce: 1}, - "c" => %{balance: -3, nonce: 1}} == - ChainState.calculate_block_state(block.txs) + assert %{"a" => %{balance: -9, nonce: 102, + locked: [%{amount: 10, block: lock_time_block}]}, + "b" => %{nonce: 1, balance: -11, + locked: [%{amount: 4, block: lock_time_block}, + %{amount: 5, block: lock_time_block}]}, + "c" => %{nonce: 1, balance: -5, + locked: [%{amount: 2, block: lock_time_block}]}} == + ChainState.calculate_block_state(block.txs, latest_block.header.height) end test "chain state" do + next_block_height = Chain.latest_block().header.height + 1 chain_state = - ChainState.calculate_chain_state(%{"a" => %{balance: 3, nonce: 100}, - "b" => %{balance: 5, nonce: 1}, - "c" => %{balance: 4, nonce: 1}}, - %{"a" => %{balance: 3, nonce: 0}, - "b" => %{balance: -1, nonce: 0}, - "c" => %{balance: -2, nonce: 0}}) - assert %{"a" => %{balance: 6, nonce: 100}, - "b" => %{balance: 4, nonce: 1}, - "c" => %{balance: 2, nonce: 1}} == chain_state + ChainState.calculate_chain_state(%{"a" => %{balance: 3, nonce: 100, + locked: [%{amount: 1, block: next_block_height}]}, + "b" => %{balance: 5, nonce: 1, + locked: [%{amount: 1, block: next_block_height + 1}]}, + "c" => %{balance: 4, nonce: 1, + locked: [%{amount: 1, block: next_block_height}]}}, + %{"a" => %{balance: 3, nonce: 0, locked: []}, + "b" => %{balance: -1, nonce: 0, locked: []}, + "c" => %{balance: -2, nonce: 0, locked: []}}) + assert %{"a" => %{balance: 6, nonce: 100, + locked: [%{amount: 1, block: next_block_height}]}, + "b" => %{balance: 4, nonce: 1, + locked: [%{amount: 1, block: next_block_height + 1}]}, + "c" => %{balance: 2, nonce: 1, + locked: [%{amount: 1, block: next_block_height}]}} == chain_state + + new_chain_state_locked_amounts = + ChainState.update_chain_state_locked(chain_state, next_block_height) + assert %{"a" => %{balance: 7, nonce: 100, locked: []}, + "b" => %{balance: 4, nonce: 1, locked: [%{amount: 1, block: next_block_height + 1}]}, + "c" => %{balance: 3, nonce: 1, locked: []}} == new_chain_state_locked_amounts end defp get_block() do @@ -38,13 +58,28 @@ defmodule AecoreChainStateTest do txs_hash: <<12, 123, 12>>, difficulty_target: 0, nonce: 0, timestamp: System.system_time(:milliseconds), version: 1}, txs: [ %SignedTx{data: %TxData{from_acc: "a", to_acc: "b", - value: 5, nonce: 101, fee: 1}, signature: <<0>>}, + value: 5, nonce: 101, fee: 1, + lock_time_block: Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1}, + signature: <<0>>}, + %SignedTx{data: %TxData{from_acc: "a", to_acc: "c", - value: 2, nonce: 102, fee: 1}, signature: <<0>>}, + value: 2, nonce: 102, fee: 1, + lock_time_block: Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1}, + signature: <<0>>}, + %SignedTx{data: %TxData{from_acc: "c", to_acc: "b", - value: 4, nonce: 1, fee: 1}, signature: <<0>>}, + value: 4, nonce: 1, fee: 1, + lock_time_block: Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1}, + signature: <<0>>}, + %SignedTx{data: %TxData{from_acc: "b", to_acc: "a", - value: 10, nonce: 1, fee: 1}, signature: <<0>>}]} + value: 10, nonce: 1, fee: 1, + lock_time_block: Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1}, + signature: <<0>>}]} end end diff --git a/apps/aecore/test/aecore_chain_test.exs b/apps/aecore/test/aecore_chain_test.exs index c5a48572..dc381807 100644 --- a/apps/aecore/test/aecore_chain_test.exs +++ b/apps/aecore/test/aecore_chain_test.exs @@ -27,7 +27,7 @@ defmodule AecoreChainTest do latest_block_hash = BlockValidation.block_header_hash(latest_block.header) chain_state = Chain.chain_state(latest_block_hash) - new_block_state = ChainState.calculate_block_state([]) + new_block_state = ChainState.calculate_block_state([], latest_block.header.height) new_chain_state = ChainState.calculate_chain_state(new_block_state, chain_state) new_chain_state_hash = ChainState.calculate_chain_state_hash(new_chain_state) diff --git a/apps/aecore/test/aecore_keys_test.exs b/apps/aecore/test/aecore_keys_test.exs index f5a7a605..a97d4992 100644 --- a/apps/aecore/test/aecore_keys_test.exs +++ b/apps/aecore/test/aecore_keys_test.exs @@ -20,7 +20,11 @@ defmodule AecoreKeysTest do test "sign transaction" do {:ok, to_account} = Keys.pubkey() - assert {:ok, _} = Keys.sign_tx(to_account, 5, Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1) + assert {:ok, _} = Keys.sign_tx(to_account, 5, + Map.get(Chain.chain_state, + to_account, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) end test "check pubkey length" do diff --git a/apps/aecore/test/aecore_tx_test.exs b/apps/aecore/test/aecore_tx_test.exs index 365feb07..ee4c36fd 100644 --- a/apps/aecore/test/aecore_tx_test.exs +++ b/apps/aecore/test/aecore_tx_test.exs @@ -15,7 +15,11 @@ defmodule AecoreTxTest do test "create and verify a signed tx" do {:ok, to_account} = Keys.pubkey() - {:ok, tx} = Keys.sign_tx(to_account, 5, Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1) + {:ok, tx} = Keys.sign_tx(to_account, 5, + Map.get(Chain.chain_state, + to_account, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :true = Keys.verify_tx(tx) end diff --git a/apps/aecore/test/aecore_txs_pool_test.exs b/apps/aecore/test/aecore_txs_pool_test.exs index fd97e6b5..7baacd49 100644 --- a/apps/aecore/test/aecore_txs_pool_test.exs +++ b/apps/aecore/test/aecore_txs_pool_test.exs @@ -18,9 +18,15 @@ defmodule AecoreTxsPoolTest do test "add transaction, remove it and get pool" do {:ok, to_account} = Keys.pubkey() {:ok, tx1} = Keys.sign_tx(to_account, 5, - Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, + to_account, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) {:ok, tx2} = Keys.sign_tx(to_account, 5, - Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, + to_account, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) Miner.resume() Miner.suspend() assert :ok = Pool.add_transaction(tx1) diff --git a/apps/aecore/test/aecore_validation_test.exs b/apps/aecore/test/aecore_validation_test.exs index 02e509f1..1d11a79f 100644 --- a/apps/aecore/test/aecore_validation_test.exs +++ b/apps/aecore/test/aecore_validation_test.exs @@ -50,16 +50,22 @@ defmodule AecoreValidationTest do version: 1}, txs: []} blocks_for_difficulty_calculation = [new_block, prev_block] - assert BlockValidation.validate_block!(new_block, prev_block, %{}, + assert BlockValidation.validate_block!(new_block, prev_block, %{}, blocks_for_difficulty_calculation) == :ok end test "validate transactions in a block" do {:ok, to_account} = Keys.pubkey() {:ok, tx1} = Keys.sign_tx(to_account, 5, - Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, + to_account, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) {:ok, tx2} = Keys.sign_tx(to_account, 10, - Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, + to_account, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) block = %{Block.genesis_block | txs: [tx1, tx2]} assert block |> BlockValidation.validate_block_transactions diff --git a/apps/aecore/test/multiple_transactions_test.exs b/apps/aecore/test/multiple_transactions_test.exs index d4a2cbf6..bf119f35 100644 --- a/apps/aecore/test/multiple_transactions_test.exs +++ b/apps/aecore/test/multiple_transactions_test.exs @@ -30,13 +30,17 @@ defmodule MultipleTransactionsTest do Miner.suspend() Pool.get_and_empty_pool() {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account2, 99, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -48,13 +52,17 @@ defmodule MultipleTransactionsTest do # account A has 100 tokens, spends 109 (+1 fee) to B should be invalid {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account2, 109, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -65,11 +73,17 @@ defmodule MultipleTransactionsTest do # account A has 100 tokens, spends 39 (+1 fee) to B, and two times 29 (+1 fee) to C should succeed account1_initial_nonce = Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce - tx = create_signed_tx(account1, account2, 39, account1_initial_nonce + 1, 1) + tx = create_signed_tx(account1, account2, 39, account1_initial_nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) - tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 2, 1) + tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 2, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) - tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 3, 1) + tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 3, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -84,16 +98,24 @@ defmodule MultipleTransactionsTest do # last transaction to C should be invalid, others be included account1_initial_nonce = Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() - tx = create_signed_tx(account1, account2, 49, account1_initial_nonce + 1, 1) + tx = create_signed_tx(account1, account2, 49, account1_initial_nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) - tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 2, 1) + tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 2, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) - tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 3, 1) + tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 3, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -106,16 +128,22 @@ defmodule MultipleTransactionsTest do # account C has 100 tokens, spends 99 (+1 fee) to B, B spends 99 (+1 fee) to A should succeed {:ok, tx} = Keys.sign_tx(account3_pub_key, 13, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account3, account2, 99, - Map.get(Chain.chain_state, account3_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account3_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) tx = create_signed_tx(account2, account1, 99, - Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -125,7 +153,7 @@ defmodule MultipleTransactionsTest do assert 119 == Chain.chain_state[account1_pub_key].balance end - @tag timeout: 10000000 + # @tag timeout: 10000000 test "in multiple blocks" do {account1, account2, account3} = get_accounts_multiple_blocks() {account1_pub_key, _account1_priv_key} = account1 @@ -138,13 +166,17 @@ defmodule MultipleTransactionsTest do Miner.suspend() Pool.get_and_empty_pool() {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account2, 99, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -156,13 +188,17 @@ defmodule MultipleTransactionsTest do # account A has 100 tokens, spends 109 (+1 fee) to B should be invalid {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account2, 109, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -173,19 +209,25 @@ defmodule MultipleTransactionsTest do # account A has 100 tokens, spends 39 (+1 fee) to B, and two times 29 (+1 fee) to C should succeed tx = create_signed_tx(account1, account2, 39, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account3, 29, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account3, 29, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -199,25 +241,33 @@ defmodule MultipleTransactionsTest do # account A has 99 (+1 fee) tokens, spends 49 (+1 fee) to B, and two times 29 (+1 fee) to C, # last transaction to C should be invalid, others be included {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account2, 49, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account3, 29, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account3, 29, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -230,19 +280,25 @@ defmodule MultipleTransactionsTest do # account A has 100 tokens, spends 99 (+1 fee) to B, B spends 99 (+1 fee) to C should succeed {:ok, tx} = Keys.sign_tx(account1_pub_key, 80, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account2, 99, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account2, account3, 99, - Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -266,19 +322,27 @@ defmodule MultipleTransactionsTest do Miner.suspend() Pool.get_and_empty_pool() {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) {:ok, tx} = Keys.sign_tx(account2_pub_key, 100, - Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 2, 0) + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 2, 0, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account3, 99, - Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) tx = create_signed_tx(account2, account3, 99, - Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) assert :ok = Pool.add_transaction(tx) miner_balance_before_mining = Map.get(Chain.chain_state, pubkey).balance Miner.resume() @@ -375,10 +439,11 @@ defmodule MultipleTransactionsTest do {account1, account2, account3} end - defp create_signed_tx(from_acc, to_acc, value, nonce, fee) do + defp create_signed_tx(from_acc, to_acc, value, nonce, fee, lock_time_block) do {from_acc_pub_key, from_acc_priv_key} = from_acc {to_acc_pub_key, _to_acc_priv_key} = to_acc - {:ok, tx_data} = TxData.create(from_acc_pub_key, to_acc_pub_key, value, nonce, fee) + {:ok, tx_data} = TxData.create(from_acc_pub_key, to_acc_pub_key, value, + nonce, fee, lock_time_block) {:ok, signature} = Keys.sign(tx_data, from_acc_priv_key) %SignedTx{data: tx_data, signature: signature} diff --git a/apps/aehttpclient/test/aehttpclient_test.exs b/apps/aehttpclient/test/aehttpclient_test.exs index dc3f5c60..6f7aba30 100644 --- a/apps/aehttpclient/test/aehttpclient_test.exs +++ b/apps/aehttpclient/test/aehttpclient_test.exs @@ -21,9 +21,13 @@ defmodule AehttpclientTest do def add_txs_to_pool() do {:ok, to_account} = Keys.pubkey() {:ok, tx1} = Keys.sign_tx(to_account, 5, - Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) {:ok, tx2} = Keys.sign_tx(to_account, 5, - Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1) + Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) Pool.add_transaction(tx1) Pool.add_transaction(tx2) end From 515260c3438eb7cb322123586c336ff68c64bac4 Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Mon, 11 Dec 2017 16:45:33 +0200 Subject: [PATCH 06/12] [GH-#125] Small refactoring --- apps/aecore/config/dev.exs | 2 +- apps/aecore/config/test.exs | 2 +- apps/aecore/lib/aecore/chain/chain_state.ex | 32 ++++++---- apps/aecore/lib/aecore/chain/worker.ex | 14 ++-- apps/aecore/lib/aecore/miner/worker.ex | 6 +- apps/aecore/test/aecore_chain_state_test.exs | 11 ++-- apps/aecore/test/aecore_chain_test.exs | 4 +- apps/aecore/test/aecore_keys_test.exs | 2 +- apps/aecore/test/aecore_tx_test.exs | 2 +- apps/aecore/test/aecore_txs_pool_test.exs | 4 +- apps/aecore/test/aecore_validation_test.exs | 4 +- .../test/multiple_transactions_test.exs | 64 +++++++++---------- apps/aehttpclient/test/aehttpclient_test.exs | 4 +- 13 files changed, 85 insertions(+), 66 deletions(-) diff --git a/apps/aecore/config/dev.exs b/apps/aecore/config/dev.exs index 5d04882a..60b026b9 100644 --- a/apps/aecore/config/dev.exs +++ b/apps/aecore/config/dev.exs @@ -65,4 +65,4 @@ config :aecore, :peers, peers_max_count: 4 config :aecore, :tx_data, - lock_time_block: 10 + lock_time_coinbase: 10 diff --git a/apps/aecore/config/test.exs b/apps/aecore/config/test.exs index 0d184840..707c6bd2 100644 --- a/apps/aecore/config/test.exs +++ b/apps/aecore/config/test.exs @@ -65,4 +65,4 @@ config :aecore, :peers, peers_max_count: 4 config :aecore, :tx_data, - lock_time_block: 0 + lock_time_coinbase: 0 diff --git a/apps/aecore/lib/aecore/chain/chain_state.ex b/apps/aecore/lib/aecore/chain/chain_state.ex index cbdd4bd9..b5483fee 100644 --- a/apps/aecore/lib/aecore/chain/chain_state.ex +++ b/apps/aecore/lib/aecore/chain/chain_state.ex @@ -9,8 +9,8 @@ defmodule Aecore.Chain.ChainState do in the transactions a single block, returns a map with the accounts as key and their balance as value. """ - @spec calculate_block_state(list(), integer()) :: map() - def calculate_block_state(txs, latest_block_height) do + @spec calculate_block_state(list(), integer(), integer()) :: map() + def calculate_block_state(txs, latest_block_height, lock_time_coinbase) do block_state = %{} block_state = @@ -27,7 +27,7 @@ defmodule Aecore.Chain.ChainState do end add_to_amount = latest_block_height + 1 != - transaction.data.lock_time_block - Application.get_env(:aecore, :tx_data)[:lock_time_block] + transaction.data.lock_time_block - lock_time_coinbase update_block_state(updated_block_state, transaction.data.to_acc, transaction.data.value, 0, transaction.data.lock_time_block, add_to_amount) @@ -72,13 +72,18 @@ defmodule Aecore.Chain.ChainState do @spec calculate_total_tokens(map()) :: integer() def calculate_total_tokens(chain_state) do - chain_state - |> Enum.map(fn{_account, data} -> data.balance + - Enum.reduce(data.locked, 0, fn(%{amount: amount}, locked_sum) -> - locked_sum + amount - end) + Enum.reduce(chain_state, {0, 0, 0}, fn({_account, data}, acc) -> + {total_tokens, total_unlocked_tokens, total_locked_tokens} = acc + locked_tokens = + Enum.reduce(data.locked, 0, fn(%{amount: amount}, locked_sum) -> + locked_sum + amount + end) + new_total_tokens = total_tokens + data.balance + locked_tokens + new_total_unlocked_tokens = total_unlocked_tokens + data.balance + new_total_locked_tokens = total_locked_tokens + locked_tokens + + {new_total_tokens, new_total_unlocked_tokens, new_total_locked_tokens} end) - |> Enum.sum() end @spec validate_chain_state(map()) :: boolean() @@ -91,7 +96,7 @@ defmodule Aecore.Chain.ChainState do @spec update_chain_state_locked(map(), integer()) :: map() def update_chain_state_locked(chain_state, new_block_height) do Enum.reduce(chain_state, %{}, fn({account, %{balance: balance, nonce: nonce, locked: locked}}, acc) -> - {locked_amount, updated_locked} = + {unlocked_amount, updated_locked} = Enum.reduce(locked, {0, []}, fn(%{amount: amount, block: lock_time_block}, {amount_update_value, updated_locked}) -> cond do lock_time_block > new_block_height -> @@ -100,11 +105,16 @@ defmodule Aecore.Chain.ChainState do {amount_update_value + amount, updated_locked} true -> + Logger.error(fn -> + "Update chain state locked: + new block height (#{new_block_height}) greater than lock time block (#{message})" + end) + {amount_update_value, updated_locked} end end) - Map.put(acc, account, %{balance: balance + locked_amount, nonce: nonce, locked: updated_locked}) + Map.put(acc, account, %{balance: balance + unlocked_amount, nonce: nonce, locked: updated_locked}) end) end diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index 38d4989a..307b41f1 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -23,7 +23,8 @@ defmodule Aecore.Chain.Worker do genesis_block_hash = BlockValidation.block_header_hash(Block.genesis_block().header) genesis_block_map = %{genesis_block_hash => Block.genesis_block()} genesis_chain_state = - ChainState.calculate_block_state(Block.genesis_block().txs, Block.genesis_block().header.height) + ChainState.calculate_block_state(Block.genesis_block().txs, Block.genesis_block().header.height, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) latest_block_chain_state = %{genesis_block_hash => genesis_chain_state} txs_index = calculate_block_acc_txs_info(Block.genesis_block()) @@ -71,7 +72,9 @@ defmodule Aecore.Chain.Worker do latest_block = latest_block() prev_block_chain_state = chain_state() - new_block_state = ChainState.calculate_block_state(block.txs, latest_block.header.height) + new_block_state = + ChainState.calculate_block_state(block.txs, latest_block.header.height, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) new_chain_state_locked_amounts = ChainState.update_chain_state_locked(new_chain_state, latest_block.header.height + 1) @@ -160,7 +163,9 @@ defmodule Aecore.Chain.Worker do {block_map, latest_block_chain_state, txs_index} = state prev_block_chain_state = latest_block_chain_state[block.header.prev_hash] latest_block = block_map[block.header.prev_hash] - new_block_state = ChainState.calculate_block_state(block.txs, latest_block.header.height) + new_block_state = + ChainState.calculate_block_state(block.txs, latest_block.header.height, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) new_chain_state_locked_amounts = ChainState.update_chain_state_locked(new_chain_state, block.header.height) @@ -190,7 +195,7 @@ defmodule Aecore.Chain.Worker do Logger.info(fn -> "Added block ##{block.header.height} with hash #{block.header |> BlockValidation.block_header_hash() - |> Base.encode16()}, total tokens: #{total_tokens}" + |> Base.encode16()}, total tokens: #{elem(total_tokens, 0)}" end) ## Store latest block to disk @@ -222,7 +227,6 @@ defmodule Aecore.Chain.Worker do def terminate(_, state) do Persistence.store_state(state) Logger.warn("Terminting, state was stored on disk ...") - end defp calculate_block_acc_txs_info(block) do diff --git a/apps/aecore/lib/aecore/miner/worker.ex b/apps/aecore/lib/aecore/miner/worker.ex index a317b00e..9431a3f3 100644 --- a/apps/aecore/lib/aecore/miner/worker.ex +++ b/apps/aecore/lib/aecore/miner/worker.ex @@ -175,10 +175,12 @@ defmodule Aecore.Miner.Worker do total_fees = calculate_total_fees(valid_txs) valid_txs = [get_coinbase_transaction(pubkey, total_fees, latest_block.header.height + 1 + - Application.get_env(:aecore, :tx_data)[:lock_time_block]) | valid_txs] + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) | valid_txs] root_hash = BlockValidation.calculate_root_hash(valid_txs) - new_block_state = ChainState.calculate_block_state(valid_txs, latest_block.header.height) + new_block_state = + ChainState.calculate_block_state(valid_txs, latest_block.header.height, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) new_chain_state = ChainState.calculate_chain_state(new_block_state, chain_state) new_chain_state_locked_amounts = ChainState.update_chain_state_locked(new_chain_state, latest_block.header.height + 1) diff --git a/apps/aecore/test/aecore_chain_state_test.exs b/apps/aecore/test/aecore_chain_state_test.exs index 0948b966..bd7e7e4f 100644 --- a/apps/aecore/test/aecore_chain_state_test.exs +++ b/apps/aecore/test/aecore_chain_state_test.exs @@ -24,7 +24,8 @@ defmodule AecoreChainStateTest do %{amount: 5, block: lock_time_block}]}, "c" => %{nonce: 1, balance: -5, locked: [%{amount: 2, block: lock_time_block}]}} == - ChainState.calculate_block_state(block.txs, latest_block.header.height) + ChainState.calculate_block_state(block.txs, latest_block.header.height, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) end test "chain state" do @@ -60,25 +61,25 @@ defmodule AecoreChainStateTest do %SignedTx{data: %TxData{from_acc: "a", to_acc: "b", value: 5, nonce: 101, fee: 1, lock_time_block: Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1}, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1}, signature: <<0>>}, %SignedTx{data: %TxData{from_acc: "a", to_acc: "c", value: 2, nonce: 102, fee: 1, lock_time_block: Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1}, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1}, signature: <<0>>}, %SignedTx{data: %TxData{from_acc: "c", to_acc: "b", value: 4, nonce: 1, fee: 1, lock_time_block: Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1}, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1}, signature: <<0>>}, %SignedTx{data: %TxData{from_acc: "b", to_acc: "a", value: 10, nonce: 1, fee: 1, lock_time_block: Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1}, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1}, signature: <<0>>}]} end diff --git a/apps/aecore/test/aecore_chain_test.exs b/apps/aecore/test/aecore_chain_test.exs index 1ee66410..27898f63 100644 --- a/apps/aecore/test/aecore_chain_test.exs +++ b/apps/aecore/test/aecore_chain_test.exs @@ -27,7 +27,9 @@ defmodule AecoreChainTest do latest_block_hash = BlockValidation.block_header_hash(latest_block.header) chain_state = Chain.chain_state(latest_block_hash) - new_block_state = ChainState.calculate_block_state([], latest_block.header.height) + new_block_state = + ChainState.calculate_block_state([], latest_block.header.height, + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) new_chain_state = ChainState.calculate_chain_state(new_block_state, chain_state) new_chain_state_hash = ChainState.calculate_chain_state_hash(new_chain_state) diff --git a/apps/aecore/test/aecore_keys_test.exs b/apps/aecore/test/aecore_keys_test.exs index a97d4992..996f9f8e 100644 --- a/apps/aecore/test/aecore_keys_test.exs +++ b/apps/aecore/test/aecore_keys_test.exs @@ -24,7 +24,7 @@ defmodule AecoreKeysTest do Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) end test "check pubkey length" do diff --git a/apps/aecore/test/aecore_tx_test.exs b/apps/aecore/test/aecore_tx_test.exs index ee4c36fd..2a48fafa 100644 --- a/apps/aecore/test/aecore_tx_test.exs +++ b/apps/aecore/test/aecore_tx_test.exs @@ -19,7 +19,7 @@ defmodule AecoreTxTest do Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :true = Keys.verify_tx(tx) end diff --git a/apps/aecore/test/aecore_txs_pool_test.exs b/apps/aecore/test/aecore_txs_pool_test.exs index 988b5580..b6638563 100644 --- a/apps/aecore/test/aecore_txs_pool_test.exs +++ b/apps/aecore/test/aecore_txs_pool_test.exs @@ -21,12 +21,12 @@ defmodule AecoreTxsPoolTest do Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) {:ok, tx2} = Keys.sign_tx(to_account, 5, Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) Miner.resume() Miner.suspend() assert :ok = Pool.add_transaction(tx1) diff --git a/apps/aecore/test/aecore_validation_test.exs b/apps/aecore/test/aecore_validation_test.exs index 25892482..5635bfde 100644 --- a/apps/aecore/test/aecore_validation_test.exs +++ b/apps/aecore/test/aecore_validation_test.exs @@ -60,12 +60,12 @@ defmodule AecoreValidationTest do Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) {:ok, tx2} = Keys.sign_tx(to_account, 10, Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) block = %{Block.genesis_block | txs: [tx1, tx2]} assert block |> BlockValidation.validate_block_transactions diff --git a/apps/aecore/test/multiple_transactions_test.exs b/apps/aecore/test/multiple_transactions_test.exs index 3f6053eb..4ee9c8c4 100644 --- a/apps/aecore/test/multiple_transactions_test.exs +++ b/apps/aecore/test/multiple_transactions_test.exs @@ -32,7 +32,7 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -40,7 +40,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account2, 99, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -54,7 +54,7 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -62,7 +62,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account2, 109, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -75,15 +75,15 @@ defmodule MultipleTransactionsTest do account1_initial_nonce = Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce tx = create_signed_tx(account1, account2, 39, account1_initial_nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 2, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 3, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -100,22 +100,22 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() Pool.get_and_empty_pool() tx = create_signed_tx(account1, account2, 49, account1_initial_nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 2, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) tx = create_signed_tx(account1, account3, 29, account1_initial_nonce + 3, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -130,7 +130,7 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account3_pub_key, 13, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -138,12 +138,12 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account3, account2, 99, Map.get(Chain.chain_state, account3_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) tx = create_signed_tx(account2, account1, 99, Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -168,7 +168,7 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -176,7 +176,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account2, 99, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -190,7 +190,7 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -198,7 +198,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account2, 109, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -211,7 +211,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account2, 39, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -219,7 +219,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account3, 29, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -227,7 +227,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account3, 29, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -243,7 +243,7 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -251,7 +251,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account2, 49, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -259,7 +259,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account3, 29, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -267,7 +267,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account3, 29, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -282,7 +282,7 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account1_pub_key, 80, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -290,7 +290,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account2, 99, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -298,7 +298,7 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account2, account3, 99, Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -324,12 +324,12 @@ defmodule MultipleTransactionsTest do {:ok, tx} = Keys.sign_tx(account1_pub_key, 100, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) {:ok, tx} = Keys.sign_tx(account2_pub_key, 100, Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 2, 0, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) Miner.resume() Miner.suspend() @@ -337,12 +337,12 @@ defmodule MultipleTransactionsTest do tx = create_signed_tx(account1, account3, 99, Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) tx = create_signed_tx(account2, account3, 99, Map.get(Chain.chain_state, account2_pub_key, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) assert :ok = Pool.add_transaction(tx) miner_balance_before_mining = Map.get(Chain.chain_state, pubkey).balance Miner.resume() diff --git a/apps/aehttpclient/test/aehttpclient_test.exs b/apps/aehttpclient/test/aehttpclient_test.exs index 6f7aba30..7afae349 100644 --- a/apps/aehttpclient/test/aehttpclient_test.exs +++ b/apps/aehttpclient/test/aehttpclient_test.exs @@ -23,11 +23,11 @@ defmodule AehttpclientTest do {:ok, tx1} = Keys.sign_tx(to_account, 5, Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) {:ok, tx2} = Keys.sign_tx(to_account, 5, Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_block] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) Pool.add_transaction(tx1) Pool.add_transaction(tx2) end From 24658aadda7094ff23074057875cc83631e51a08 Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Mon, 11 Dec 2017 17:29:25 +0200 Subject: [PATCH 07/12] [GH-#125] Fixed Logger message --- apps/aecore/lib/aecore/chain/chain_state.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/aecore/lib/aecore/chain/chain_state.ex b/apps/aecore/lib/aecore/chain/chain_state.ex index b5483fee..7fed1d58 100644 --- a/apps/aecore/lib/aecore/chain/chain_state.ex +++ b/apps/aecore/lib/aecore/chain/chain_state.ex @@ -4,6 +4,8 @@ defmodule Aecore.Chain.ChainState do The chain state is a map, telling us what amount of tokens each account has. """ + require Logger + @doc """ Calculates the balance of each account mentioned in the transactions a single block, returns a map with the @@ -107,7 +109,7 @@ defmodule Aecore.Chain.ChainState do true -> Logger.error(fn -> "Update chain state locked: - new block height (#{new_block_height}) greater than lock time block (#{message})" + new block height (#{new_block_height}) greater than lock time block (#{lock_time_block})" end) {amount_update_value, updated_locked} From fd3d906e4aaf47f700e9e0de1bc473ad797230ae Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Mon, 11 Dec 2017 17:55:11 +0200 Subject: [PATCH 08/12] [GH-#125] Fixed test --- apps/aecore/test/aecore_txs_pool_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/aecore/test/aecore_txs_pool_test.exs b/apps/aecore/test/aecore_txs_pool_test.exs index b6638563..a6a9a04d 100644 --- a/apps/aecore/test/aecore_txs_pool_test.exs +++ b/apps/aecore/test/aecore_txs_pool_test.exs @@ -21,12 +21,12 @@ defmodule AecoreTxsPoolTest do Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 2) {:ok, tx2} = Keys.sign_tx(to_account, 5, Map.get(Chain.chain_state, to_account, %{nonce: 0}).nonce + 1, 1, Chain.latest_block().header.height + - Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 1) + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 2) Miner.resume() Miner.suspend() assert :ok = Pool.add_transaction(tx1) From 47756338454dc16de9bf5af4917c5a022a64d947 Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Fri, 15 Dec 2017 12:18:01 +0200 Subject: [PATCH 09/12] [GH-#125] Added exception when not substracting negative value in update_block_state --- apps/aecore/lib/aecore/chain/chain_state.ex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/aecore/lib/aecore/chain/chain_state.ex b/apps/aecore/lib/aecore/chain/chain_state.ex index 7fed1d58..3f01a136 100644 --- a/apps/aecore/lib/aecore/chain/chain_state.ex +++ b/apps/aecore/lib/aecore/chain/chain_state.ex @@ -148,6 +148,10 @@ defmodule Aecore.Chain.ChainState do new_locked = if(value > 0) do block_state_filled_empty[account].locked ++ [%{amount: value, block: lock_time_block}] else + if(!add_to_amount) do + throw({:error, "Update block state: not substracting negative value"}) + end + block_state_filled_empty[account].locked end From 6bfca9c855ff1aeb6c4c63b01ff693ade291b67a Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Mon, 18 Dec 2017 10:56:45 +0200 Subject: [PATCH 10/12] [GH-#125] Added default value for lock_time_block --- apps/aecore/lib/aecore/keys/worker.ex | 4 +++- apps/aecore/lib/aecore/structures/tx_data.ex | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/aecore/lib/aecore/keys/worker.ex b/apps/aecore/lib/aecore/keys/worker.ex index 505eb822..d3920996 100644 --- a/apps/aecore/lib/aecore/keys/worker.ex +++ b/apps/aecore/lib/aecore/keys/worker.ex @@ -6,6 +6,7 @@ defmodule Aecore.Keys.Worker do alias Aecore.Structures.TxData alias Aecore.Structures.SignedTx + alias Aecore.Chain.Worker, as: Chain @filename_pub "key.pub" @filename_priv "key" @@ -40,7 +41,8 @@ defmodule Aecore.Keys.Worker do """ @spec sign_tx(binary(), integer(), integer(), integer(), integer()) :: {:ok, %SignedTx{}} - def sign_tx(to_acc, value, nonce, fee, lock_time_block) do + def sign_tx(to_acc, value, nonce, fee, + lock_time_block \\ Chain.latest_block().header.height + 1) do {:ok, from_acc} = pubkey() {:ok, tx_data} = TxData.create(from_acc, to_acc, value, nonce, fee, lock_time_block) {:ok, signature} = sign(tx_data) diff --git a/apps/aecore/lib/aecore/structures/tx_data.ex b/apps/aecore/lib/aecore/structures/tx_data.ex index d0df7988..a6ed077b 100644 --- a/apps/aecore/lib/aecore/structures/tx_data.ex +++ b/apps/aecore/lib/aecore/structures/tx_data.ex @@ -4,6 +4,8 @@ defmodule Aecore.Structures.TxData do """ alias Aecore.Structures.TxData + alias Aecore.Chain.Worker, as: Chain + @type tx_data() :: %TxData{} @doc """ @@ -19,7 +21,9 @@ defmodule Aecore.Structures.TxData do use ExConstructor @spec create(binary(), binary(), integer(), integer(), integer(), integer()) :: {:ok, %TxData{}} - def create(from_acc, to_acc, value, nonce, fee, lock_time_block) do + def create(from_acc, to_acc, value, nonce, fee, + lock_time_block \\ Chain.latest_block().header.height + 1) do + {:ok, %TxData{from_acc: from_acc, to_acc: to_acc, value: value, From 920d71a5e56d27142acf08f623f122ba8fdb69ae Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Mon, 18 Dec 2017 14:16:14 +0200 Subject: [PATCH 11/12] [GH-#125] Set default value for lock_time_block as 0; lock time now works in all cases; added test for checking if locked amount is spendable --- apps/aecore/lib/aecore/chain/chain_state.ex | 25 +++++------ apps/aecore/lib/aecore/chain/worker.ex | 9 ++-- apps/aecore/lib/aecore/keys/worker.ex | 4 +- apps/aecore/lib/aecore/miner/worker.ex | 3 +- apps/aecore/lib/aecore/structures/tx_data.ex | 5 +-- apps/aecore/test/aecore_chain_state_test.exs | 3 +- apps/aecore/test/aecore_chain_test.exs | 3 +- .../test/multiple_transactions_test.exs | 44 ++++++++++++++++++- 8 files changed, 61 insertions(+), 35 deletions(-) diff --git a/apps/aecore/lib/aecore/chain/chain_state.ex b/apps/aecore/lib/aecore/chain/chain_state.ex index f1139038..fcffc9e2 100644 --- a/apps/aecore/lib/aecore/chain/chain_state.ex +++ b/apps/aecore/lib/aecore/chain/chain_state.ex @@ -11,8 +11,8 @@ defmodule Aecore.Chain.ChainState do in the transactions a single block, returns a map with the accounts as key and their balance as value. """ - @spec calculate_block_state(list(), integer(), integer()) :: map() - def calculate_block_state(txs, latest_block_height, lock_time_coinbase) do + @spec calculate_block_state(list(), integer()) :: map() + def calculate_block_state(txs, latest_block_height) do block_state = %{} block_state = @@ -22,17 +22,16 @@ defmodule Aecore.Chain.ChainState do transaction.data.from_acc != nil -> update_block_state(block_state, transaction.data.from_acc, -(transaction.data.value + transaction.data.fee), - transaction.data.nonce, transaction.data.lock_time_block, true) + transaction.data.nonce, transaction.data.lock_time_block, false) true -> block_state end - add_to_amount = latest_block_height + 1 != - transaction.data.lock_time_block - lock_time_coinbase + add_to_locked = latest_block_height + 1 <= transaction.data.lock_time_block update_block_state(updated_block_state, transaction.data.to_acc, transaction.data.value, - 0, transaction.data.lock_time_block, add_to_amount) + 0, transaction.data.lock_time_block, add_to_locked) end reduce_map_list(block_state) @@ -121,7 +120,7 @@ defmodule Aecore.Chain.ChainState do end @spec update_block_state(map(), binary(), integer(), integer(), integer(), boolean()) :: map() - defp update_block_state(block_state, account, value, nonce, lock_time_block, add_to_amount) do + defp update_block_state(block_state, account, value, nonce, lock_time_block, add_to_locked) do block_state_filled_empty = cond do !Map.has_key?(block_state, account) -> @@ -131,10 +130,10 @@ defmodule Aecore.Chain.ChainState do block_state end - new_balance = if(add_to_amount) do - block_state_filled_empty[account].balance + value - else + new_balance = if(add_to_locked) do block_state_filled_empty[account].balance + else + block_state_filled_empty[account].balance + value end new_nonce = cond do @@ -145,13 +144,9 @@ defmodule Aecore.Chain.ChainState do block_state_filled_empty[account].nonce end - new_locked = if(value > 0) do + new_locked = if(add_to_locked) do block_state_filled_empty[account].locked ++ [%{amount: value, block: lock_time_block}] else - if(!add_to_amount) do - throw({:error, "Update block state: not substracting negative value"}) - end - block_state_filled_empty[account].locked end diff --git a/apps/aecore/lib/aecore/chain/worker.ex b/apps/aecore/lib/aecore/chain/worker.ex index 093e63d7..f9e4d069 100644 --- a/apps/aecore/lib/aecore/chain/worker.ex +++ b/apps/aecore/lib/aecore/chain/worker.ex @@ -23,8 +23,7 @@ defmodule Aecore.Chain.Worker do genesis_block_hash = BlockValidation.block_header_hash(Block.genesis_block().header) genesis_block_map = %{genesis_block_hash => Block.genesis_block()} genesis_chain_state = - ChainState.calculate_block_state(Block.genesis_block().txs, Block.genesis_block().header.height, - Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) + ChainState.calculate_block_state(Block.genesis_block().txs, Block.genesis_block().header.height) latest_block_chain_state = %{genesis_block_hash => genesis_chain_state} txs_index = calculate_block_acc_txs_info(Block.genesis_block()) @@ -73,8 +72,7 @@ defmodule Aecore.Chain.Worker do prev_block_chain_state = chain_state() new_block_state = - ChainState.calculate_block_state(block.txs, latest_block.header.height, - Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) + ChainState.calculate_block_state(block.txs, latest_block.header.height) new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) new_chain_state_locked_amounts = ChainState.update_chain_state_locked(new_chain_state, latest_block.header.height + 1) @@ -164,8 +162,7 @@ defmodule Aecore.Chain.Worker do prev_block_chain_state = latest_block_chain_state[block.header.prev_hash] latest_block = block_map[block.header.prev_hash] new_block_state = - ChainState.calculate_block_state(block.txs, latest_block.header.height, - Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) + ChainState.calculate_block_state(block.txs, latest_block.header.height) new_chain_state = ChainState.calculate_chain_state(new_block_state, prev_block_chain_state) new_chain_state_locked_amounts = ChainState.update_chain_state_locked(new_chain_state, block.header.height) diff --git a/apps/aecore/lib/aecore/keys/worker.ex b/apps/aecore/lib/aecore/keys/worker.ex index d3920996..8cfdfdc9 100644 --- a/apps/aecore/lib/aecore/keys/worker.ex +++ b/apps/aecore/lib/aecore/keys/worker.ex @@ -6,7 +6,6 @@ defmodule Aecore.Keys.Worker do alias Aecore.Structures.TxData alias Aecore.Structures.SignedTx - alias Aecore.Chain.Worker, as: Chain @filename_pub "key.pub" @filename_priv "key" @@ -41,8 +40,7 @@ defmodule Aecore.Keys.Worker do """ @spec sign_tx(binary(), integer(), integer(), integer(), integer()) :: {:ok, %SignedTx{}} - def sign_tx(to_acc, value, nonce, fee, - lock_time_block \\ Chain.latest_block().header.height + 1) do + def sign_tx(to_acc, value, nonce, fee, lock_time_block \\ 0) do {:ok, from_acc} = pubkey() {:ok, tx_data} = TxData.create(from_acc, to_acc, value, nonce, fee, lock_time_block) {:ok, signature} = sign(tx_data) diff --git a/apps/aecore/lib/aecore/miner/worker.ex b/apps/aecore/lib/aecore/miner/worker.ex index e6ada412..9eb18421 100644 --- a/apps/aecore/lib/aecore/miner/worker.ex +++ b/apps/aecore/lib/aecore/miner/worker.ex @@ -179,8 +179,7 @@ defmodule Aecore.Miner.Worker do root_hash = BlockValidation.calculate_root_hash(valid_txs) new_block_state = - ChainState.calculate_block_state(valid_txs, latest_block.header.height, - Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) + ChainState.calculate_block_state(valid_txs, latest_block.header.height) new_chain_state = ChainState.calculate_chain_state(new_block_state, chain_state) new_chain_state_locked_amounts = ChainState.update_chain_state_locked(new_chain_state, latest_block.header.height + 1) diff --git a/apps/aecore/lib/aecore/structures/tx_data.ex b/apps/aecore/lib/aecore/structures/tx_data.ex index a6ed077b..a30cdbd3 100644 --- a/apps/aecore/lib/aecore/structures/tx_data.ex +++ b/apps/aecore/lib/aecore/structures/tx_data.ex @@ -4,7 +4,6 @@ defmodule Aecore.Structures.TxData do """ alias Aecore.Structures.TxData - alias Aecore.Chain.Worker, as: Chain @type tx_data() :: %TxData{} @@ -21,9 +20,7 @@ defmodule Aecore.Structures.TxData do use ExConstructor @spec create(binary(), binary(), integer(), integer(), integer(), integer()) :: {:ok, %TxData{}} - def create(from_acc, to_acc, value, nonce, fee, - lock_time_block \\ Chain.latest_block().header.height + 1) do - + def create(from_acc, to_acc, value, nonce, fee, lock_time_block \\ 0) do {:ok, %TxData{from_acc: from_acc, to_acc: to_acc, value: value, diff --git a/apps/aecore/test/aecore_chain_state_test.exs b/apps/aecore/test/aecore_chain_state_test.exs index bd7e7e4f..795b5144 100644 --- a/apps/aecore/test/aecore_chain_state_test.exs +++ b/apps/aecore/test/aecore_chain_state_test.exs @@ -24,8 +24,7 @@ defmodule AecoreChainStateTest do %{amount: 5, block: lock_time_block}]}, "c" => %{nonce: 1, balance: -5, locked: [%{amount: 2, block: lock_time_block}]}} == - ChainState.calculate_block_state(block.txs, latest_block.header.height, - Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) + ChainState.calculate_block_state(block.txs, latest_block.header.height) end test "chain state" do diff --git a/apps/aecore/test/aecore_chain_test.exs b/apps/aecore/test/aecore_chain_test.exs index 11ab2920..8584fb11 100644 --- a/apps/aecore/test/aecore_chain_test.exs +++ b/apps/aecore/test/aecore_chain_test.exs @@ -28,8 +28,7 @@ defmodule AecoreChainTest do chain_state = Chain.chain_state(latest_block_hash) new_block_state = - ChainState.calculate_block_state([], latest_block.header.height, - Application.get_env(:aecore, :tx_data)[:lock_time_coinbase]) + ChainState.calculate_block_state([], latest_block.header.height) new_chain_state = ChainState.calculate_chain_state(new_block_state, chain_state) new_chain_state_hash = ChainState.calculate_chain_state_hash(new_chain_state) diff --git a/apps/aecore/test/multiple_transactions_test.exs b/apps/aecore/test/multiple_transactions_test.exs index 4ee9c8c4..07ad31b0 100644 --- a/apps/aecore/test/multiple_transactions_test.exs +++ b/apps/aecore/test/multiple_transactions_test.exs @@ -352,6 +352,39 @@ defmodule MultipleTransactionsTest do assert miner_balance_after_mining == miner_balance_before_mining + Miner.coinbase_transaction_value() + 2 end + test "locked amount" do + {:ok, pubkey} = Keys.pubkey() + account1 = get_account_locked_amount() + {account1_pub_key, _account1_priv_key} = account1 + + Miner.resume() + Miner.suspend() + Pool.get_and_empty_pool() + {:ok, tx} = Keys.sign_tx(account1_pub_key, 90, + Map.get(Chain.chain_state, pubkey, %{nonce: 0}).nonce + 1, 10, + Chain.latest_block().header.height + + Application.get_env(:aecore, :tx_data)[:lock_time_coinbase] + 3) + Pool.add_transaction(tx) + Miner.resume() + Miner.suspend() + tx = create_signed_tx(account1, {pubkey, <<0>>}, 50, + Map.get(Chain.chain_state, account1_pub_key, %{nonce: 0}).nonce + 1, 10) + Pool.add_transaction(tx) + Miner.resume() + Miner.suspend() + assert Enum.count(Pool.get_pool()) == 1 + Miner.resume() + Miner.suspend() + assert Enum.count(Pool.get_pool()) == 1 + assert Map.get(Chain.chain_state, account1_pub_key).balance == 90 + miner_balance_before_block = Map.get(Chain.chain_state, pubkey).balance + Miner.resume() + Miner.suspend() + assert Enum.count(Pool.get_pool()) == 0 + miner_balance_after_block = Map.get(Chain.chain_state, pubkey).balance + assert miner_balance_after_block == miner_balance_before_block + 100 + 60 + end + defp get_accounts_one_block() do account1 = { <<4, 94, 96, 161, 182, 76, 153, 22, 179, 136, 60, 87, 225, 135, 253, 179, 80, @@ -439,7 +472,16 @@ defmodule MultipleTransactionsTest do {account1, account2, account3} end - defp create_signed_tx(from_acc, to_acc, value, nonce, fee, lock_time_block) do + defp get_account_locked_amount() do + {<<4, 55, 160, 38, 64, 182, 216, 237, 37, 115, 115, 235, 25, 35, 106, 13, 194, + 87, 156, 61, 156, 235, 207, 151, 183, 35, 38, 247, 66, 253, 39, 197, 43, 49, + 55, 78, 125, 31, 45, 38, 203, 156, 1, 206, 235, 241, 50, 140, 195, 38, 19, + 89, 234, 69, 251, 211, 208, 29, 72, 99, 90, 90, 212, 128, 105>>, + <<132, 73, 10, 38, 77, 68, 7, 72, 211, 181, 33, 176, 209, 113, 210, 159, 247, + 148, 237, 83, 238, 200, 99, 252, 175, 107, 11, 95, 114, 133, 149, 168>>} + end + + defp create_signed_tx(from_acc, to_acc, value, nonce, fee, lock_time_block \\ 0) do {from_acc_pub_key, from_acc_priv_key} = from_acc {to_acc_pub_key, _to_acc_priv_key} = to_acc {:ok, tx_data} = TxData.create(from_acc_pub_key, to_acc_pub_key, value, From e136659e97e603f656e220a655246598bc69606c Mon Sep 17 00:00:00 2001 From: cheezus1 Date: Mon, 18 Dec 2017 14:29:57 +0200 Subject: [PATCH 12/12] [GH-#125] Fixed travis error --- apps/aecore/test/multiple_transactions_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/aecore/test/multiple_transactions_test.exs b/apps/aecore/test/multiple_transactions_test.exs index 07ad31b0..4655f739 100644 --- a/apps/aecore/test/multiple_transactions_test.exs +++ b/apps/aecore/test/multiple_transactions_test.exs @@ -380,7 +380,7 @@ defmodule MultipleTransactionsTest do miner_balance_before_block = Map.get(Chain.chain_state, pubkey).balance Miner.resume() Miner.suspend() - assert Enum.count(Pool.get_pool()) == 0 + assert Enum.empty?(Pool.get_pool()) miner_balance_after_block = Map.get(Chain.chain_state, pubkey).balance assert miner_balance_after_block == miner_balance_before_block + 100 + 60 end