diff --git a/lib/archethic/account/mem_tables_loader.ex b/lib/archethic/account/mem_tables_loader.ex index eacb93c0f..53c75fedf 100644 --- a/lib/archethic/account/mem_tables_loader.ex +++ b/lib/archethic/account/mem_tables_loader.ex @@ -8,14 +8,10 @@ defmodule ArchEthic.Account.MemTablesLoader do alias ArchEthic.Crypto - alias ArchEthic.P2P - alias ArchEthic.P2P.Node - alias ArchEthic.TransactionChain alias ArchEthic.TransactionChain.Transaction alias ArchEthic.TransactionChain.Transaction.ValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.TransactionMovement @@ -29,7 +25,7 @@ defmodule ArchEthic.Account.MemTablesLoader do :previous_public_key, validation_stamp: [ :timestamp, - ledger_operations: [:node_movements, :unspent_outputs, :transaction_movements] + ledger_operations: [:unspent_outputs, :transaction_movements] ] ] @@ -69,7 +65,6 @@ defmodule ArchEthic.Account.MemTablesLoader do timestamp: timestamp, ledger_operations: %LedgerOperations{ unspent_outputs: unspent_outputs, - node_movements: node_movements, transaction_movements: transaction_movements } } @@ -81,7 +76,6 @@ defmodule ArchEthic.Account.MemTablesLoader do :ok = set_transaction_movements(address, transaction_movements, timestamp) :ok = set_unspent_outputs(address, unspent_outputs, timestamp) - :ok = set_node_rewards(address, node_movements, timestamp) Logger.info("Loaded into in memory account tables", transaction_address: Base.encode16(address), @@ -125,18 +119,4 @@ defmodule ArchEthic.Account.MemTablesLoader do NFTLedger.add_unspent_output(address, unspent_output, timestamp) end) end - - defp set_node_rewards(address, node_movements, timestamp) do - node_movements - |> Enum.filter(&(&1.amount > 0)) - |> Enum.each(fn %NodeMovement{to: to, amount: amount} -> - %Node{reward_address: reward_address} = P2P.get_node_info!(to) - - UCOLedger.add_unspent_output( - reward_address, - %UnspentOutput{amount: amount, from: address, type: :UCO, reward?: true}, - timestamp - ) - end) - end end diff --git a/lib/archethic/beacon_chain/replication_attestation.ex b/lib/archethic/beacon_chain/replication_attestation.ex index ff0e33501..183a56420 100644 --- a/lib/archethic/beacon_chain/replication_attestation.ex +++ b/lib/archethic/beacon_chain/replication_attestation.ex @@ -30,7 +30,8 @@ defmodule ArchEthic.BeaconChain.ReplicationAttestation do ...> address: <<0, 0, 232, 183, 247, 15, 195, 209, 138, 58, 226, 218, 221, 135, 181, 43, 216, 164, 4, 187, 38, ...> 200, 170, 241, 23, 249, 75, 17, 23, 241, 185, 36, 15, 66>>, ...> type: :transfer, - ...> timestamp: ~U[2022-01-27 09:14:22Z] + ...> timestamp: ~U[2022-01-27 09:14:22Z], + ...> fee: 10_000_000 ...> }, ...> confirmations: [ ...> { @@ -52,6 +53,8 @@ defmodule ArchEthic.BeaconChain.ReplicationAttestation do 0, 0, 1, 126, 154, 208, 125, 176, # Transaction type 253, + # Fee + 0, 0, 0, 0, 0, 152, 150, 128, # Nb movements 0, 0, # Nb confirmations @@ -92,7 +95,7 @@ defmodule ArchEthic.BeaconChain.ReplicationAttestation do iex> <<1, 0, 0, 232, 183, 247, 15, 195, 209, 138, 58, 226, 218, 221, 135, 181, 43, 216, ...> 164, 4, 187, 38, 200, 170, 241, 23, 249, 75, 17, 23, 241, 185, 36, 15, 66, ...> 0, 0, 1, 126, 154, 208, 125, 176, - ...> 253,0, 0, + ...> 253, 0, 0, 0, 0, 0, 152, 150, 128, 0, 0, ...> 1, 0,64, ...> 129, 204, 107, 81, 235, 88, 234, 207, 125, 1, 208, 227, 239, 175, 78, 217, ...> 100, 172, 67, 228, 131, 42, 177, 200, 54, 225, 34, 241, 35, 226, 108, 138, @@ -106,7 +109,8 @@ defmodule ArchEthic.BeaconChain.ReplicationAttestation do address: <<0, 0, 232, 183, 247, 15, 195, 209, 138, 58, 226, 218, 221, 135, 181, 43, 216, 164, 4, 187, 38, 200, 170, 241, 23, 249, 75, 17, 23, 241, 185, 36, 15, 66>>, type: :transfer, - timestamp: ~U[2022-01-27 09:14:22.000Z] + timestamp: ~U[2022-01-27 09:14:22.000Z], + fee: 10_000_000 }, confirmations: [ { diff --git a/lib/archethic/beacon_chain/slot.ex b/lib/archethic/beacon_chain/slot.ex index 6aad08276..ad59d7062 100644 --- a/lib/archethic/beacon_chain/slot.ex +++ b/lib/archethic/beacon_chain/slot.ex @@ -69,6 +69,7 @@ defmodule ArchEthic.BeaconChain.Slot do ...> <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>> ...> ], + ...> fee: 10_000_000 ...> }, ...> confirmations: [{0, <<185, 37, 172, 79, 189, 197, 94, 202, 41, 160, 222, 127, 227, 180, 133, 62, 76, ...> 29, 230, 10, 100, 79, 47, 49, 139, 117, 0, 64, 89, 229, 228, 214, 6, 49, 119, @@ -86,7 +87,8 @@ defmodule ArchEthic.BeaconChain.Slot do movements_addresses: [ <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>> - ] + ], + fee: 10_000_000 }, confirmations: [ { @@ -113,7 +115,8 @@ defmodule ArchEthic.BeaconChain.Slot do ...> movements_addresses: [ ...> <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>> - ...> ] + ...> ], + ...> fee: 10_000_000 ...> }, ...> confirmations: [{0, <<185, 37, 172, 79, 189, 197, 94, 202, 41, 160, 222, 127, 227, 180, 133, 62, 76, ...> 29, 230, 10, 100, 79, 47, 49, 139, 117, 0, 64, 89, 229, 228, 214, 6, 49, 119, @@ -132,6 +135,7 @@ defmodule ArchEthic.BeaconChain.Slot do ...> <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>> ...> ], + ...> fee: 10_000_000 ...> }, ...> confirmations: [{1, <<89, 98, 246, 6, 202, 116, 247, 88, 69, 148, 188, 173, 34, 0, 194, 108, 169, ...> 155, 63, 197, 200, 6, 31, 148, 57, 152, 195, 154, 181, 14, 77, 9, 161, 38, @@ -149,7 +153,8 @@ defmodule ArchEthic.BeaconChain.Slot do movements_addresses: [ <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>> - ] + ], + fee: 10_000_000 }, confirmations: [ { @@ -292,7 +297,8 @@ defmodule ArchEthic.BeaconChain.Slot do ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>>, ...> timestamp: ~U[2020-06-25 15:11:53Z], ...> type: :transfer, - ...> movements_addresses: [] + ...> movements_addresses: [], + ...> fee: 10_000_000 ...> }, ...> confirmations: [{0, <<129, 204, 107, 81, 235, 88, 234, 207, 125, 1, 208, 227, 239, 175, 78, 217, ...> 100, 172, 67, 228, 131, 42, 177, 200, 54, 225, 34, 241, 35, 226, 108, 138, @@ -332,6 +338,8 @@ defmodule ArchEthic.BeaconChain.Slot do 0, 0, 1, 114, 236, 9, 2, 168, # Type (transfer) 253, + # Fee + 0, 0, 0, 0, 0, 152, 150, 128, # Nb movements addresses 0, 0, # Nb confirmations @@ -409,7 +417,7 @@ defmodule ArchEthic.BeaconChain.Slot do iex> <<1, 0, 96, 8, 1, 120, 0, 0, 0, 1, ...> 1, 0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12, - ...> 0, 0, 1, 114, 236, 9, 2, 168, 253, 0, 0, + ...> 0, 0, 1, 114, 236, 9, 2, 168, 253, 0, 0, 0, 0, 0, 152, 150, 128, 0, 0, ...> 1, 0, 64, 129, 204, 107, 81, 235, 88, 234, 207, 125, 1, 208, 227, 239, 175, 78, 217, ...> 100, 172, 67, 228, 131, 42, 177, 200, 54, 225, 34, 241, 35, 226, 108, 138, ...> 201, 2, 32, 75, 92, 49, 194, 42, 113, 154, 20, 43, 216, 176, 11, 159, 188, @@ -431,7 +439,8 @@ defmodule ArchEthic.BeaconChain.Slot do 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>>, timestamp: ~U[2020-06-25 15:11:53.000Z], type: :transfer, - movements_addresses: [] + movements_addresses: [], + fee: 10_000_000 }, confirmations: [{0, <<129, 204, 107, 81, 235, 88, 234, 207, 125, 1, 208, 227, 239, 175, 78, 217, 100, 172, 67, 228, 131, 42, 177, 200, 54, 225, 34, 241, 35, 226, 108, 138, diff --git a/lib/archethic/beacon_chain/summary.ex b/lib/archethic/beacon_chain/summary.ex index 418fc65f1..df91d74a0 100644 --- a/lib/archethic/beacon_chain/summary.ex +++ b/lib/archethic/beacon_chain/summary.ex @@ -61,7 +61,8 @@ defmodule ArchEthic.BeaconChain.Summary do ...> address: <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>>, ...> type: :transfer, - ...> timestamp: ~U[2020-06-25 15:11:53Z] + ...> timestamp: ~U[2020-06-25 15:11:53Z], + ...> fee: 10_000_000 ...> } ...> } ...> ], @@ -82,7 +83,8 @@ defmodule ArchEthic.BeaconChain.Summary do address: <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>>, type: :transfer, - timestamp: ~U[2020-06-25 15:11:53Z] + timestamp: ~U[2020-06-25 15:11:53Z], + fee: 10_000_000 } } ], @@ -101,7 +103,8 @@ defmodule ArchEthic.BeaconChain.Summary do ...> address: <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>>, ...> type: :transfer, - ...> timestamp: ~U[2020-06-25 15:11:53Z] + ...> timestamp: ~U[2020-06-25 15:11:53Z], + ...> fee: 10_000_000 ...> } ...> } ...> ], @@ -123,7 +126,8 @@ defmodule ArchEthic.BeaconChain.Summary do address: <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>>, type: :transfer, - timestamp: ~U[2020-06-25 15:11:53Z] + timestamp: ~U[2020-06-25 15:11:53Z], + fee: 10_000_000 } } ], @@ -266,7 +270,8 @@ defmodule ArchEthic.BeaconChain.Summary do ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>>, ...> timestamp: ~U[2020-06-25 15:11:53Z], ...> type: :transfer, - ...> movements_addresses: [] + ...> movements_addresses: [], + ...> fee: 10_000_000 ...> }, ...> confirmations: [{0, <<255, 120, 232, 52, 141, 15, 97, 213, 231, 93, 242, 160, 123, 25, 192, 3, 133, ...> 170, 197, 102, 148, 208, 119, 130, 225, 102, 130, 96, 223, 61, 36, 76, 229, @@ -296,6 +301,8 @@ defmodule ArchEthic.BeaconChain.Summary do 0, 0, 1, 114, 236, 9, 2, 168, # Type (transfer) 253, + # Fee + 0, 0, 0, 0, 0, 152, 150, 128, # Nb movement addresses 0, 0, # Nb confirmations @@ -352,7 +359,7 @@ defmodule ArchEthic.BeaconChain.Summary do iex> <<1, 0, 96, 7, 114, 128, 0, 0, 0, 1, 1, 0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12, - ...> 0, 0, 1, 114, 236, 9, 2, 168, 253, 0, 0, + ...> 0, 0, 1, 114, 236, 9, 2, 168, 253, 0, 0, 0, 0, 0, 152, 150, 128, 0, 0, ...> 1, 0, 64, 255, 120, 232, 52, 141, 15, 97, 213, 231, 93, 242, 160, 123, 25, 192, 3, 133, ...> 170, 197, 102, 148, 208, 119, 130, 225, 102, 130, 96, 223, 61, 36, 76, 229, ...> 210, 5, 142, 79, 249, 177, 51, 15, 45, 45, 141, 217, 85, 77, 146, 199, 126, @@ -370,7 +377,8 @@ defmodule ArchEthic.BeaconChain.Summary do 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>>, timestamp: ~U[2020-06-25 15:11:53.000Z], type: :transfer, - movements_addresses: [] + movements_addresses: [], + fee: 10_000_000 }, confirmations: [{0, <<255, 120, 232, 52, 141, 15, 97, 213, 231, 93, 242, 160, 123, 25, 192, 3, 133, 170, 197, 102, 148, 208, 119, 130, 225, 102, 130, 96, 223, 61, 36, 76, 229, diff --git a/lib/archethic/bootstrap/network_init.ex b/lib/archethic/bootstrap/network_init.ex index 37e2febb8..5dd472db8 100644 --- a/lib/archethic/bootstrap/network_init.ex +++ b/lib/archethic/bootstrap/network_init.ex @@ -16,7 +16,6 @@ defmodule ArchEthic.Bootstrap.NetworkInit do alias ArchEthic.Mining alias ArchEthic.PubSub - alias ArchEthic.P2P.Node alias ArchEthic.Replication @@ -133,11 +132,6 @@ defmodule ArchEthic.Bootstrap.NetworkInit do transaction_movements: Transaction.get_movements(tx) } |> LedgerOperations.from_transaction(tx) - |> LedgerOperations.distribute_rewards( - %Node{last_public_key: Crypto.last_node_public_key()}, - [%Node{last_public_key: Crypto.last_node_public_key()}], - [] - ) |> LedgerOperations.consume_inputs(tx.address, unspent_outputs) validation_stamp = diff --git a/lib/archethic/mining.ex b/lib/archethic/mining.ex index 3b6968caf..32f96deb8 100644 --- a/lib/archethic/mining.ex +++ b/lib/archethic/mining.ex @@ -18,7 +18,6 @@ defmodule ArchEthic.Mining do alias ArchEthic.P2P.Node alias ArchEthic.SelfRepair - alias ArchEthic.SharedSecrets alias ArchEthic.TransactionChain.Transaction alias ArchEthic.TransactionChain.Transaction.CrossValidationStamp @@ -102,45 +101,6 @@ defmodule ArchEthic.Mining do validation_node_public_keys == Enum.map(validation_nodes, & &1.last_public_key) end - def valid_election?( - tx = %Transaction{ - address: tx_address, - type: tx_type, - validation_stamp: %ValidationStamp{timestamp: timestamp, proof_of_election: poe} - }, - validation_node_public_keys - ) - when is_list(validation_node_public_keys) do - daily_nonce_public_key = SharedSecrets.get_daily_nonce_public_key(timestamp) - - if daily_nonce_public_key == SharedSecrets.genesis_daily_nonce_public_key() do - # Should happens only during the network bootstrapping - true - else - node_list = transaction_validation_node_list(tx_type, timestamp) - storage_nodes = Election.chain_storage_nodes_with_type(tx_address, tx_type, node_list) - - constraints = Election.get_validation_constraints() - - with true <- - Election.valid_proof_of_election?(tx, poe, daily_nonce_public_key), - nodes = [_ | _] <- - Election.validation_nodes( - tx, - poe, - node_list, - storage_nodes, - constraints - ), - set_of_validation_node_public_keys <- Enum.map(nodes, & &1.last_public_key) do - Enum.all?(validation_node_public_keys, &(&1 in set_of_validation_node_public_keys)) - else - _ -> - false - end - end - end - @doc """ Add transaction mining context which built by another cross validation node """ diff --git a/lib/archethic/mining/validation_context.ex b/lib/archethic/mining/validation_context.ex index ce954fce0..589c094ca 100644 --- a/lib/archethic/mining/validation_context.ex +++ b/lib/archethic/mining/validation_context.ex @@ -699,15 +699,11 @@ defmodule ArchEthic.Mining.ValidationContext do transaction: tx, previous_transaction: prev_tx, unspent_outputs: unspent_outputs, - coordinator_node: coordinator_node, - previous_storage_nodes: previous_storage_nodes, valid_pending_transaction?: valid_pending_transaction? } ) do initial_error = if valid_pending_transaction?, do: nil, else: :pending_transaction - confirmed_cross_validation_nodes = get_confirmed_validation_nodes(context) - validation_stamp = %ValidationStamp{ timestamp: DateTime.utc_now(), @@ -728,11 +724,6 @@ defmodule ArchEthic.Mining.ValidationContext do ) } |> LedgerOperations.from_transaction(tx) - |> LedgerOperations.distribute_rewards( - coordinator_node, - confirmed_cross_validation_nodes, - previous_storage_nodes - ) |> LedgerOperations.consume_inputs(tx.address, unspent_outputs), recipients: resolve_transaction_recipients(tx), errors: [initial_error, chain_error(prev_tx, tx)] |> Enum.filter(& &1) @@ -907,7 +898,6 @@ defmodule ArchEthic.Mining.ValidationContext do transaction_fee: fn -> valid_stamp_fee?(stamp, context) end, transaction_movements: fn -> valid_stamp_transaction_movements?(stamp, context) end, recipients: fn -> valid_stamp_recipients?(stamp, context) end, - node_movements: fn -> valid_stamp_node_movements?(stamp, context) end, unspent_outputs: fn -> valid_stamp_unspent_outputs?(stamp, context) end, errors: fn -> valid_stamp_errors?(stamp, context) end ] @@ -1011,70 +1001,6 @@ defmodule ArchEthic.Mining.ValidationContext do expected_unspent_outputs == next_unspent_outputs end - defp valid_stamp_node_movements?( - %ValidationStamp{ledger_operations: ops}, - context = %__MODULE__{ - transaction: tx, - coordinator_node: %Node{last_public_key: coordinator_node_public_key}, - unspent_outputs: unspent_outputs - } - ) do - previous_storage_nodes = - P2P.distinct_nodes([unspent_storage_nodes(unspent_outputs), previous_storage_nodes(tx)]) - - cross_validation_nodes = get_confirmed_validation_nodes(context) - - [ - fn -> LedgerOperations.valid_node_movements_roles?(ops) end, - fn -> - LedgerOperations.valid_node_movements_cross_validation_nodes?( - ops, - Enum.map(cross_validation_nodes, & &1.last_public_key) - ) - end, - fn -> - LedgerOperations.valid_node_movements_previous_storage_nodes?( - ops, - Enum.map(previous_storage_nodes, & &1.last_public_key) - ) - end, - fn -> LedgerOperations.valid_reward_distribution?(ops) end, - fn -> - LedgerOperations.has_node_movement_with_role?( - ops, - coordinator_node_public_key, - :coordinator_node - ) - end, - fn -> - Enum.all?( - cross_validation_nodes, - &LedgerOperations.has_node_movement_with_role?( - ops, - &1.last_public_key, - :cross_validation_node - ) - ) - end - ] - |> Task.async_stream(& &1.(), ordered: false) - |> Enum.all?(&match?({:ok, true}, &1)) - end - - defp unspent_storage_nodes([]), do: [] - - defp unspent_storage_nodes(unspent_outputs) do - unspent_outputs - |> Stream.map(&Election.chain_storage_nodes(&1.from, P2P.available_nodes())) - |> Enum.to_list() - end - - defp previous_storage_nodes(tx) do - tx - |> Transaction.previous_address() - |> Election.chain_storage_nodes(P2P.available_nodes()) - end - @doc """ Get the chain storage node position """ diff --git a/lib/archethic/p2p/message.ex b/lib/archethic/p2p/message.ex index ccfcab3ae..a4aa38ae9 100644 --- a/lib/archethic/p2p/message.ex +++ b/lib/archethic/p2p/message.ex @@ -1191,18 +1191,11 @@ defmodule ArchEthic.P2P.Message do end def process(%GetTransactionSummary{address: address}) do - case TransactionChain.get_transaction(address, [ - :address, - :type, - validation_stamp: [ - :timestamp, - ledger_operations: [:node_movements, :transaction_movements] - ] - ]) do - {:ok, tx} -> - TransactionSummary.from_transaction(tx) + case TransactionChain.get_transaction_summary(address) do + {:ok, summary} -> + summary - _ -> + {:error, :not_found} -> %NotFound{} end end diff --git a/lib/archethic/replication/transaction_validator.ex b/lib/archethic/replication/transaction_validator.ex index be29237dc..2466053ee 100644 --- a/lib/archethic/replication/transaction_validator.ex +++ b/lib/archethic/replication/transaction_validator.ex @@ -2,6 +2,7 @@ defmodule ArchEthic.Replication.TransactionValidator do @moduledoc false alias ArchEthic.Bootstrap + alias ArchEthic.Contracts alias ArchEthic.Election @@ -19,7 +20,6 @@ defmodule ArchEthic.Replication.TransactionValidator do alias ArchEthic.TransactionChain.Transaction.CrossValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.UnspentOutput alias ArchEthic.TransactionChain.TransactionInput @@ -30,18 +30,12 @@ defmodule ArchEthic.Replication.TransactionValidator do """ @type error :: :invalid_atomic_commitment - | :invalid_cross_validation_stamp_signatures - | :invalid_transaction_with_inconsistencies | :invalid_node_election | :invalid_proof_of_work | :invalid_proof_of_election | :invalid_validation_stamp_signature | :invalid_transaction_fee | :invalid_transaction_movements - | :invalid_node_movements_roles - | :invalid_cross_validation_nodes_movements - | :invalid_reward_distribution - | :invalid_previous_storage_nodes_movements | :insufficient_funds | :invalid_unspent_outputs | :invalid_chain @@ -100,8 +94,7 @@ defmodule ArchEthic.Replication.TransactionValidator do defp valid_transaction(tx = %Transaction{}, previous_inputs_unspent_outputs, chain_node?) when is_list(previous_inputs_unspent_outputs) do with :ok <- validate_consensus(tx), - :ok <- validate_validation_stamp(tx), - :ok <- validate_node_election(tx) do + :ok <- validate_validation_stamp(tx) do if chain_node? do check_unspent_outputs(tx, previous_inputs_unspent_outputs) else @@ -116,12 +109,10 @@ defmodule ArchEthic.Replication.TransactionValidator do defp validate_consensus( tx = %Transaction{ - validation_stamp: validation_stamp = %ValidationStamp{}, cross_validation_stamps: cross_stamps } ) do - with :ok <- validate_atomic_commitment(tx), - :ok <- validate_cross_validation_stamps_signatures(cross_stamps, validation_stamp) do + with :ok <- validate_atomic_commitment(tx) do validate_cross_validation_stamps_inconsistencies(cross_stamps) end end @@ -134,14 +125,6 @@ defmodule ArchEthic.Replication.TransactionValidator do end end - defp validate_cross_validation_stamps_signatures(stamps, validation_stamp) do - if Enum.all?(stamps, &CrossValidationStamp.valid_signature?(&1, validation_stamp)) do - :ok - else - {:error, :invalid_cross_validation_stamp_signatures} - end - end - defp validate_cross_validation_stamps_inconsistencies(stamps) do if Enum.all?(stamps, &(&1.inconsistencies == [])) do :ok @@ -151,15 +134,12 @@ defmodule ArchEthic.Replication.TransactionValidator do end end - defp validate_validation_stamp( - tx = %Transaction{validation_stamp: validation_stamp = %ValidationStamp{}} - ) do + defp validate_validation_stamp(tx = %Transaction{}) do with :ok <- validate_proof_of_work(tx), :ok <- validate_proof_of_election(tx), - :ok <- validate_stamp_signature(validation_stamp), + :ok <- validate_node_election(tx), :ok <- validate_transaction_fee(tx), - :ok <- validate_transaction_movements(tx), - :ok <- validate_node_movements(tx) do + :ok <- validate_transaction_movements(tx) do validate_no_additional_errors(tx) end end @@ -203,18 +183,63 @@ defmodule ArchEthic.Replication.TransactionValidator do end end - defp validate_stamp_signature( - validation_stamp = %ValidationStamp{ - ledger_operations: %LedgerOperations{node_movements: node_movements} - } - ) do - coordinator_node_public_key = - get_coordinator_node_public_key_from_node_movements(node_movements) - - if ValidationStamp.valid_signature?(validation_stamp, coordinator_node_public_key) do + defp validate_node_election(tx = %Transaction{}) do + if valid_election?(tx) do :ok else - {:error, :invalid_validation_stamp_signature} + {:error, :invalid_node_election} + end + end + + defp valid_election?( + tx = %Transaction{ + address: tx_address, + type: tx_type, + validation_stamp: + validation_stamp = %ValidationStamp{ + timestamp: tx_timestamp, + proof_of_election: proof_of_election + }, + cross_validation_stamps: cross_validation_stamps + } + ) do + authorized_nodes = Mining.transaction_validation_node_list(tx_type, tx_timestamp) + daily_nonce_public_key = SharedSecrets.get_daily_nonce_public_key(tx_timestamp) + + case authorized_nodes do + [] -> + # Should happens only during the network bootstrapping + daily_nonce_public_key == SharedSecrets.genesis_daily_nonce_public_key() + + _ -> + storage_nodes = + Election.chain_storage_nodes_with_type(tx_address, tx_type, P2P.available_nodes()) + + validation_nodes = + Election.validation_nodes( + tx, + proof_of_election, + authorized_nodes, + storage_nodes, + Election.get_validation_constraints() + ) + + valid_coordinator? = + Enum.any?( + validation_nodes, + &ValidationStamp.valid_signature?(validation_stamp, &1.last_public_key) + ) + + valid_cross_validators? = + Enum.all?( + cross_validation_stamps, + fn cross_stamp = %CrossValidationStamp{node_public_key: node_public_key} -> + Enum.any?(validation_nodes, &(&1.last_public_key == node_public_key)) and + CrossValidationStamp.valid_signature?(cross_stamp, validation_stamp) + end + ) + + valid_coordinator? and valid_cross_validators? end end @@ -275,48 +300,6 @@ defmodule ArchEthic.Replication.TransactionValidator do end end - defp validate_node_movements(%Transaction{ - validation_stamp: %ValidationStamp{ledger_operations: ops}, - cross_validation_stamps: cross_stamps - }) do - with :ok <- validate_node_movements_roles(ops), - :ok <- validate_node_movements_cross_validation_nodes(ops, cross_stamps) do - validate_valid_reward_distribution(ops) - end - end - - defp validate_node_movements_roles(ops = %LedgerOperations{}) do - if LedgerOperations.valid_node_movements_roles?(ops) do - :ok - else - {:error, :invalid_node_movements_roles} - end - end - - defp validate_node_movements_cross_validation_nodes( - ops = %LedgerOperations{}, - cross_validation_stamps - ) do - cross_validation_node_public_keys = Enum.map(cross_validation_stamps, & &1.node_public_key) - - if LedgerOperations.valid_node_movements_cross_validation_nodes?( - ops, - cross_validation_node_public_keys - ) do - :ok - else - {:error, :invalid_cross_validation_nodes_movements} - end - end - - defp validate_valid_reward_distribution(ops = %LedgerOperations{}) do - if LedgerOperations.valid_reward_distribution?(ops) do - :ok - else - {:error, :invalid_reward_distribution} - end - end - defp validate_no_additional_errors(%Transaction{validation_stamp: %ValidationStamp{errors: []}}), do: :ok @@ -356,30 +339,11 @@ defmodule ArchEthic.Replication.TransactionValidator do }, previous_inputs_unspent_outputs ) do - previous_storage_nodes_public_keys = - previous_storage_node_public_keys(tx, previous_inputs_unspent_outputs) - - with :ok <- - validate_node_movements_previous_storage_nodes(ops, previous_storage_nodes_public_keys), - :ok <- validate_unspent_outputs(tx, previous_inputs_unspent_outputs) do + with :ok <- validate_unspent_outputs(tx, previous_inputs_unspent_outputs) do validate_funds(ops, previous_inputs_unspent_outputs) end end - defp validate_node_movements_previous_storage_nodes( - ops = %LedgerOperations{}, - previous_storage_nodes_public_keys - ) do - if LedgerOperations.valid_node_movements_previous_storage_nodes?( - ops, - previous_storage_nodes_public_keys - ) do - :ok - else - {:error, :invalid_previous_storage_nodes_movements} - end - end - defp validate_unspent_outputs( tx = %Transaction{ validation_stamp: %ValidationStamp{ @@ -417,29 +381,6 @@ defmodule ArchEthic.Replication.TransactionValidator do end end - defp previous_storage_node_public_keys( - tx = %Transaction{type: type, validation_stamp: %ValidationStamp{timestamp: _timestamp}}, - previous_inputs_unspent_outputs - ) do - node_list = P2P.available_nodes() - - inputs_unspent_outputs_storage_nodes = - previous_inputs_unspent_outputs - |> Stream.map(& &1.from) - |> Stream.flat_map(&Election.chain_storage_nodes(&1, node_list)) - |> Enum.to_list() - - P2P.distinct_nodes([ - Election.chain_storage_nodes_with_type( - Transaction.previous_address(tx), - type, - node_list - ), - inputs_unspent_outputs_storage_nodes - ]) - |> Enum.map(& &1.last_public_key) - end - defp new_ledger_operations( tx = %Transaction{validation_stamp: %ValidationStamp{timestamp: timestamp}}, previous_unspent_outputs @@ -454,36 +395,4 @@ defmodule ArchEthic.Replication.TransactionValidator do |> LedgerOperations.from_transaction(tx) |> LedgerOperations.consume_inputs(tx.address, previous_unspent_outputs) end - - defp validate_node_election( - tx = %Transaction{ - validation_stamp: %ValidationStamp{ - ledger_operations: %LedgerOperations{ - node_movements: node_movements - } - }, - cross_validation_stamps: cross_validation_stamps - } - ) do - coordinator_node_public_key = - get_coordinator_node_public_key_from_node_movements(node_movements) - - validation_nodes = - Enum.uniq([ - coordinator_node_public_key | Enum.map(cross_validation_stamps, & &1.node_public_key) - ]) - - if Mining.valid_election?(tx, validation_nodes) do - :ok - else - {:error, :invalid_node_election} - end - end - - defp get_coordinator_node_public_key_from_node_movements(node_movements) do - %NodeMovement{to: coordinator_node_public_key} = - Enum.find(node_movements, &(:coordinator_node in &1.roles)) - - coordinator_node_public_key - end end diff --git a/lib/archethic/transaction_chain.ex b/lib/archethic/transaction_chain.ex index 7ff5bb4f5..40d7fe7ef 100644 --- a/lib/archethic/transaction_chain.ex +++ b/lib/archethic/transaction_chain.ex @@ -20,6 +20,7 @@ defmodule ArchEthic.TransactionChain do alias __MODULE__.Transaction alias __MODULE__.Transaction.ValidationStamp + alias __MODULE__.TransactionSummary require Logger @@ -469,4 +470,25 @@ defmodule ArchEthic.TransactionChain do end defp get_last_transaction_address([], address, _), do: address + + @doc """ + Get a transaction summary from a transaction address + """ + @spec get_transaction_summary(binary()) :: {:ok, TransactionSummary.t()} | {:error, :not_found} + def get_transaction_summary(address) do + case get_transaction(address, [ + :address, + :type, + validation_stamp: [ + :timestamp, + ledger_operations: [:fee, :transaction_movements] + ] + ]) do + {:ok, tx} -> + {:ok, TransactionSummary.from_transaction(tx)} + + _ -> + {:error, :not_found} + end + end end diff --git a/lib/archethic/transaction_chain/transaction.ex b/lib/archethic/transaction_chain/transaction.ex index a44f0c4cb..96384d5f6 100755 --- a/lib/archethic/transaction_chain/transaction.ex +++ b/lib/archethic/transaction_chain/transaction.ex @@ -523,7 +523,6 @@ defmodule ArchEthic.TransactionChain.Transaction do ...> errors: [], ...> ledger_operations: %ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations{ ...> fee: 0, - ...> node_movements: [], ...> transaction_movements: [], ...> unspent_outputs: [] ...> }, @@ -546,7 +545,7 @@ defmodule ArchEthic.TransactionChain.Transaction do ...> }, ...> version: 1 ...> } - ...> |> Transaction.serialize() + ...> |> Transaction.serialize() <<0, 0, 0, 1, 0, 0, 120, 135, 125, 48, 92, 13, 27, 60, 42, 84, 221, 204, 42, 196, 25, 37, 237, 215, 122, 113, 54, 59, 9, 251, 27, 179, 5, 44, 116, 217, 180, 32, 3, 0, 0, 0, 0, 0, 0, 0, 92, 0, 98, 12, 24, 6, 0, 0, 0, 1, 0, 0, 238, @@ -571,7 +570,7 @@ defmodule ArchEthic.TransactionChain.Transaction do 123, 142, 29, 113, 208, 111, 136, 227, 252, 213, 180, 80, 70, 158, 27, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 187, 93, 5, 6, 190, 102, 244, 88, 141, 142, 7, 138, 178, 77, 128, 21, 95, 29, 222, 145, 211, 18, 48, 16, 185, 69, 209, 146, 56, 26, 106, 191, 101, 56, 15, 99, 52, 179, 212, 169, 7, 30, 131, 39, 100, 115, 73, 176, 212, 121, 236, @@ -677,7 +676,7 @@ defmodule ArchEthic.TransactionChain.Transaction do ...> 123, 142, 29, 113, 208, 111, 136, 227, 252, 213, 180, 80, 70, 158, 27, 148, ...> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ...> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ...> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...> 64, 187, 93, 5, 6, 190, 102, 244, 88, 141, 142, 7, 138, 178, 77, 128, 21, 95, ...> 29, 222, 145, 211, 18, 48, 16, 185, 69, 209, 146, 56, 26, 106, 191, 101, 56, ...> 15, 99, 52, 179, 212, 169, 7, 30, 131, 39, 100, 115, 73, 176, 212, 121, 236, @@ -722,7 +721,6 @@ defmodule ArchEthic.TransactionChain.Transaction do errors: [], ledger_operations: %ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations{ fee: 0, - node_movements: [], transaction_movements: [], unspent_outputs: [] }, diff --git a/lib/archethic/transaction_chain/transaction/validation_stamp.ex b/lib/archethic/transaction_chain/transaction/validation_stamp.ex index ff7d56e7a..2f3beed05 100755 --- a/lib/archethic/transaction_chain/transaction/validation_stamp.ex +++ b/lib/archethic/transaction_chain/transaction/validation_stamp.ex @@ -26,7 +26,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp do - Proof of work: Origin public key matching the origin signature - Proof of integrity: Integrity proof from the entire transaction chain - Proof of election: Digest which define the election's order of validation nodes - - Ledger Operations: Set of ledger operations taken by the network such as fee, node movements, transaction movements and unspent outputs + - Ledger Operations: Set of ledger operations taken by the network such as fee, transaction movements and unspent outputs - Recipients: List of the last smart contract chain resolved addresses - Contract validation: Determine if the transaction coming from a contract is valid according to the constraints - Signature: generated from the coordinator private key to avoid non-repudiation of the stamp @@ -96,7 +96,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp do ...> ledger_operations: %LedgerOperations{ ...> fee: 10_000_000, ...> transaction_movements: [], - ...> node_movements: [], ...> unspent_outputs: [] ...> }, ...> signature: <<67, 12, 4, 246, 155, 34, 32, 108, 195, 54, 139, 8, 77, 152, 5, 55, 233, 217, @@ -123,8 +122,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp do 0, 0, 0, 0, 0, 152, 150, 128, # Nb of transaction movements 0, - # Nb of node movements - 0, # Nb of unspent outputs 0, # Nb of resolved recipients addresses @@ -202,7 +199,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp do ...> 240, 175, 53, 236, 65, 151, 191, 128, 11, 58, 103, 82, 6, 218, 31, 220, 114, ...> 65, 3, 151, 209, 9, 84, 209, 105, 191, 180, 156, 157, 95, 25, 202, 2, 169, ...> 112, 109, 54, 99, 40, 47, 96, 93, 33, 82, 40, 100, 13, - ...> 0, 0, 0, 0, 0, 152, 150, 128, 0, 0, 0, 0, 0, 64, + ...> 0, 0, 0, 0, 0, 152, 150, 128, 0, 0, 0, 0, 64, ...> 67, 12, 4, 246, 155, 34, 32, 108, 195, 54, 139, 8, 77, 152, 5, 55, 233, 217, ...> 126, 181, 204, 195, 215, 239, 124, 186, 99, 187, 251, 243, 201, 6, 122, 65, ...> 238, 221, 14, 89, 120, 225, 39, 33, 95, 95, 225, 113, 143, 200, 47, 96, 239, @@ -222,7 +219,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp do ledger_operations: %ValidationStamp.LedgerOperations{ fee: 10_000_000, transaction_movements: [], - node_movements: [], unspent_outputs: [] }, recipients: [], diff --git a/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations.ex b/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations.ex index 6791015d9..595c791cd 100644 --- a/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations.ex +++ b/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations.ex @@ -9,28 +9,14 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation @unit_uco 100_000_000 - # 0.5% - @storage_node_rate 50_000_000 - # 0.4% - @cross_validation_node_rate 40_000_000 - # 0.1% - @coordinator_rate 10_000_000 - # 0.1% - @network_pool_rate 10_000_000 - defstruct transaction_movements: [], - node_movements: [], unspent_outputs: [], fee: 0 alias ArchEthic.Crypto - alias ArchEthic.P2P - alias ArchEthic.P2P.Node - alias ArchEthic.TransactionChain alias ArchEthic.TransactionChain.Transaction - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.TransactionMovement @@ -40,13 +26,11 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation @typedoc """ - Transaction movements: represents the pending transaction ledger movements - - Node movements: represents the node rewards - Unspent outputs: represents the new unspent outputs - fee: represents the transaction fee distributed across the node movements """ @type t() :: %__MODULE__{ transaction_movements: list(TransactionMovement.t()), - node_movements: list(NodeMovement.t()), unspent_outputs: list(UnspentOutput.t()), fee: non_neg_integer() } @@ -99,206 +83,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation def from_transaction(ops = %__MODULE__{}, %Transaction{}), do: ops - @doc """ - Create node rewards and movements based on the transaction fee by distributing it using the different rates - for each individual actor: coordinator node, cross validation node, previous storage node - - 10% of the transaction's fee are burnt dedicated to the network pool - - ## Examples - - iex> %LedgerOperations{ fee: 50_000_000} # 0.5 UCO - ...> |> LedgerOperations.distribute_rewards( - ...> %Node{last_public_key: "F35EB8260981AC5D8268B7B323277C8FB44D73B81DCC603B0E9CEB4B406A18AD"}, - ...> [ - ...> %Node{last_public_key: "5D0AE5A5B686030AD630119F3494B4852E3990BF196C117D574FD32BEB747FC7"}, - ...> %Node{last_public_key: "074CA174E4763A169F714C0D37187C5AC889683B4BBE9B0859C4073A690B7DF1"} - ...> ], - ...> [ - ...> %Node{last_public_key: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23"}, - ...> %Node{last_public_key: "AFC6C2DF93A524F3EE569745EE6F22131BB3F380E5121DDF730982DC7C1AD9AE"}, - ...> %Node{last_public_key: "4D75266A648F6D67576E6C77138C07042077B815FB5255D7F585CD36860DA19E"} - ...> ] - ...> ) - %LedgerOperations{ - fee: 50_000_000, - transaction_movements: [ %TransactionMovement { to: <<0::8, 0::8, 0::256>>, amount: 5_000_000, type: :UCO} ], - node_movements: [ - %NodeMovement{to: "074CA174E4763A169F714C0D37187C5AC889683B4BBE9B0859C4073A690B7DF1", amount: 10_000_000, roles: [:cross_validation_node] }, - %NodeMovement{to: "4D75266A648F6D67576E6C77138C07042077B815FB5255D7F585CD36860DA19E", amount: 8_333_333, roles: [:previous_storage_node]}, - %NodeMovement{to: "5D0AE5A5B686030AD630119F3494B4852E3990BF196C117D574FD32BEB747FC7", amount: 10_000_000, roles: [:cross_validation_node]}, - %NodeMovement{to: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23", amount: 8_333_333, roles: [:previous_storage_node]}, - %NodeMovement{to: "AFC6C2DF93A524F3EE569745EE6F22131BB3F380E5121DDF730982DC7C1AD9AE", amount: 8_333_333, roles: [:previous_storage_node]}, - %NodeMovement{to: "F35EB8260981AC5D8268B7B323277C8FB44D73B81DCC603B0E9CEB4B406A18AD", amount: 5_000_000, roles: [:coordinator_node]}, - ] - } - - When some nodes has several roles (present in the network bootstrapping phase), - a mapping per node and per role is perform to ensure the right amount of rewards. - - iex> %LedgerOperations{ fee: 50_000_000} - ...> |> LedgerOperations.distribute_rewards( - ...> %Node{last_public_key: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23"}, - ...> [ - ...> %Node{last_public_key: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23"}, - ...> %Node{last_public_key: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23"} - ...> ], - ...> [ - ...> %Node{last_public_key: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23"}, - ...> %Node{last_public_key: "AFC6C2DF93A524F3EE569745EE6F22131BB3F380E5121DDF730982DC7C1AD9AE"}, - ...> %Node{last_public_key: "4D75266A648F6D67576E6C77138C07042077B815FB5255D7F585CD36860DA19E"} - ...> ] - ...> ) - %LedgerOperations{ - fee: 50_000_000, - transaction_movements: [ %TransactionMovement { to: <<0::8, 0::8, 0::256>>, amount: 5_000_000, type: :UCO} ], - node_movements: [ - %NodeMovement{to: "4D75266A648F6D67576E6C77138C07042077B815FB5255D7F585CD36860DA19E", amount: 8_333_333, roles: [:previous_storage_node]}, - %NodeMovement{to: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23", amount: 23_333_333, roles: [:coordinator_node, :cross_validation_node, :previous_storage_node] }, - %NodeMovement{to: "AFC6C2DF93A524F3EE569745EE6F22131BB3F380E5121DDF730982DC7C1AD9AE", amount: 8_333_333, roles: [:previous_storage_node] } - ] - } - """ - @spec distribute_rewards(t(), Node.t(), list(Node.t()), list(Node.t())) :: - t() - def distribute_rewards( - ops = %__MODULE__{fee: fee}, - %Node{last_public_key: coordinator_node_public_key}, - cross_validation_nodes, - previous_storage_nodes - ) - when is_list(cross_validation_nodes) and is_list(previous_storage_nodes) do - cross_validation_node_reward = - get_cross_validation_node_reward(fee, length(cross_validation_nodes)) - - previous_storage_node_reward = - get_previous_storage_reward(fee, length(previous_storage_nodes)) - - role_distribution = - [ - {:coordinator_node, coordinator_node_public_key} - ] ++ - Enum.map(cross_validation_nodes, &{:cross_validation_node, &1.last_public_key}) ++ - Enum.map(previous_storage_nodes, &{:previous_storage_node, &1.last_public_key}) - - node_movements = - role_distribution - |> group_roles_by_node - |> Enum.to_list() - |> sum_rewards( - reward_per_role(fee, cross_validation_node_reward, previous_storage_node_reward) - ) - |> Enum.map(fn {public_key, {roles, reward}} -> - %NodeMovement{to: public_key, amount: reward, roles: roles} - end) - - ops - |> Map.update!( - :transaction_movements, - &[ - %TransactionMovement{ - to: @burning_address, - amount: get_network_pool_reward(fee), - type: :UCO - } - | &1 - ] - ) - |> Map.put(:node_movements, node_movements) - end - - defp sum_rewards(_, _, acc \\ %{}) - - defp sum_rewards([{public_key, roles} | tail], rewards_by_role, acc) do - sum_node_rewards = Enum.reduce(roles, 0, &(&2 + Map.get(rewards_by_role, &1))) - sum_rewards(tail, rewards_by_role, Map.put(acc, public_key, {roles, sum_node_rewards})) - end - - defp sum_rewards([], _, acc), do: acc - - defp group_roles_by_node(_, acc \\ %{}) - - defp group_roles_by_node([{role, public_key} | tail], acc) do - group_roles_by_node(tail, Map.update(acc, public_key, [role], &Enum.uniq([role | &1]))) - end - - defp group_roles_by_node(_, acc) do - Enum.map(acc, fn {public_key, roles} -> - {public_key, Enum.reverse(roles)} - end) - end - - @doc """ - Return the reward for the network pool based on the fee and its rate - - The allocation for the network represents 10% - - ## Examples - - iex> LedgerOperations.get_network_pool_reward(100_000_000) - 10_000_000 - """ - @spec get_network_pool_reward(fee :: non_neg_integer()) :: non_neg_integer() - def get_network_pool_reward(fee), do: div(fee * @network_pool_rate, @unit_uco) - - @doc """ - Return the reward for the coordinator node based on the fee and its rate - - The allocation for coordinator represents 10% - - ## Examples - - iex> LedgerOperations.get_coordinator_node_reward(100_000_000) - 10_000_000 - """ - @spec get_coordinator_node_reward(fee :: non_neg_integer()) :: non_neg_integer() - def get_coordinator_node_reward(fee), do: div(fee * @coordinator_rate, @unit_uco) - - @doc """ - Return the reward for each cross validation node based on the fee, the rate and the number of cross validation nodes - - The allocation for the entire cross validation nodes represents 40% of the fee - - ## Examples - - iex> LedgerOperations.get_cross_validation_node_reward(100_000_000, 2) - 20_000_000 - """ - @spec get_cross_validation_node_reward( - fee :: non_neg_integer(), - nb_cross_validation_nodes :: non_neg_integer() - ) :: non_neg_integer() - def get_cross_validation_node_reward(fee, nb_cross_validation_nodes) do - (fee * @cross_validation_node_rate) - |> div(@unit_uco) - |> div(nb_cross_validation_nodes) - end - - @doc """ - Return the reward for each previous storage node based on the fee, its rate and the number of storage nodes - - The allocation for the entire previous storages nodes represents 50% of the fee - - ## Examples - - iex> LedgerOperations.get_previous_storage_reward(100_000_000, 5) - 10_000_000 - - iex> LedgerOperations.get_previous_storage_reward(100_000_000, 0) - 0 - """ - @spec get_previous_storage_reward( - fee :: non_neg_integer(), - nb_previous_storage_nodes :: non_neg_integer() - ) :: non_neg_integer() - def get_previous_storage_reward(_fee, 0), do: 0 - - def get_previous_storage_reward(fee, nb_previous_storage_nodes) do - (fee * @storage_node_rate) - |> div(@unit_uco) - |> div(nb_previous_storage_nodes) - end - @doc """ Returns the amount to spend from the transaction movements and the fee @@ -428,7 +212,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation %TransactionMovement{to: "@Charlie2", amount: 217_000_000, type: :UCO} ], fee: 40_000_000, - node_movements: [], unspent_outputs: [ %UnspentOutput{from: "@Alice2", amount: 703_000_000, type: :UCO} ] @@ -455,7 +238,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation %TransactionMovement{to: "@Charlie2", amount: 217_000_000, type: :UCO}, ], fee: 40_000_000, - node_movements: [], unspent_outputs: [ %UnspentOutput{from: "@Alice2", amount: 1_103_000_000, type: :UCO}, ] @@ -478,7 +260,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation %TransactionMovement{to: "@Bob4", amount: 1_000_000_000, type: {:NFT, "@CharlieNFT"}} ], fee: 40_000_000, - node_movements: [], unspent_outputs: [ %UnspentOutput{from: "@Alice2", amount: 160_000_000, type: :UCO}, %UnspentOutput{from: "@Alice2", amount: 200_000_000, type: {:NFT, "@CharlieNFT"}} @@ -504,7 +285,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation %TransactionMovement{to: "@Bob4", amount: 1_000_000_000, type: {:NFT, "@CharlieNFT"}} ], fee: 40_000_000, - node_movements: [], unspent_outputs: [ %UnspentOutput{from: "@Alice2", amount: 160_000_000, type: :UCO}, %UnspentOutput{from: "@Alice2", amount: 900_000_000, type: {:NFT, "@CharlieNFT"}} @@ -554,28 +334,15 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation end @doc """ - List all the addresses from transaction movements and node movements. - - Node movements public keys are used to determine the node addresses + List all the addresses from transaction movements """ @spec movement_addresses(t()) :: list(binary()) def movement_addresses(%__MODULE__{ - transaction_movements: transaction_movements, - node_movements: node_movements + transaction_movements: transaction_movements }) do - node_addresses = - node_movements - |> Enum.map(fn %NodeMovement{to: public_key} -> - %Node{reward_address: address} = P2P.get_node_info!(public_key) - address - end) - - transaction_addresses = - transaction_movements - |> Enum.reject(&(&1.to == @burning_address)) - |> Enum.map(& &1.to) - - transaction_addresses ++ node_addresses + transaction_movements + |> Enum.reject(&(&1.to == @burning_address)) + |> Enum.map(& &1.to) end @doc """ @@ -592,15 +359,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation ...> amount: 102_000_000, ...> type: :UCO ...> }, - ...> %TransactionMovement{to: <<0::8, 0::8, 0::256>> , amount: 1_000_000, type: :UCO} - ...> ], - ...> node_movements: [ - ...> %NodeMovement{ - ...> to: <<0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, 220, 195, 112, 1, 54, 221, - ...> 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207>>, - ...> amount: 9_000_000, - ...> roles: [:coordinator_node, :cross_validation_node, :previous_storage_node] - ...> }, ...> ], ...> unspent_outputs: [ ...> %UnspentOutput{ @@ -616,7 +374,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation # Fee (0.1 UCO) 0, 0, 0, 0, 0, 152, 150, 128, # Nb of transaction movements - 2, + 1, # Transaction movement recipient 0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, 220, 195, 112, 1, 54, 221, 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207, @@ -624,23 +382,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation 0, 0, 0, 0, 6, 20, 101, 128, # Transaction movement type (UCO) 0, - # Network pool burning address - 0::8, 0::8, 0::256, - # Amount of fee burnt (0.01) - 0, 0, 0, 0, 0, 15, 66, 64, - # Type of movement - 0, - # Nb of node movements - 1, - # Node public key - 0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, 220, 195, 112, 1, 54, 221, - 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207, - # Node reward (0.09 UCO) - 0, 0, 0, 0, 0, 137, 84, 64, - # Nb roles - 3, - # Roles - 0, 1, 2, # Nb of unspent outputs 1, # Unspent output origin @@ -649,15 +390,12 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation # Unspent output amount (2 UCO) 0, 0, 0, 0, 11, 235, 194, 0, # Unspent output type (UCO) - 0, - # Unspent output reward? 0 >> """ def serialize(%__MODULE__{ fee: fee, transaction_movements: transaction_movements, - node_movements: node_movements, unspent_outputs: unspent_outputs }) do bin_transaction_movements = @@ -665,15 +403,11 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation |> Enum.map(&TransactionMovement.serialize/1) |> :erlang.list_to_binary() - bin_node_movements = - node_movements |> Enum.map(&NodeMovement.serialize/1) |> :erlang.list_to_binary() - bin_unspent_outputs = unspent_outputs |> Enum.map(&UnspentOutput.serialize/1) |> :erlang.list_to_binary() <> + length(unspent_outputs)::8, bin_unspent_outputs::binary>> end @doc """ @@ -681,17 +415,12 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation ## Examples - iex> <<0, 0, 0, 0, 0, 152, 150, 128, 2, + iex> <<0, 0, 0, 0, 0, 152, 150, 128, 1, ...> 0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, 220, 195, 112, 1, 54, 221, 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207, ...> 0, 0, 0, 0, 60, 203, 247, 0, 0, - ...> 0, 0, 0::256, 0, 0, 0, 0, 0, 15, 66, 64, 0, - ...> 1, 0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, 220, 195, 112, - ...> 1, 54, 221, 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207, - ...> 0, 0, 0, 0, 0, 137, 84, 64, - ...> 3, 0, 1, 2, ...> 1, 0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, ...> 220, 195, 112, 1, 54, 221, 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207, - ...> 0, 0, 0, 0, 11, 235, 194, 0, 0, 0>> + ...> 0, 0, 0, 0, 11, 235, 194, 0, 0>> ...> |> LedgerOperations.deserialize() { %LedgerOperations{ @@ -702,19 +431,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207>>, amount: 1_020_000_000, type: :UCO - }, - %TransactionMovement { - to: <<0::8, 0::8, 0::256>>, - amount: 1_000_000, - type: :UCO - } - ], - node_movements: [ - %NodeMovement{ - to: <<0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, 220, 195, 112, 1, 54, 221, - 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207>>, - amount: 9_000_000, - roles: [:coordinator_node, :cross_validation_node, :previous_storage_node] } ], unspent_outputs: [ @@ -722,8 +438,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation from: <<0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, 220, 195, 112, 1, 54, 221, 86, 154, 234, 96, 217, 149, 84, 188, 63, 242, 166, 47, 158, 139, 207>>, amount: 200_000_000, - type: :UCO, - reward?: false + type: :UCO } ] }, @@ -732,8 +447,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation """ def deserialize(<>) do {tx_movements, rest} = reduce_transaction_movements(rest, nb_transaction_movements, []) - <> = rest - {node_movements, rest} = reduce_node_movements(rest, nb_node_movements, []) <> = rest {unspent_outputs, rest} = reduce_unspent_outputs(rest, nb_unspent_outputs, []) @@ -741,7 +454,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation %__MODULE__{ fee: fee, transaction_movements: tx_movements, - node_movements: node_movements, unspent_outputs: unspent_outputs }, rest @@ -759,17 +471,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation reduce_transaction_movements(rest, nb, [tx_movement | acc]) end - defp reduce_node_movements(rest, 0, _), do: {[], rest} - - defp reduce_node_movements(rest, nb, acc) when length(acc) == nb do - {Enum.reverse(acc), rest} - end - - defp reduce_node_movements(rest, nb, acc) do - {node_movement, rest} = NodeMovement.deserialize(rest) - reduce_node_movements(rest, nb, [node_movement | acc]) - end - defp reduce_unspent_outputs(rest, 0, _), do: {[], rest} defp reduce_unspent_outputs(rest, nb, acc) when length(acc) == nb do @@ -787,9 +488,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation transaction_movements: Map.get(ledger_ops, :transaction_movements, []) |> Enum.map(&TransactionMovement.from_map/1), - node_movements: - Map.get(ledger_ops, :node_movements, []) - |> Enum.map(&NodeMovement.from_map/1), unspent_outputs: Map.get(ledger_ops, :unspent_outputs, []) |> Enum.map(&UnspentOutput.from_map/1), @@ -800,238 +498,16 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation @spec to_map(t()) :: map() def to_map(%__MODULE__{ transaction_movements: transaction_movements, - node_movements: node_movements, unspent_outputs: unspent_outputs, fee: fee }) do %{ transaction_movements: Enum.map(transaction_movements, &TransactionMovement.to_map/1), - node_movements: Enum.map(node_movements, &NodeMovement.to_map/1), unspent_outputs: Enum.map(unspent_outputs, &UnspentOutput.to_map/1), fee: fee } end - @doc """ - Determines if the node movements are valid according to a list of nodes - - ## Examples - - iex> %LedgerOperations{ - ...> fee: 50_000_000, - ...> transaction_movements: [%TransactionMovement{to: <<0::8, 0::8, 0::256>>, amount: 5_000_000, type: :UCO}], - ...> node_movements: [ - ...> %NodeMovement{to: "F35EB8260981AC5D8268B7B323277C8FB44D73B81DCC603B0E9CEB4B406A18AD", amount: 5_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "5D0AE5A5B686030AD630119F3494B4852E3990BF196C117D574FD32BEB747FC7", amount: 10_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "074CA174E4763A169F714C0D37187C5AC889683B4BBE9B0859C4073A690B7DF1", amount: 10_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23", amount: 8_333_333, roles: [:previous_storage_node]}, - ...> %NodeMovement{to: "AFC6C2DF93A524F3EE569745EE6F22131BB3F380E5121DDF730982DC7C1AD9AE", amount: 8_333_333, roles: [:previous_storage_node]}, - ...> %NodeMovement{to: "4D75266A648F6D67576E6C77138C07042077B815FB5255D7F585CD36860DA19E", amount: 8_333_333, roles: [:previous_storage_node]} - ...> ] - ...> } - ...> |> LedgerOperations.valid_reward_distribution?() - true - - When some nodes has several roles(present in the network bootstrapping phase), - a mapping per node and per role is perform to ensure the right amount of rewards. - - iex> %LedgerOperations{ - ...> fee: 50_000_000, - ...> transaction_movements: [%TransactionMovement{to: <<0::8, 0::8, 0::256>>, amount: 5_000_000, type: :UCO}], - ...> node_movements: [ - ...> %NodeMovement{to: "503EF04022CDAA3F0F402A1C2524ED3782E09F228BC16DEB1766051C86880F8D", amount: 25_000_000, roles: [:coordinator_node, :cross_validation_node]}, - ...> %NodeMovement{to: "5EDA43AA8BBDAB66E4737989D44471F70FDEFD41D9E186507F27A61FA2170B23", amount: 8_333_333, roles: [:previous_storage_node]}, - ...> %NodeMovement{to: "AFC6C2DF93A524F3EE569745EE6F22131BB3F380E5121DDF730982DC7C1AD9AE", amount: 8_333_333, roles: [:previous_storage_node]}, - ...> %NodeMovement{to: "4D75266A648F6D67576E6C77138C07042077B815FB5255D7F585CD36860DA19E", amount: 8_333_333, roles: [:previous_storage_node]} - ...> ] - ...> } - ...> |> LedgerOperations.valid_reward_distribution?() - true - """ - @spec valid_reward_distribution?(t()) :: boolean() - def valid_reward_distribution?(%__MODULE__{ - fee: fee, - node_movements: node_movements, - transaction_movements: transaction_movements - }) do - nb_cross_validation_nodes = Enum.count(node_movements, &(:cross_validation_node in &1.roles)) - - cross_validation_node_reward = - get_cross_validation_node_reward(fee, nb_cross_validation_nodes) - - nb_previous_storage_nodes = Enum.count(node_movements, &(:previous_storage_node in &1.roles)) - previous_storage_node_reward = get_previous_storage_reward(fee, nb_previous_storage_nodes) - - rewards_matrix = - reward_per_role(fee, cross_validation_node_reward, previous_storage_node_reward) - - valid_node_movements? = - Enum.all?(node_movements, fn %NodeMovement{roles: roles, amount: amount} -> - total_rewards = Enum.reduce(roles, 0, &(&2 + Map.get(rewards_matrix, &1))) - amount == total_rewards - end) - - valid_network_pool_reward? = - Enum.any?( - transaction_movements, - &(&1.to == @burning_address and &1.amount == get_network_pool_reward(fee) and - &1.type == :UCO) - ) - - valid_network_pool_reward? and valid_node_movements? - end - - defp reward_per_role(fee, cross_validation_node_reward, previous_storage_node_reward) do - %{ - coordinator_node: get_coordinator_node_reward(fee), - cross_validation_node: cross_validation_node_reward, - previous_storage_node: previous_storage_node_reward - } - end - - @doc """ - Determine if the roles in the node movements are correctly distributed: - - one coordinator node - - one or many cross validation nodes - - ## Examples - - iex> %LedgerOperations{ - ...> node_movements: [ - ...> %NodeMovement{to: "key1", amount: 23_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key2", amount: 4_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "key3", amount: 1_000_000, roles: [:previous_storage_node]} - ...> ] - ...> } |> LedgerOperations.valid_node_movements_roles?() - true - - iex> %LedgerOperations{ - ...> node_movements: [ - ...> %NodeMovement{to: "key1", amount: 23_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key1", amount: 23_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key2", amount: 4_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "key3", amount: 1_000_000, roles: [:previous_storage_node]} - ...> ] - ...> } |> LedgerOperations.valid_node_movements_roles?() - false - """ - @spec valid_node_movements_roles?(t()) :: boolean() - def valid_node_movements_roles?(%__MODULE__{node_movements: node_movements}) do - frequencies = - node_movements - |> Enum.flat_map(& &1.roles) - |> Enum.frequencies() - - with 1 <- Map.get(frequencies, :coordinator_node), - true <- Map.get(frequencies, :cross_validation_nodes) >= 1 do - true - else - _ -> - false - end - end - - @doc """ - Determine if the cross validation node movements public keys are the good one from a list of cross validation node public keys - - ## Examples - - iex> %LedgerOperations{ - ...> node_movements: [ - ...> %NodeMovement{to: "key2", amount: 30_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key3", amount: 15_000_000, roles: [:cross_validation_node]} - ...> ] - ...> } |> LedgerOperations.valid_node_movements_cross_validation_nodes?(["key3"]) - true - """ - @spec valid_node_movements_cross_validation_nodes?(t(), list(Crypto.key())) :: boolean() - def valid_node_movements_cross_validation_nodes?( - %__MODULE__{node_movements: node_movements}, - cross_validation_node_public_keys - ) do - node_movements - |> Enum.filter(&(&1.to in cross_validation_node_public_keys)) - |> Enum.all?(&(:cross_validation_node in &1.roles)) - end - - @doc """ - Determine if the node movements with previous storage node role are the list of previous storage nodes public keys - - ## Examples - - iex> %LedgerOperations{ - ...> node_movements: [ - ...> %NodeMovement{to: "key2", amount: 30_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key3", amount: 10_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "key4", amount: 80_000_000, roles: [:previous_storage_nodes]} - ...> ] - ...> } |> LedgerOperations.valid_node_movements_previous_storage_nodes?(["key10", "key4", "key8"]) - true - - iex> %LedgerOperations{ - ...> node_movements: [ - ...> %NodeMovement{to: "key2", amount: 30_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key3", amount: 15_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "key4", amount: 80_000_000, roles: [:previous_storage_nodes]}, - ...> %NodeMovement{to: "key22", amount: 80_000_000, roles: [:previous_storage_node]} - ...> ] - ...> } |> LedgerOperations.valid_node_movements_previous_storage_nodes?(["key10", "key4", "key8"]) - false - """ - @spec valid_node_movements_previous_storage_nodes?(t(), list(Crypto.key())) :: boolean() - def valid_node_movements_previous_storage_nodes?( - %__MODULE__{node_movements: node_movements}, - previous_storage_node_public_keys - ) do - node_movements - |> Enum.filter(&(:previous_storage_node in &1.roles)) - |> Enum.all?(&(&1.to in previous_storage_node_public_keys)) - end - - @doc """ - Determine if the node movements involve a node public key with a given role - - ## Examples - - iex> %LedgerOperations{ - ...> node_movements: [ - ...> %NodeMovement{to: "key2", amount: 43_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key3", amount: 20_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "key4", amount: 10_000_000, roles: [:previous_storage_node]} - ...> ] - ...> } - ...> |> LedgerOperations.has_node_movement_with_role?("key2", :coordinator_node) - true - - iex> %LedgerOperations{ - ...> node_movements: [ - ...> %NodeMovement{to: "key2", amount: 43_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key3", amount: 20_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "key4", amount: 10_000_000, roles: [:previous_storage_node]} - ...> ] - ...> } - ...> |> LedgerOperations.has_node_movement_with_role?("other node", :coordinator_node) - false - - iex> %LedgerOperations{ - ...> node_movements: [ - ...> %NodeMovement{to: "key2", amount: 43_000_000, roles: [:coordinator_node]}, - ...> %NodeMovement{to: "key3", amount: 20_000_000, roles: [:cross_validation_node]}, - ...> %NodeMovement{to: "key4", amount: 10_000_000, roles: [:previous_storage_node]} - ...> ] - ...> } - ...> |> LedgerOperations.has_node_movement_with_role?("key1", :coordinator_node) - false - """ - @spec has_node_movement_with_role?(t(), Crypto.key(), NodeMovement.role()) :: boolean() - def has_node_movement_with_role?( - %__MODULE__{node_movements: node_movements}, - node_public_key, - node_role - ) do - Enum.any?(node_movements, &(&1.to == node_public_key and node_role in &1.roles)) - end - @doc """ Determines if the transaction movements are valid at a given time """ @@ -1045,7 +521,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation expected_movements = [ %TransactionMovement{ to: @burning_address, - amount: get_network_pool_reward(fee), + amount: fee, type: :UCO } | resolve_transaction_movements(tx_movements, timestamp) diff --git a/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/node_movement.ex b/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/node_movement.ex deleted file mode 100644 index 12693baf6..000000000 --- a/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/node_movement.ex +++ /dev/null @@ -1,128 +0,0 @@ -defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement do - @moduledoc """ - Represents the movements regarding the nodes involved during the - transaction validation. The node public keys are present as well as their rewards - """ - defstruct [:to, :amount, :roles] - - alias ArchEthic.Crypto - alias ArchEthic.Utils - - @type role() :: - :coordinator_node | :cross_validation_node | :previous_storage_node - - @type t() :: %__MODULE__{ - to: Crypto.key(), - amount: non_neg_integer(), - roles: list(role()) - } - - @doc """ - Serialize a node movement into binary format - - ## Examples - - iex> %NodeMovement{ - ...> to: <<0, 0, 214, 107, 17, 107, 227, 11, 17, 43, 204, 48, 78, 129, 145, 126, 45, 68, 194, - ...> 159, 19, 92, 240, 29, 37, 105, 183, 232, 56, 42, 163, 236, 251, 186>>, - ...> amount: 30_000_000, - ...> roles: [:coordinator_node, :previous_storage_node] - ...> } - ...> |> NodeMovement.serialize() - << - # Node public key - 0, 0, 214, 107, 17, 107, 227, 11, 17, 43, 204, 48, 78, 129, 145, 126, 45, 68, 194, - 159, 19, 92, 240, 29, 37, 105, 183, 232, 56, 42, 163, 236, 251, 186, - # Amount - 0, 0, 0, 0, 1, 201, 195, 128, - # Nb roles - 2, - # Coordinator and previous storage node roles - 0, 2 - >> - """ - @spec serialize(t()) :: <<_::64, _::_*8>> - def serialize(%__MODULE__{to: to, amount: amount, roles: roles}) do - roles_bin = Enum.map(roles, &role_to_bin/1) |> :erlang.list_to_binary() - <> - end - - defp role_to_bin(:coordinator_node), do: <<0>> - defp role_to_bin(:cross_validation_node), do: <<1>> - defp role_to_bin(:previous_storage_node), do: <<2>> - - @doc """ - Deserialize an encoded node movement - - ## Examples - - iex> <<0, 0, 214, 107, 17, 107, 227, 11, 17, 43, 204, 48, 78, 129, 145, 126, 45, 68, 194, - ...> 159, 19, 92, 240, 29, 37, 105, 183, 232, 56, 42, 163, 236, 251, 186, - ...> 0, 0, 0, 0, 1, 201, 195, 128, 2, 0, 2 - ...> >> - ...> |> NodeMovement.deserialize() - { - %NodeMovement{ - to: <<0, 0, 214, 107, 17, 107, 227, 11, 17, 43, 204, 48, 78, 129, 145, 126, 45, 68, 194, - 159, 19, 92, 240, 29, 37, 105, 183, 232, 56, 42, 163, 236, 251, 186>>, - amount: 30_000_000, - roles: [:coordinator_node, :previous_storage_node] - }, - "" - } - """ - @spec deserialize(bitstring()) :: {t(), bitstring} - def deserialize(data) do - {public_key, <>} = - Utils.deserialize_public_key(data) - - { - %__MODULE__{ - to: public_key, - amount: amount, - roles: bin_roles_to_list(bin_roles) - }, - rest - } - end - - defp bin_roles_to_list(_, acc \\ []) - - defp bin_roles_to_list(<<0, rest::binary>>, acc), - do: bin_roles_to_list(rest, [:coordinator_node | acc]) - - defp bin_roles_to_list(<<1, rest::binary>>, acc), - do: bin_roles_to_list(rest, [:cross_validation_node | acc]) - - defp bin_roles_to_list(<<2, rest::binary>>, acc), - do: bin_roles_to_list(rest, [:previous_storage_node | acc]) - - defp bin_roles_to_list(<<>>, acc), do: Enum.reverse(acc) - - @spec from_map(map()) :: t() - def from_map(movement = %{}) do - roles = - case Map.get(movement, :roles) do - nil -> - nil - - roles -> - Enum.map(roles, &String.to_atom/1) - end - - %__MODULE__{ - to: Map.get(movement, :to), - amount: Map.get(movement, :amount), - roles: roles - } - end - - @spec to_map(t()) :: map() - def to_map(%__MODULE__{to: to, amount: amount, roles: roles}) do - %{ - to: to, - amount: amount, - roles: Enum.map(roles, &Atom.to_string/1) - } - end -end diff --git a/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/unspent_output.ex b/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/unspent_output.ex index 74ecb12b5..87a2609fe 100644 --- a/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/unspent_output.ex +++ b/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/unspent_output.ex @@ -14,8 +14,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation @type t :: %__MODULE__{ amount: non_neg_integer(), from: Crypto.versioned_hash(), - type: TransactionMovementType.t(), - reward?: boolean() + type: TransactionMovementType.t() } @doc """ @@ -39,8 +38,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation # Amount 0, 0, 0, 0, 62, 149, 186, 128, # UCO Unspent Output - 0, - # Reward? 0 >> @@ -64,16 +61,12 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation 1, # NFT address 0, 49, 101, 72, 154, 152, 3, 174, 47, 2, 35, 7, 92, 122, 206, 185, 71, 140, 74, - 197, 46, 99, 117, 89, 96, 100, 20, 0, 34, 181, 215, 143, 175, - # Reward? - 0 + 197, 46, 99, 117, 89, 96, 100, 20, 0, 34, 181, 215, 143, 175 >> """ @spec serialize(__MODULE__.t()) :: <<_::64, _::_*8>> - def serialize(%__MODULE__{from: from, amount: amount, type: type, reward?: reward?}) do - reward_bit = if reward?, do: 1, else: 0 - - <> + def serialize(%__MODULE__{from: from, amount: amount, type: type}) do + <> end @doc """ @@ -83,15 +76,14 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation iex> <<0, 0, 214, 107, 17, 107, 227, 11, 17, 43, 204, 48, 78, 129, 145, 126, 45, 68, 194, ...> 159, 19, 92, 240, 29, 37, 105, 183, 232, 56, 42, 163, 236, 251, 186, - ...> 0, 0, 0, 0, 62, 149, 186, 128, 0, 0>> + ...> 0, 0, 0, 0, 62, 149, 186, 128, 0>> ...> |> UnspentOutput.deserialize() { %UnspentOutput{ from: <<0, 0, 214, 107, 17, 107, 227, 11, 17, 43, 204, 48, 78, 129, 145, 126, 45, 68, 194, 159, 19, 92, 240, 29, 37, 105, 183, 232, 56, 42, 163, 236, 251, 186>>, amount: 1_050_000_000, - type: :UCO, - reward?: false + type: :UCO }, "" } @@ -99,7 +91,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation iex> <<0, 0, 214, 107, 17, 107, 227, 11, 17, 43, 204, 48, 78, 129, 145, 126, 45, 68, 194, ...> 159, 19, 92, 240, 29, 37, 105, 183, 232, 56, 42, 163, 236, 251, 186, ...> 0, 0, 0, 0, 62, 149, 186, 128, 1, 0, 0, 49, 101, 72, 154, 152, 3, 174, 47, 2, 35, 7, 92, 122, 206, 185, 71, 140, 74, - ...> 197, 46, 99, 117, 89, 96, 100, 20, 0, 34, 181, 215, 143, 175, 0 + ...> 197, 46, 99, 117, 89, 96, 100, 20, 0, 34, 181, 215, 143, 175 ...> >> ...> |> UnspentOutput.deserialize() { @@ -108,8 +100,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation 159, 19, 92, 240, 29, 37, 105, 183, 232, 56, 42, 163, 236, 251, 186>>, amount: 1_050_000_000, type: {:NFT, <<0, 0, 49, 101, 72, 154, 152, 3, 174, 47, 2, 35, 7, 92, 122, 206, 185, 71, 140, 74, - 197, 46, 99, 117, 89, 96, 100, 20, 0, 34, 181, 215, 143, 175>>}, - reward?: false + 197, 46, 99, 117, 89, 96, 100, 20, 0, 34, 181, 215, 143, 175>>} }, "" } @@ -117,16 +108,13 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation @spec deserialize(bitstring()) :: {__MODULE__.t(), bitstring} def deserialize(data) when is_bitstring(data) do {address, <>} = Utils.deserialize_address(data) - {type, <>} = TransactionMovementType.deserialize(rest) - - reward? = if reward_bit == 1, do: true, else: false + {type, rest} = TransactionMovementType.deserialize(rest) { %__MODULE__{ from: address, amount: amount, - type: type, - reward?: reward? + type: type }, rest } @@ -136,8 +124,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation def from_map(unspent_output = %{}) do res = %__MODULE__{ from: Map.get(unspent_output, :from), - amount: Map.get(unspent_output, :amount), - reward?: Map.get(unspent_output, :reward) + amount: Map.get(unspent_output, :amount) } case Map.get(unspent_output, :type) do @@ -150,12 +137,11 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation end @spec to_map(t()) :: map() - def to_map(%__MODULE__{from: from, amount: amount, type: :UCO, reward?: reward?}) do + def to_map(%__MODULE__{from: from, amount: amount, type: :UCO}) do %{ from: from, amount: amount, - type: "UCO", - reward: reward? + type: "UCO" } end @@ -164,8 +150,7 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation from: from, amount: amount, type: "NFT", - nft_address: nft_address, - reward: false + nft_address: nft_address } end end diff --git a/lib/archethic/transaction_chain/transaction_summary.ex b/lib/archethic/transaction_chain/transaction_summary.ex index fd6ba5b70..ad9eb1088 100644 --- a/lib/archethic/transaction_chain/transaction_summary.ex +++ b/lib/archethic/transaction_chain/transaction_summary.ex @@ -2,7 +2,7 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do @moduledoc """ Represents transaction header or extract to summarize it """ - defstruct [:timestamp, :address, :type, movements_addresses: []] + defstruct [:timestamp, :address, :type, :fee, movements_addresses: []] alias ArchEthic.TransactionChain.Transaction alias ArchEthic.TransactionChain.Transaction.ValidationStamp @@ -14,7 +14,8 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do timestamp: DateTime.t(), address: binary(), movements_addresses: list(binary()), - type: Transaction.transaction_type() + type: Transaction.transaction_type(), + fee: pos_integer() } @doc """ @@ -26,14 +27,18 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do type: type, validation_stamp: %ValidationStamp{ timestamp: timestamp, - ledger_operations: operations + ledger_operations: + operations = %LedgerOperations{ + fee: fee + } } }) do %__MODULE__{ address: address, timestamp: timestamp, movements_addresses: LedgerOperations.movement_addresses(operations), - type: type + type: type, + fee: fee } end @@ -50,7 +55,8 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do ...> movements_addresses: [ ...> <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>> - ...> ] + ...> ], + ...> fee: 10_000_000 ...> } ...> |> TransactionSummary.serialize() << @@ -61,6 +67,8 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do 0, 0, 1, 114, 236, 9, 2, 168, # Type 253, + # Fee, + 0, 0, 0, 0, 0, 152, 150, 128, # Nb movements addresses 0, 1, # Movement address @@ -73,10 +81,11 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do address: address, timestamp: timestamp, type: type, - movements_addresses: movements_addresses + movements_addresses: movements_addresses, + fee: fee }) do <> end @@ -87,7 +96,8 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do iex> <<0, 0, 11, 4, 226, 118, 242, 59, 165, 128, 69, 40, 228, 121, 127, 37, 154, 199, ...> 168, 212, 53, 82, 220, 22, 56, 222, 223, 127, 16, 172, 142, 218, 41, 247, 0, 0, 1, 114, 236, 9, 2, 168, - ...> 253, 0, 1, 0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, + ...> 253, 0, 0, 0, 0, 0, 152, 150, 128, + ...> 0, 1, 0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, ...> 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>> ...> |> TransactionSummary.deserialize() { @@ -99,14 +109,15 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do movements_addresses: [ <<0, 0, 234, 233, 156, 155, 114, 241, 116, 246, 27, 130, 162, 205, 249, 65, 232, 166, 99, 207, 133, 252, 112, 223, 41, 12, 206, 162, 233, 28, 49, 204, 255, 12>> - ] + ], + fee: 10_000_000 }, "" } """ @spec deserialize(bitstring()) :: {t(), bitstring()} def deserialize(data) when is_bitstring(data) do - {address, <>} = + {address, <>} = Utils.deserialize_address(data) {addresses, rest} = Utils.deserialize_addresses(rest, nb_movements, []) @@ -116,7 +127,8 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do address: address, timestamp: DateTime.from_unix!(timestamp, :millisecond), type: Transaction.parse_type(type), - movements_addresses: addresses + movements_addresses: addresses, + fee: fee }, rest } @@ -127,13 +139,15 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do address: address, timestamp: timestamp, type: type, - movements_addresses: movements_addresses + movements_addresses: movements_addresses, + fee: fee }) do %{ address: address, timestamp: timestamp, type: Atom.to_string(type), - movements_addresses: movements_addresses + movements_addresses: movements_addresses, + fee: fee } end @@ -142,13 +156,15 @@ defmodule ArchEthic.TransactionChain.TransactionSummary do address: address, timestamp: timestamp, type: type, - movements_addresses: movements_addresses + movements_addresses: movements_addresses, + fee: fee }) do %__MODULE__{ address: address, timestamp: timestamp, type: String.to_atom(type), - movements_addresses: movements_addresses + movements_addresses: movements_addresses, + fee: fee } end end diff --git a/lib/archethic_web/graphql_schema/transaction_type.ex b/lib/archethic_web/graphql_schema/transaction_type.ex index 92398103b..45b2cfec1 100644 --- a/lib/archethic_web/graphql_schema/transaction_type.ex +++ b/lib/archethic_web/graphql_schema/transaction_type.ex @@ -141,7 +141,6 @@ defmodule ArchEthicWeb.GraphQLSchema.TransactionType do """ object :ledger_operations do field(:transaction_movements, list_of(:transaction_movement)) - field(:node_movements, list_of(:node_movement)) field(:unspent_outputs, list_of(:unspent_output)) field(:fee, :amount) end @@ -195,17 +194,6 @@ defmodule ArchEthicWeb.GraphQLSchema.TransactionType do field(:nft_address, :address) end - @desc """ - [NodeMovement] represents node transaction movement - It includes: - - To: node public key - - Amount: reward (UCO) - """ - object :node_movement do - field(:to, :public_key) - field(:amount, :amount) - end - @desc """ [CrossValidationStamp] represents the approval of the validation stamp by a cross validation node. It includes: diff --git a/lib/archethic_web/templates/explorer/transaction_details.html.leex b/lib/archethic_web/templates/explorer/transaction_details.html.leex index 39f51609d..04067741d 100644 --- a/lib/archethic_web/templates/explorer/transaction_details.html.leex +++ b/lib/archethic_web/templates/explorer/transaction_details.html.leex @@ -292,12 +292,6 @@ Transaction movements -
  • - - Node movements - -
  • @@ -353,31 +347,6 @@ <% end %> -
    -

    Node movements

    - <%= for movement <- @transaction.validation_stamp.ledger_operations.node_movements do %> -
    -
    -
    Node public key
    -
    - <%= link to: Routes.live_path(@socket, ArchEthicWeb.NodeDetailsLive, Base.encode16(movement.to)) do%> - <%= Base.encode16(movement.to) %> - <% end %> -
    -
    -
    -
    Reward
    -
    - <%= to_float(movement.amount) %> - UCO - <%= if movement.amount > 0 do %> - (<%= format_full_usd_amount(movement.amount, @uco_price_at_time[:usd], @uco_price_now[:usd]) %>) - <% end %> -
    -
    -
    - <% end %> -

    Unspent outputs

    diff --git a/priv/migrations/2_create_validation_stamp_type.cql b/priv/migrations/2_create_validation_stamp_type.cql index e83513097..1826eb776 100644 --- a/priv/migrations/2_create_validation_stamp_type.cql +++ b/priv/migrations/2_create_validation_stamp_type.cql @@ -1,9 +1,3 @@ -CREATE TYPE IF NOT EXISTS archethic.ledger_operations_node_movement( - "to" blob, - amount bigint, - roles list -); - CREATE TYPE IF NOT EXISTS archethic.ledger_operations_transaction_movement( "to" blob, amount bigint, @@ -15,14 +9,12 @@ CREATE TYPE IF NOT EXISTS archethic.ledger_operations_unspent_output( "from" blob, amount bigint, type varchar, - nft_address blob, - reward boolean + nft_address blob ); CREATE TYPE IF NOT EXISTS archethic.ledger_operations( fee bigint, transaction_movements LIST>, - node_movements LIST>, unspent_outputs LIST> ); diff --git a/test/archethic/account/mem_tables_loader_test.exs b/test/archethic/account/mem_tables_loader_test.exs index c41d4b470..baa3dc353 100644 --- a/test/archethic/account/mem_tables_loader_test.exs +++ b/test/archethic/account/mem_tables_loader_test.exs @@ -11,7 +11,6 @@ defmodule ArchEthic.Account.MemTablesLoaderTest do alias ArchEthic.TransactionChain.Transaction alias ArchEthic.TransactionChain.Transaction.ValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.TransactionMovement @@ -44,9 +43,6 @@ defmodule ArchEthic.Account.MemTablesLoaderTest do %UnspentOutput{from: "@Alice2", amount: 200_000_000, type: :UCO} ] = UCOLedger.get_unspent_outputs("@Charlie3") - [%UnspentOutput{from: "@Charlie3", amount: 1_303_000_000, type: :UCO}] = - UCOLedger.get_unspent_outputs("@NodeKey") - [%UnspentOutput{from: "@Charlie3", amount: 3_400_000_000}] = UCOLedger.get_unspent_outputs("@Tom4") @@ -76,9 +72,6 @@ defmodule ArchEthic.Account.MemTablesLoaderTest do %UnspentOutput{from: "@Alice2", amount: 200_000_000, type: :UCO} ] = UCOLedger.get_unspent_outputs("@Charlie3") - [%UnspentOutput{from: "@Charlie3", amount: 1_303_000_000, type: :UCO}] = - UCOLedger.get_unspent_outputs("@NodeKey") - [%UnspentOutput{from: "@Charlie3", amount: 3_400_000_000, type: :UCO}] = UCOLedger.get_unspent_outputs("@Tom4") @@ -103,7 +96,6 @@ defmodule ArchEthic.Account.MemTablesLoaderTest do %TransactionMovement{to: "@Tom4", amount: 3_400_000_000, type: :UCO}, %TransactionMovement{to: "@Bob3", amount: 1_000_000_000, type: {:NFT, "@CharlieNFT"}} ], - node_movements: [%NodeMovement{to: "NodeKey", amount: 1_303_000_000, roles: []}], unspent_outputs: [ %UnspentOutput{ from: "@Alice2", diff --git a/test/archethic/beacon_chain/subset_test.exs b/test/archethic/beacon_chain/subset_test.exs index ba13a5875..fb724f585 100644 --- a/test/archethic/beacon_chain/subset_test.exs +++ b/test/archethic/beacon_chain/subset_test.exs @@ -55,7 +55,8 @@ defmodule ArchEthic.BeaconChain.SubsetTest do tx_summary = %TransactionSummary{ address: tx_address, timestamp: tx_time, - type: :node + type: :node, + fee: 0 } sig = Crypto.sign_with_last_node_key(TransactionSummary.serialize(tx_summary)) @@ -88,7 +89,8 @@ defmodule ArchEthic.BeaconChain.SubsetTest do tx_summary = %TransactionSummary{ address: tx_address, timestamp: tx_time, - type: :node + type: :node, + fee: 0 } tx_summary_payload = TransactionSummary.serialize(tx_summary) @@ -163,7 +165,8 @@ defmodule ArchEthic.BeaconChain.SubsetTest do 232, 210, 105, 102, 193, 193, 24, 54, 42, 200, 226, 13, 38, 69>>, <<0, 0, 8, 253, 201, 142, 182, 78, 169, 132, 29, 19, 74, 3, 142, 207, 219, 127, 147, 40, 24, 44, 170, 214, 171, 224, 29, 177, 205, 226, 88, 62, 248, 84>> - ] + ], + fee: 0 } tx_summary_payload = TransactionSummary.serialize(tx_summary) @@ -252,7 +255,8 @@ defmodule ArchEthic.BeaconChain.SubsetTest do 232, 210, 105, 102, 193, 193, 24, 54, 42, 200, 226, 13, 38, 69>>, <<0, 0, 8, 253, 201, 142, 182, 78, 169, 132, 29, 19, 74, 3, 142, 207, 219, 127, 147, 40, 24, 44, 170, 214, 171, 224, 29, 177, 205, 226, 88, 62, 248, 84>> - ] + ], + fee: 0 } send( @@ -340,7 +344,8 @@ defmodule ArchEthic.BeaconChain.SubsetTest do 232, 210, 105, 102, 193, 193, 24, 54, 42, 200, 226, 13, 38, 69>>, <<0, 0, 8, 253, 201, 142, 182, 78, 169, 132, 29, 19, 74, 3, 142, 207, 219, 127, 147, 40, 24, 44, 170, 214, 171, 224, 29, 177, 205, 226, 88, 62, 248, 84>> - ] + ], + fee: 0 } tx_summary_payload = TransactionSummary.serialize(tx_summary) diff --git a/test/archethic/bootstrap/network_init_test.exs b/test/archethic/bootstrap/network_init_test.exs index e61b9d358..8d6df5994 100644 --- a/test/archethic/bootstrap/network_init_test.exs +++ b/test/archethic/bootstrap/network_init_test.exs @@ -94,18 +94,12 @@ defmodule ArchEthic.Bootstrap.NetworkInitTest do tx = NetworkInit.self_validation(tx, unspent_outputs) tx_fee = tx.validation_stamp.ledger_operations.fee - network_pool_burn = LedgerOperations.get_network_pool_reward(tx_fee) unspent_output = 1_000_000_000_000 - (tx_fee + 500_000_000_000) assert %Transaction{ validation_stamp: %ValidationStamp{ ledger_operations: %LedgerOperations{ transaction_movements: [ - %TransactionMovement{ - to: <<0::8, 0::8, 0::256>>, - amount: ^network_pool_burn, - type: :UCO - }, %TransactionMovement{to: "@Alice2", amount: 500_000_000_000, type: :UCO} ], unspent_outputs: [ @@ -140,11 +134,6 @@ defmodule ArchEthic.Bootstrap.NetworkInitTest do tx = TransactionFactory.create_valid_transaction( - %{ - welcome_node: P2P.get_node_info(), - coordinator_node: P2P.get_node_info(), - storage_nodes: [P2P.get_node_info()] - }, inputs, type: :transfer ) @@ -178,6 +167,8 @@ defmodule ArchEthic.Bootstrap.NetworkInitTest do end test "init_node_shared_secrets_chain/1 should create node shared secrets transaction chain, load daily nonce and authorize node" do + start_supervised!({ArchEthic.SelfRepair.Scheduler, [interval: "0 0 0 * *"]}) + MockClient |> stub(:send_message, fn _, %GetTransactionChain{}, _ -> diff --git a/test/archethic/bootstrap/sync_test.exs b/test/archethic/bootstrap/sync_test.exs index 2dcb98c6b..e12957849 100644 --- a/test/archethic/bootstrap/sync_test.exs +++ b/test/archethic/bootstrap/sync_test.exs @@ -209,6 +209,8 @@ defmodule ArchEthic.Bootstrap.SyncTest do end test "should initiate storage nonce, first node transaction, node shared secrets and genesis wallets" do + start_supervised!({ArchEthic.SelfRepair.Scheduler, [interval: "0 0 0 * *"]}) + MockDB |> stub(:chain_size, fn _ -> 1 end) diff --git a/test/archethic/bootstrap_test.exs b/test/archethic/bootstrap_test.exs index 133491dce..9c941b84e 100644 --- a/test/archethic/bootstrap_test.exs +++ b/test/archethic/bootstrap_test.exs @@ -41,7 +41,6 @@ defmodule ArchEthic.BootstrapTest do alias ArchEthic.TransactionChain.Transaction alias ArchEthic.TransactionChain.Transaction.ValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.TransactionSummary import Mox @@ -197,20 +196,7 @@ defmodule ArchEthic.BootstrapTest do timestamp: DateTime.utc_now(), proof_of_work: "", proof_of_integrity: "", - ledger_operations: %LedgerOperations{ - node_movements: [ - %NodeMovement{ - to: P2P.list_nodes() |> Enum.random() |> Map.get(:last_public_key), - amount: 100_000_000, - roles: [ - :welcome_node, - :coordinator_node, - :cross_validation_node, - :previous_storage_node - ] - } - ] - } + ledger_operations: %LedgerOperations{} } validated_tx = %{tx | validation_stamp: stamp} diff --git a/test/archethic/db/cassandra_impl_test.exs b/test/archethic/db/cassandra_impl_test.exs index 7bd33a68c..df1c6c515 100644 --- a/test/archethic/db/cassandra_impl_test.exs +++ b/test/archethic/db/cassandra_impl_test.exs @@ -435,14 +435,8 @@ defmodule ArchEthic.DB.CassandraImplTest do P2P.add_and_connect_node(welcome_node) P2P.add_and_connect_node(coordinator_node) - context = %{ - welcome_node: welcome_node, - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - } - inputs = Keyword.get(opts, :inputs, []) - TransactionFactory.create_valid_transaction(context, inputs, opts) + TransactionFactory.create_valid_transaction(inputs, opts) end defp empty_keys(tx) do diff --git a/test/archethic/mining/validation_context_test.exs b/test/archethic/mining/validation_context_test.exs index 7fddafda9..0365bd901 100644 --- a/test/archethic/mining/validation_context_test.exs +++ b/test/archethic/mining/validation_context_test.exs @@ -16,7 +16,6 @@ defmodule ArchEthic.Mining.ValidationContextTest do alias ArchEthic.TransactionChain.Transaction.CrossValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.TransactionMovement @@ -93,19 +92,6 @@ defmodule ArchEthic.Mining.ValidationContextTest do |> ValidationContext.cross_validate() end - test "should get inconsistency when the node movements are invalid" do - validation_context = create_context() - - %ValidationContext{ - cross_validation_stamps: [%CrossValidationStamp{inconsistencies: [:node_movements]}] - } = - validation_context - |> ValidationContext.add_validation_stamp( - create_validation_stamp_with_invalid_node_movements(validation_context) - ) - |> ValidationContext.cross_validate() - end - test "should get inconsistency when the errors are invalid" do validation_context = create_context() @@ -205,9 +191,6 @@ defmodule ArchEthic.Mining.ValidationContextTest do defp create_validation_stamp_with_invalid_signature(%ValidationContext{ transaction: tx, - coordinator_node: coordinator_node, - cross_validation_nodes: cross_validation_nodes, - previous_storage_nodes: previous_storage_nodes, unspent_outputs: unspent_outputs }) do %ValidationStamp{ @@ -221,21 +204,13 @@ defmodule ArchEthic.Mining.ValidationContextTest do transaction_movements: Transaction.get_movements(tx) } |> LedgerOperations.from_transaction(tx) - |> LedgerOperations.consume_inputs(tx.address, unspent_outputs) - |> LedgerOperations.distribute_rewards( - coordinator_node, - cross_validation_nodes, - previous_storage_nodes - ), + |> LedgerOperations.consume_inputs(tx.address, unspent_outputs), signature: :crypto.strong_rand_bytes(32) } end defp create_validation_stamp_with_invalid_proof_of_work(%ValidationContext{ transaction: tx, - coordinator_node: coordinator_node, - cross_validation_nodes: cross_validation_nodes, - previous_storage_nodes: previous_storage_nodes, unspent_outputs: unspent_outputs }) do %ValidationStamp{ @@ -250,20 +225,12 @@ defmodule ArchEthic.Mining.ValidationContextTest do } |> LedgerOperations.from_transaction(tx) |> LedgerOperations.consume_inputs(tx.address, unspent_outputs) - |> LedgerOperations.distribute_rewards( - coordinator_node, - cross_validation_nodes, - previous_storage_nodes - ) } |> ValidationStamp.sign() end defp create_validation_stamp_with_invalid_transaction_fee(%ValidationContext{ transaction: tx, - coordinator_node: coordinator_node, - cross_validation_nodes: cross_validation_nodes, - previous_storage_nodes: previous_storage_nodes, unspent_outputs: unspent_outputs }) do %ValidationStamp{ @@ -277,20 +244,12 @@ defmodule ArchEthic.Mining.ValidationContextTest do transaction_movements: Transaction.get_movements(tx) } |> LedgerOperations.consume_inputs(tx.address, unspent_outputs) - |> LedgerOperations.distribute_rewards( - coordinator_node, - cross_validation_nodes, - previous_storage_nodes - ) } |> ValidationStamp.sign() end defp create_validation_stamp_with_invalid_transaction_movements(%ValidationContext{ transaction: tx, - coordinator_node: coordinator_node, - cross_validation_nodes: cross_validation_nodes, - previous_storage_nodes: previous_storage_nodes, unspent_outputs: unspent_outputs }) do fee = Fee.calculate(tx, 0.07) @@ -315,20 +274,12 @@ defmodule ArchEthic.Mining.ValidationContextTest do ] } |> LedgerOperations.consume_inputs(tx.address, unspent_outputs) - |> LedgerOperations.distribute_rewards( - coordinator_node, - cross_validation_nodes, - previous_storage_nodes - ) } |> ValidationStamp.sign() end defp create_validation_stamp_with_invalid_unspent_outputs(%ValidationContext{ transaction: tx, - coordinator_node: coordinator_node, - cross_validation_nodes: cross_validation_nodes, - previous_storage_nodes: previous_storage_nodes, unspent_outputs: _unspent_outputs }) do %ValidationStamp{ @@ -336,81 +287,23 @@ defmodule ArchEthic.Mining.ValidationContextTest do proof_of_work: Crypto.first_node_public_key(), proof_of_integrity: TransactionChain.proof_of_integrity([tx]), proof_of_election: Election.validation_nodes_election_seed_sorting(tx, DateTime.utc_now()), - ledger_operations: - %LedgerOperations{ - fee: Fee.calculate(tx, 0.07), - transaction_movements: Transaction.get_movements(tx), - unspent_outputs: [ - %UnspentOutput{ - amount: 100_000_000_000, - from: tx.address, - type: :UCO - } - ] - } - |> LedgerOperations.distribute_rewards( - coordinator_node, - cross_validation_nodes, - previous_storage_nodes - ) - } - |> ValidationStamp.sign() - end - - defp create_validation_stamp_with_invalid_node_movements(%ValidationContext{ - transaction: tx, - coordinator_node: coordinator_node, - cross_validation_nodes: cross_validation_nodes, - previous_storage_nodes: previous_storage_nodes, - unspent_outputs: unspent_outputs - }) do - %ValidationStamp{ - timestamp: DateTime.utc_now(), - proof_of_work: Crypto.first_node_public_key(), - proof_of_integrity: TransactionChain.proof_of_integrity([tx]), - proof_of_election: Election.validation_nodes_election_seed_sorting(tx, DateTime.utc_now()), - ledger_operations: - %LedgerOperations{ - fee: Fee.calculate(tx, 0.07), - transaction_movements: Transaction.get_movements(tx), - node_movements: [ - %NodeMovement{ - to: coordinator_node.last_public_key, - amount: 2_000_000_000, - roles: [:coordinator_node] - }, - %NodeMovement{ - to: Enum.at(cross_validation_nodes, 0).last_public_key, - amount: 1_500_000_000, - roles: [:cross_validation_node] - }, - %NodeMovement{ - to: Enum.at(cross_validation_nodes, 1).last_public_key, - amount: 1_500_000_000, - roles: [:cross_validation_node] - }, - %NodeMovement{ - to: Enum.at(previous_storage_nodes, 0).last_public_key, - amount: 1_000_000_000, - roles: [:previous_storage_node] - }, - %NodeMovement{ - to: Enum.at(previous_storage_nodes, 1).last_public_key, - amount: 1_000_000_000, - roles: [:previous_storage_node] - } - ] - } - |> LedgerOperations.consume_inputs(tx.address, unspent_outputs) + ledger_operations: %LedgerOperations{ + fee: Fee.calculate(tx, 0.07), + transaction_movements: Transaction.get_movements(tx), + unspent_outputs: [ + %UnspentOutput{ + amount: 100_000_000_000, + from: tx.address, + type: :UCO + } + ] + } } |> ValidationStamp.sign() end defp create_validation_stamp_with_invalid_errors(%ValidationContext{ transaction: tx, - coordinator_node: coordinator_node, - cross_validation_nodes: cross_validation_nodes, - previous_storage_nodes: previous_storage_nodes, unspent_outputs: unspent_outputs }) do %ValidationStamp{ @@ -423,12 +316,7 @@ defmodule ArchEthic.Mining.ValidationContextTest do fee: Fee.calculate(tx, 0.07), transaction_movements: Transaction.get_movements(tx) } - |> LedgerOperations.consume_inputs(tx.address, unspent_outputs) - |> LedgerOperations.distribute_rewards( - coordinator_node, - cross_validation_nodes, - previous_storage_nodes - ), + |> LedgerOperations.consume_inputs(tx.address, unspent_outputs), errors: [:contract_validation] } |> ValidationStamp.sign() diff --git a/test/archethic/p2p/messages_test.exs b/test/archethic/p2p/messages_test.exs index fdd21d386..25f76ef48 100644 --- a/test/archethic/p2p/messages_test.exs +++ b/test/archethic/p2p/messages_test.exs @@ -52,7 +52,6 @@ defmodule ArchEthic.P2P.MessageTest do alias ArchEthic.TransactionChain.Transaction.CrossValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.UnspentOutput alias ArchEthic.TransactionChain.TransactionData alias ArchEthic.TransactionChain.TransactionInput @@ -195,15 +194,6 @@ defmodule ArchEthic.P2P.MessageTest do ledger_operations: %LedgerOperations{ fee: 1_000_000, transaction_movements: [], - node_movements: [ - %NodeMovement{ - to: - <<0, 0, 92, 208, 222, 119, 27, 128, 82, 69, 163, 128, 196, 105, 19, 18, 99, 217, - 105, 80, 238, 155, 239, 91, 54, 82, 200, 16, 121, 32, 83, 63, 79, 88>>, - amount: 1_000_000, - roles: [:coordinator_node] - } - ], unspent_outputs: [] }, signature: @@ -289,15 +279,6 @@ defmodule ArchEthic.P2P.MessageTest do ledger_operations: %LedgerOperations{ fee: 1_000_000, transaction_movements: [], - node_movements: [ - %NodeMovement{ - to: - <<0, 0, 92, 208, 222, 119, 27, 128, 82, 69, 163, 128, 196, 105, 19, 18, 99, - 217, 105, 80, 238, 155, 239, 91, 54, 82, 200, 16, 121, 32, 83, 63, 79, 88>>, - amount: 1_000_000, - roles: [:coordinator_node] - } - ], unspent_outputs: [] }, signature: @@ -367,15 +348,6 @@ defmodule ArchEthic.P2P.MessageTest do ledger_operations: %LedgerOperations{ fee: 1_000_000, transaction_movements: [], - node_movements: [ - %NodeMovement{ - to: - <<0, 0, 92, 208, 222, 119, 27, 128, 82, 69, 163, 128, 196, 105, 19, 18, 99, - 217, 105, 80, 238, 155, 239, 91, 54, 82, 200, 16, 121, 32, 83, 63, 79, 88>>, - amount: 1_000_000, - roles: [:coordinator_node] - } - ], unspent_outputs: [] }, signature: @@ -534,16 +506,6 @@ defmodule ArchEthic.P2P.MessageTest do ledger_operations: %LedgerOperations{ fee: 1_000_000, transaction_movements: [], - node_movements: [ - %NodeMovement{ - to: - <<0, 0, 92, 208, 222, 119, 27, 128, 82, 69, 163, 128, 196, 105, 19, 18, 99, - 217, 105, 80, 238, 155, 239, 91, 54, 82, 200, 16, 121, 32, 83, 63, 79, - 88>>, - amount: 1_000_000, - roles: [:coordinator_node] - } - ], unspent_outputs: [] }, signature: diff --git a/test/archethic/replication/transaction_validator_test.exs b/test/archethic/replication/transaction_validator_test.exs index 89deab600..320bdfe29 100644 --- a/test/archethic/replication/transaction_validator_test.exs +++ b/test/archethic/replication/transaction_validator_test.exs @@ -46,8 +46,7 @@ defmodule ArchEthic.Replication.TransactionValidatorTest do last_public_key: "key3", available?: true, geo_patch: "BBB", - authorization_date: DateTime.utc_now() |> DateTime.add(-1), - authorized?: true + authorization_date: DateTime.utc_now() |> DateTime.add(-1) } ] @@ -65,101 +64,67 @@ defmodule ArchEthic.Replication.TransactionValidatorTest do end describe "validate/2" do - test "should return {:error, :invalid_atomic_commitment} when the atomic commitment is not reached", - context do + test "should return {:error, :invalid_atomic_commitment} when the atomic commitment is not reached" do unspent_outputs = [%UnspentOutput{from: "@Alice2", amount: 1_000_000_000, type: :UCO}] assert {:error, :invalid_atomic_commitment} = - context - |> TransactionFactory.create_transaction_with_not_atomic_commitment( - unspent_outputs - ) + TransactionFactory.create_transaction_with_not_atomic_commitment(unspent_outputs) |> TransactionValidator.validate() end - test "should return {:error, :invalid_proof_of_work} when an invalid proof of work", - context do + test "should return {:error, :invalid_proof_of_work} when an invalid proof of work" do assert {:error, :invalid_proof_of_work} = - context - |> TransactionFactory.create_transaction_with_invalid_proof_of_work([]) + TransactionFactory.create_transaction_with_invalid_proof_of_work() |> TransactionValidator.validate() end - test "should return {:error, :invalid_proof_of_election} when an invalid proof of work", - context do + test "should return {:error, :invalid_proof_of_election} when an invalid proof of work" do assert {:error, :invalid_proof_of_election} = - context - |> TransactionFactory.create_transaction_with_invalid_proof_of_election([]) + TransactionFactory.create_transaction_with_invalid_proof_of_election() |> TransactionValidator.validate() end - test "should return {:error, :invalid_validation_stamp_signature} when the validation stamp signature is invalid", - context do - assert {:error, :invalid_validation_stamp_signature} = - context - |> TransactionFactory.create_transaction_with_invalid_validation_stamp_signature( - [] - ) + test "should return {:error, :invalid_node_election} when the validation stamp signature is invalid" do + assert {:error, :invalid_node_election} = + TransactionFactory.create_transaction_with_invalid_validation_stamp_signature() |> TransactionValidator.validate() end - test "should return {:error, :invalid_transaction_fee} when the fees are invalid", - context do + test "should return {:error, :invalid_transaction_fee} when the fees are invalid" do assert {:error, :invalid_transaction_fee} = - context - |> TransactionFactory.create_transaction_with_invalid_fee([]) + TransactionFactory.create_transaction_with_invalid_fee() |> TransactionValidator.validate() end - test "should return {:error, :invalid_transaction_movements} when the transaction movements are invalid", - context do + test "should return {:error, :invalid_transaction_movements} when the transaction movements are invalid" do assert {:error, :invalid_transaction_movements} = - context - |> TransactionFactory.create_transaction_with_invalid_transaction_movements([]) + TransactionFactory.create_transaction_with_invalid_transaction_movements() |> TransactionValidator.validate() end - test "should return {:error, ::invalid_cross_validation_nodes_movements} when the node movements are invalid", - context do - unspent_outputs = [%UnspentOutput{from: "@Alice2", amount: 1_000_000_000, type: :UCO}] - - assert {:error, :invalid_cross_validation_nodes_movements} = - context - |> TransactionFactory.create_transaction_with_invalid_node_movements( - unspent_outputs - ) - |> TransactionValidator.validate() - end - - test "should return {:error, :invalid_transaction_with_inconsistencies} when there is an atomic commitment but with inconsistencies", - context do + test "should return {:error, :invalid_transaction_with_inconsistencies} when there is an atomic commitment but with inconsistencies" do unspent_outputs = [%UnspentOutput{from: "@Alice2", amount: 1_000_000_000, type: :UCO}] assert {:error, :invalid_transaction_with_inconsistencies} = - context - |> TransactionFactory.create_valid_transaction_with_inconsistencies( - unspent_outputs - ) + TransactionFactory.create_valid_transaction_with_inconsistencies(unspent_outputs) |> TransactionValidator.validate() end - test "should return :ok when the transaction is valid", context do + test "should return :ok when the transaction is valid" do unspent_outputs = [%UnspentOutput{from: "@Alice2", amount: 1_000_000_000, type: :UCO}] assert :ok = - context - |> TransactionFactory.create_valid_transaction(unspent_outputs) + TransactionFactory.create_valid_transaction(unspent_outputs) |> TransactionValidator.validate() end end describe "validate/3" do - test "should return :ok when the transaction is valid", context do + test "should return :ok when the transaction is valid" do unspent_outputs = [%UnspentOutput{from: "@Alice2", amount: 1_000_000_000, type: :UCO}] assert :ok = - context - |> TransactionFactory.create_valid_transaction(unspent_outputs) + TransactionFactory.create_valid_transaction(unspent_outputs) |> TransactionValidator.validate(nil, unspent_outputs) end end diff --git a/test/archethic/replication_test.exs b/test/archethic/replication_test.exs index 1a061e9a7..13d9681cc 100644 --- a/test/archethic/replication_test.exs +++ b/test/archethic/replication_test.exs @@ -59,7 +59,8 @@ defmodule ArchEthic.ReplicationTest do me = self() unspent_outputs = [%UnspentOutput{from: "@Alice2", amount: 1_000_000_000, type: :UCO}] - tx = create_valid_transaction(transaction_context(), unspent_outputs) + p2p_context() + tx = create_valid_transaction(unspent_outputs) MockDB |> expect(:write_transaction_chain, fn _ -> @@ -88,24 +89,11 @@ defmodule ArchEthic.ReplicationTest do end test "validate_and_store_transaction/1" do - P2P.add_and_connect_node(%Node{ - ip: {127, 0, 0, 1}, - port: 3000, - authorized?: true, - last_public_key: Crypto.last_node_public_key(), - first_public_key: Crypto.last_node_public_key(), - available?: true, - geo_patch: "AAA", - network_patch: "AAA", - enrollment_date: DateTime.utc_now(), - authorization_date: DateTime.utc_now() |> DateTime.add(-10), - reward_address: <<0::8, 0::8, :crypto.strong_rand_bytes(32)::binary>> - }) - me = self() unspent_outputs = [%UnspentOutput{from: "@Alice2", amount: 1_000_000_000, type: :UCO}] - tx = create_valid_transaction(transaction_context(), unspent_outputs) + p2p_context() + tx = create_valid_transaction(unspent_outputs) MockDB |> expect(:write_transaction, fn _ -> @@ -120,7 +108,7 @@ defmodule ArchEthic.ReplicationTest do assert_received :replicated end - defp transaction_context do + defp p2p_context do SharedSecrets.add_origin_public_key(:software, Crypto.first_node_public_key()) welcome_node = %Node{ @@ -154,7 +142,6 @@ defmodule ArchEthic.ReplicationTest do available?: true, geo_patch: "BBB", network_patch: "BBB", - authorized?: true, authorization_date: DateTime.utc_now(), reward_address: <<0::8, :crypto.strong_rand_bytes(32)::binary>> } @@ -172,24 +159,13 @@ defmodule ArchEthic.ReplicationTest do } end - defp create_valid_transaction( - %{ - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - }, - unspent_outputs - ) do + defp create_valid_transaction(unspent_outputs) do tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) ledger_operations = %LedgerOperations{ fee: Fee.calculate(tx, 0.07) } - |> LedgerOperations.distribute_rewards( - coordinator_node, - [coordinator_node], - [coordinator_node] ++ storage_nodes - ) |> LedgerOperations.consume_inputs(tx.address, unspent_outputs) validation_stamp = diff --git a/test/archethic/self_repair/sync/beacon_summary_handler/transaction_handler_test.exs b/test/archethic/self_repair/sync/beacon_summary_handler/transaction_handler_test.exs index 0f1f4ba39..cc4167e6b 100644 --- a/test/archethic/self_repair/sync/beacon_summary_handler/transaction_handler_test.exs +++ b/test/archethic/self_repair/sync/beacon_summary_handler/transaction_handler_test.exs @@ -65,7 +65,6 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandler.TransactionHandlerTest geo_patch: "BBB", network_patch: "BBB", reward_address: :crypto.strong_rand_bytes(32), - authorized?: true, authorization_date: DateTime.utc_now() } ] @@ -94,7 +93,7 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandler.TransactionHandlerTest }) end - test "download_transaction/2 should download the transaction", context do + test "download_transaction/2 should download the transaction" do inputs = [ %TransactionInput{ from: "@Alice2", @@ -104,7 +103,7 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandler.TransactionHandlerTest } ] - tx = TransactionFactory.create_valid_transaction(context, inputs) + tx = TransactionFactory.create_valid_transaction(inputs) MockClient |> stub(:send_message, fn @@ -116,7 +115,7 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandler.TransactionHandlerTest assert ^tx = TransactionHandler.download_transaction(tx_summary, "AAA") end - test "process_transaction/1 should handle the transaction and replicate it", context do + test "process_transaction/1 should handle the transaction and replicate it" do me = self() inputs = [ @@ -128,7 +127,7 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandler.TransactionHandlerTest } ] - tx = TransactionFactory.create_valid_transaction(context, inputs) + tx = TransactionFactory.create_valid_transaction(inputs) MockClient |> stub(:send_message, fn diff --git a/test/archethic/self_repair/sync/beacon_summary_handler_test.exs b/test/archethic/self_repair/sync/beacon_summary_handler_test.exs index 3d5e87573..482e1aca8 100644 --- a/test/archethic/self_repair/sync/beacon_summary_handler_test.exs +++ b/test/archethic/self_repair/sync/beacon_summary_handler_test.exs @@ -139,7 +139,8 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandlerTest do tx_summary = %TransactionSummary{ address: addr1, timestamp: DateTime.utc_now(), - type: :transfer + type: :transfer, + fee: 100_000_000 } storage_nodes = @@ -195,7 +196,8 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandlerTest do transaction_summary: %TransactionSummary{ address: addr1, timestamp: DateTime.utc_now(), - type: :transfer + type: :transfer, + fee: 100_000_000 } } ] @@ -209,14 +211,16 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandlerTest do transaction_summary: %TransactionSummary{ address: addr1, timestamp: DateTime.utc_now(), - type: :transfer + type: :transfer, + fee: 100_000_000 } }, %ReplicationAttestation{ transaction_summary: %TransactionSummary{ address: addr2, timestamp: DateTime.utc_now(), - type: :transfer + type: :transfer, + fee: 100_000_000 } } ] @@ -353,22 +357,6 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandlerTest do end test "should synchronize transactions" do - node = %Node{ - ip: {127, 0, 0, 1}, - port: 3000, - first_public_key: Crypto.last_node_public_key(), - last_public_key: Crypto.last_node_public_key(), - available?: true, - geo_patch: "AAA", - network_patch: "AAA", - reward_address: <<0::8, 0::8, :crypto.strong_rand_bytes(32)::binary>>, - enrollment_date: DateTime.utc_now(), - authorized?: true, - authorization_date: DateTime.utc_now() |> DateTime.add(-1) - } - - P2P.add_and_connect_node(node) - inputs = [ %TransactionInput{ from: "@Alice2", @@ -378,8 +366,10 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandlerTest do } ] + create_p2p_context() + transfer_tx = - TransactionFactory.create_valid_transaction(create_mining_context(), inputs, + TransactionFactory.create_valid_transaction(inputs, seed: "transfer_seed" ) @@ -441,7 +431,7 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandlerTest do end end - defp create_mining_context do + defp create_p2p_context do welcome_node = %Node{ first_public_key: "key1", last_public_key: "key1", @@ -474,8 +464,7 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandlerTest do geo_patch: "BBB", network_patch: "BBB", reward_address: <<0::8, 0::8, :crypto.strong_rand_bytes(32)::binary>>, - authorization_date: DateTime.utc_now(), - authorized?: true + authorization_date: DateTime.utc_now() } ] @@ -483,11 +472,5 @@ defmodule ArchEthic.SelfRepair.Sync.BeaconSummaryHandlerTest do P2P.add_and_connect_node(welcome_node) P2P.add_and_connect_node(coordinator_node) - - %{ - welcome_node: welcome_node, - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - } end end diff --git a/test/archethic/self_repair/sync_test.exs b/test/archethic/self_repair/sync_test.exs index ee0c2d944..112300847 100644 --- a/test/archethic/self_repair/sync_test.exs +++ b/test/archethic/self_repair/sync_test.exs @@ -142,8 +142,7 @@ defmodule ArchEthic.SelfRepair.SyncTest do }} end - test "should retrieve the missing beacon summaries from the given date", - context do + test "should retrieve the missing beacon summaries from the given date" do Crypto.generate_deterministic_keypair("daily_nonce_seed") |> elem(0) |> NetworkLookup.set_daily_nonce_public_key(DateTime.utc_now() |> DateTime.add(-10)) @@ -158,7 +157,7 @@ defmodule ArchEthic.SelfRepair.SyncTest do } ] - tx = TransactionFactory.create_valid_transaction(context, inputs) + tx = TransactionFactory.create_valid_transaction(inputs) me = self() @@ -175,7 +174,8 @@ defmodule ArchEthic.SelfRepair.SyncTest do tx_summary = %TransactionSummary{ address: tx.address, type: :transfer, - timestamp: DateTime.utc_now() + timestamp: DateTime.utc_now(), + fee: 100_000_000 } elected_storage_nodes = diff --git a/test/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/node_movement_test.exs b/test/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/node_movement_test.exs deleted file mode 100644 index b300e6139..000000000 --- a/test/archethic/transaction_chain/transaction/validation_stamp/ledger_operations/node_movement_test.exs +++ /dev/null @@ -1,5 +0,0 @@ -defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovementTest do - use ExUnit.Case - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement - doctest NodeMovement -end diff --git a/test/archethic/transaction_chain/transaction/validation_stamp/ledger_operations_test.exs b/test/archethic/transaction_chain/transaction/validation_stamp/ledger_operations_test.exs index 36859ad26..bf657327d 100644 --- a/test/archethic/transaction_chain/transaction/validation_stamp/ledger_operations_test.exs +++ b/test/archethic/transaction_chain/transaction/validation_stamp/ledger_operations_test.exs @@ -2,11 +2,8 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperation use ArchEthicCase use ExUnitProperties - alias ArchEthic.P2P.Node - alias ArchEthic.TransactionChain.Transaction alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.TransactionMovement diff --git a/test/archethic/transaction_chain/transaction/validation_stamp_test.exs b/test/archethic/transaction_chain/transaction/validation_stamp_test.exs index 6e3a9e85c..1c1aa1a97 100644 --- a/test/archethic/transaction_chain/transaction/validation_stamp_test.exs +++ b/test/archethic/transaction_chain/transaction/validation_stamp_test.exs @@ -8,7 +8,6 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStampTest do alias ArchEthic.TransactionChain.Transaction.ValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.TransactionMovement @@ -42,29 +41,17 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStampTest do defp gen_ledger_operations do gen all( fee <- StreamData.positive_integer(), - node_movements <- StreamData.list_of(gen_node_movement()), transaction_movements <- StreamData.list_of(gen_transaction_movement()), unspent_outputs <- StreamData.list_of(gen_unspent_outputs()) ) do %LedgerOperations{ fee: fee, - node_movements: node_movements, transaction_movements: transaction_movements, unspent_outputs: unspent_outputs } end end - defp gen_node_movement do - gen all( - to <- StreamData.binary(length: 33), - amount <- StreamData.positive_integer(), - roles <- gen_roles() - ) do - %NodeMovement{to: to, amount: amount, roles: Enum.take(roles, 1)} - end - end - defp gen_transaction_movement do gen all( to <- StreamData.binary(length: 33), @@ -92,10 +79,4 @@ defmodule ArchEthic.TransactionChain.Transaction.ValidationStampTest do %UnspentOutput{from: from, amount: amount, type: type} end end - - defp gen_roles do - [:coordinator_node, :cross_validation_node, :previous_storage_node] - |> StreamData.one_of() - |> StreamData.uniq_list_of(min_length: 1, max_length: 3, max_tries: 100) - end end diff --git a/test/support/transaction_factory.ex b/test/support/transaction_factory.ex index c15873c39..5a4155161 100644 --- a/test/support/transaction_factory.ex +++ b/test/support/transaction_factory.ex @@ -12,17 +12,12 @@ defmodule ArchEthic.TransactionFactory do alias ArchEthic.TransactionChain.Transaction.CrossValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations - alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.NodeMovement alias ArchEthic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.TransactionMovement alias ArchEthic.TransactionChain.TransactionData def create_valid_transaction( - %{ - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - }, inputs \\ [], opts \\ [] ) do @@ -39,11 +34,6 @@ defmodule ArchEthic.TransactionFactory do fee: Fee.calculate(tx, 0.07), transaction_movements: Transaction.get_movements(tx) } - |> LedgerOperations.distribute_rewards( - coordinator_node, - [coordinator_node], - storage_nodes - ) |> LedgerOperations.consume_inputs(tx.address, inputs) validation_stamp = @@ -62,8 +52,8 @@ defmodule ArchEthic.TransactionFactory do %{tx | validation_stamp: validation_stamp, cross_validation_stamps: [cross_validation_stamp]} end - def create_transaction_with_not_atomic_commitment(context, unspent_outputs) do - tx = create_valid_transaction(context, unspent_outputs) + def create_transaction_with_not_atomic_commitment(unspent_outputs \\ []) do + tx = create_valid_transaction(unspent_outputs) cross_validation_stamp = CrossValidationStamp.sign( @@ -74,24 +64,13 @@ defmodule ArchEthic.TransactionFactory do Map.update!(tx, :cross_validation_stamps, &[cross_validation_stamp | &1]) end - def create_valid_transaction_with_inconsistencies( - %{ - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - }, - inputs - ) do + def create_valid_transaction_with_inconsistencies(inputs \\ []) do tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) ledger_operations = %LedgerOperations{ fee: Fee.calculate(tx, 0.07) } - |> LedgerOperations.distribute_rewards( - coordinator_node, - [coordinator_node], - [coordinator_node] ++ storage_nodes - ) |> LedgerOperations.consume_inputs(tx.address, inputs) validation_stamp = @@ -114,24 +93,13 @@ defmodule ArchEthic.TransactionFactory do %{tx | validation_stamp: validation_stamp, cross_validation_stamps: [cross_validation_stamp]} end - def create_transaction_with_invalid_proof_of_work( - %{ - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - }, - inputs - ) do + def create_transaction_with_invalid_proof_of_work(inputs \\ []) do tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) ledger_operations = %LedgerOperations{ fee: Fee.calculate(tx, 0.07) } - |> LedgerOperations.distribute_rewards( - coordinator_node, - [coordinator_node], - [coordinator_node] ++ storage_nodes - ) |> LedgerOperations.consume_inputs(tx.address, inputs) validation_stamp = %ValidationStamp{ @@ -152,24 +120,13 @@ defmodule ArchEthic.TransactionFactory do %{tx | validation_stamp: validation_stamp, cross_validation_stamps: [cross_validation_stamp]} end - def create_transaction_with_invalid_proof_of_election( - %{ - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - }, - inputs - ) do + def create_transaction_with_invalid_proof_of_election(inputs \\ []) do tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) ledger_operations = %LedgerOperations{ fee: Fee.calculate(tx, 0.07) } - |> LedgerOperations.distribute_rewards( - coordinator_node, - [coordinator_node], - [coordinator_node] ++ storage_nodes - ) |> LedgerOperations.consume_inputs(tx.address, inputs) validation_stamp = @@ -192,24 +149,13 @@ defmodule ArchEthic.TransactionFactory do %{tx | validation_stamp: validation_stamp, cross_validation_stamps: [cross_validation_stamp]} end - def create_transaction_with_invalid_validation_stamp_signature( - %{ - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - }, - inputs - ) do + def create_transaction_with_invalid_validation_stamp_signature(inputs \\ []) do tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) ledger_operations = %LedgerOperations{ fee: Fee.calculate(tx, 0.07) } - |> LedgerOperations.distribute_rewards( - coordinator_node, - [coordinator_node], - [coordinator_node] ++ storage_nodes - ) |> LedgerOperations.consume_inputs(tx.address, inputs) validation_stamp = %ValidationStamp{ @@ -230,24 +176,13 @@ defmodule ArchEthic.TransactionFactory do %{tx | validation_stamp: validation_stamp, cross_validation_stamps: [cross_validation_stamp]} end - def create_transaction_with_invalid_fee( - %{ - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - }, - inputs - ) do + def create_transaction_with_invalid_fee(inputs \\ []) do tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) ledger_operations = %LedgerOperations{ fee: 1_000_000_000 } - |> LedgerOperations.distribute_rewards( - coordinator_node, - [coordinator_node], - [coordinator_node] ++ storage_nodes - ) |> LedgerOperations.consume_inputs(tx.address, inputs) validation_stamp = @@ -270,13 +205,7 @@ defmodule ArchEthic.TransactionFactory do %{tx | validation_stamp: validation_stamp, cross_validation_stamps: [cross_validation_stamp]} end - def create_transaction_with_invalid_transaction_movements( - %{ - coordinator_node: coordinator_node, - storage_nodes: storage_nodes - }, - inputs - ) do + def create_transaction_with_invalid_transaction_movements(inputs \\ []) do tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) ledger_operations = @@ -286,49 +215,6 @@ defmodule ArchEthic.TransactionFactory do %TransactionMovement{to: "@Bob4", amount: 30_330_000_000, type: :UCO} ] } - |> LedgerOperations.distribute_rewards( - coordinator_node, - [coordinator_node], - [coordinator_node] ++ storage_nodes - ) - |> LedgerOperations.consume_inputs(tx.address, inputs) - - validation_stamp = - %ValidationStamp{ - timestamp: DateTime.utc_now(), - proof_of_work: Crypto.first_node_public_key(), - proof_of_integrity: TransactionChain.proof_of_integrity([tx]), - proof_of_election: - Election.validation_nodes_election_seed_sorting(tx, DateTime.utc_now()), - ledger_operations: ledger_operations - } - |> ValidationStamp.sign() - - cross_validation_stamp = - CrossValidationStamp.sign( - %CrossValidationStamp{}, - validation_stamp - ) - - %{tx | validation_stamp: validation_stamp, cross_validation_stamps: [cross_validation_stamp]} - end - - def create_transaction_with_invalid_node_movements(_context, inputs) do - tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) - - ledger_operations = - %LedgerOperations{ - fee: Fee.calculate(tx, 0.07), - node_movements: [ - %NodeMovement{ - to: Crypto.last_node_public_key(), - amount: 2_000_000_000, - roles: [:coordinator_node] - }, - %NodeMovement{to: "key3", amount: 2_000_000_000, roles: [:cross_validation_node]}, - %NodeMovement{to: "key4", amount: 2_000_000_000, roles: [:previous_storage_node]} - ] - } |> LedgerOperations.consume_inputs(tx.address, inputs) validation_stamp =