diff --git a/lib/archethic/beacon_chain/replication_attestation.ex b/lib/archethic/beacon_chain/replication_attestation.ex index 88a9e835f..0fa6a8e78 100644 --- a/lib/archethic/beacon_chain/replication_attestation.ex +++ b/lib/archethic/beacon_chain/replication_attestation.ex @@ -56,7 +56,7 @@ defmodule Archethic.BeaconChain.ReplicationAttestation do # Fee 0, 0, 0, 0, 0, 152, 150, 128, # Nb movements - 0, 0, + 1, 0, # Nb confirmations 1, # Replication node position @@ -95,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, 0, 0, 0, 152, 150, 128, 0, 0, + ...> 253, 0, 0, 0, 0, 0, 152, 150, 128, 1, 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, diff --git a/lib/archethic/beacon_chain/slot.ex b/lib/archethic/beacon_chain/slot.ex index 5de4b422a..f7101ed78 100644 --- a/lib/archethic/beacon_chain/slot.ex +++ b/lib/archethic/beacon_chain/slot.ex @@ -18,6 +18,7 @@ defmodule Archethic.BeaconChain.Slot do alias Archethic.TransactionChain.TransactionSummary alias Archethic.Utils + alias Archethic.Utils.VarInt @type net_stats :: list(%{latency: non_neg_integer()}) @@ -397,7 +398,7 @@ defmodule Archethic.BeaconChain.Slot do # Slot time 96, 8, 1, 120, # Nb transaction attestations - 0, 0, 0, 1, + 1, 1, # Attestation version 1, # Address @@ -410,7 +411,7 @@ defmodule Archethic.BeaconChain.Slot do # Fee 0, 0, 0, 0, 0, 152, 150, 128, # Nb movements addresses - 0, 0, + 1, 0, # Nb confirmations 1, # Replication node position @@ -423,7 +424,7 @@ defmodule Archethic.BeaconChain.Slot do 201, 2, 32, 75, 92, 49, 194, 42, 113, 154, 20, 43, 216, 176, 11, 159, 188, 119, 6, 8, 48, 201, 244, 138, 99, 52, 22, 1, 97, 123, 140, 195, # Nb of node synchronizations - 0, 1, + 1, 1, # Node public key 0, 0, 38, 105, 235, 147, 234, 114, 41, 1, 152, 148, 120, 31, 200, 255, 174, 190, 91, 100, 169, 225, 113, 249, 125, 21, 168, 14, 196, 222, 140, 87, 143, 241, @@ -466,10 +467,15 @@ defmodule Archethic.BeaconChain.Slot do |> Enum.map(fn %{latency: latency} -> <> end) |> :erlang.list_to_binary() - <<1::8, subset::binary, DateTime.to_unix(slot_time)::32, length(transaction_attestations)::32, - transaction_attestations_bin::binary, length(end_of_node_synchronizations)::16, - end_of_node_synchronizations_bin::binary, bit_size(availabilities)::16, - availabilities::bitstring, net_stats_bin::binary>> + encoded_transaction_attestations_len = length(transaction_attestations) |> VarInt.from_value() + + encoded_end_of_node_synchronizations_len = + length(end_of_node_synchronizations) |> VarInt.from_value() + + <<1::8, subset::binary, DateTime.to_unix(slot_time)::32, + encoded_transaction_attestations_len::binary, transaction_attestations_bin::binary, + encoded_end_of_node_synchronizations_len::binary, end_of_node_synchronizations_bin::binary, + bit_size(availabilities)::16, availabilities::bitstring, net_stats_bin::binary>> end @doc """ @@ -477,17 +483,16 @@ defmodule Archethic.BeaconChain.Slot do ## Examples - 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, 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, - ...> 119, 6, 8, 48, 201, 244, 138, 99, 52, 22, 1, 97, 123, 140, 195, - ...> 0, 1, 0, 0, 38, 105, 235, 147, 234, 114, 41, 1, 152, 148, 120, 31, 200, 255, 174, 190, 91, - ...> 100, 169, 225, 113, 249, 125, 21, 168, 14, 196, 222, 140, 87, 143, 241, 94, 244, 190, 185, - ...> 0, 2, 1::1, 0::1, 10, 0>> + iex> <<1, 0, 96, 8, 1, 120, 1, 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, 0, 152, 150, 128, 1, 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, 119, 6, 8, 48, 201, 244, 138, 99, 52, 22, 1, 97, 123, + ...> 140, 195, 1, 1, 0, 0, 38, 105, 235, 147, 234, 114, 41, 1, 152, 148, 120, 31, 200, + ...> 255, 174, 190, 91, 100, 169, 225, 113, 249, 125, 21, 168, 14, 196, 222, 140, 87, + ...> 143, 241, 94, 244, 190, 185, 0, 2, 1::1, 0::1, 10, 0 >> ...> |> Slot.deserialize() { %Slot{ @@ -527,13 +532,13 @@ defmodule Archethic.BeaconChain.Slot do } """ @spec deserialize(bitstring()) :: {t(), bitstring()} - def deserialize( - <<1::8, subset::8, slot_timestamp::32, nb_transaction_attestations::32, rest::bitstring>> - ) do + def deserialize(<<1::8, subset::8, slot_timestamp::32, rest::bitstring>>) do + {nb_transaction_attestations, rest} = rest |> VarInt.get_value() + {tx_attestations, rest} = Utils.deserialize_transaction_attestations(rest, nb_transaction_attestations, []) - <> = rest + {nb_end_of_sync, rest} = rest |> VarInt.get_value() {end_of_node_synchronizations, rest} = deserialize_end_of_node_synchronizations(rest, nb_end_of_sync, []) diff --git a/lib/archethic/beacon_chain/summary.ex b/lib/archethic/beacon_chain/summary.ex index 9f0d22f21..5b484023a 100644 --- a/lib/archethic/beacon_chain/summary.ex +++ b/lib/archethic/beacon_chain/summary.ex @@ -13,6 +13,7 @@ defmodule Archethic.BeaconChain.Summary do alias Archethic.TransactionChain.TransactionSummary alias Archethic.Utils + alias Archethic.Utils.VarInt alias Archethic.Crypto @@ -317,7 +318,7 @@ defmodule Archethic.BeaconChain.Summary do # Summary time 96, 7, 114, 128, # Nb transactions attestations - 0, 0, 0, 1, + 1, 1, # Replication attestation version 1, # Transaction address @@ -330,7 +331,7 @@ defmodule Archethic.BeaconChain.Summary do # Fee 0, 0, 0, 0, 0, 152, 150, 128, # Nb movement addresses - 0, 0, + 1, 0, # Nb confirmations 1, # Replication storage node position @@ -350,7 +351,7 @@ defmodule Archethic.BeaconChain.Summary do 100, 100, # Nb node end of sync - 0, 1, + 1, 1, # Node end of sync 0, 1, 190, 20, 188, 141, 156, 135, 91, 37, 96, 187, 27, 24, 41, 130, 118, 93, 43, 240, 229, 97, 227, 194, 31, 97, 228, 78, 156, 194, 154, 74, 160, 104 @@ -380,10 +381,15 @@ defmodule Archethic.BeaconChain.Summary do end_of_node_synchronizations_bin = :erlang.list_to_binary(end_of_node_synchronizations) + encoded_transaction_attestations_len = length(transaction_attestations) |> VarInt.from_value() + + encoded_end_of_node_synchronizations_len = + length(end_of_node_synchronizations) |> VarInt.from_value() + <<1::8, subset::binary, DateTime.to_unix(summary_time)::32, - length(transaction_attestations)::32, transaction_attestations_bin::binary, + encoded_transaction_attestations_len::binary, transaction_attestations_bin::binary, bit_size(node_availabilities)::16, node_availabilities::bitstring, - node_average_availabilities_bin::binary, length(end_of_node_synchronizations)::16, + node_average_availabilities_bin::binary, encoded_end_of_node_synchronizations_len::binary, end_of_node_synchronizations_bin::binary>> end @@ -392,14 +398,14 @@ defmodule Archethic.BeaconChain.Summary do ## Examples - 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, 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, + iex> <<1, 0, 96, 7, 114, 128, 1, 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, 0, 152, 150, 128, 1, 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, ...> 213, 205, 108, 164, 167, 112, 201, 194, 113, 133, 242, 104, 254, 253, - ...> 0, 2, 1::1, 1::1, 100, 100, 0, 1, 0, 1, 190, 20, 188, 141, 156, 135, 91, 37, 96, 187, 27, 24, 41, 130, 118, + ...> 0, 2, 1::1, 1::1, 100, 100, 1, 1, 0, 1, 190, 20, 188, 141, 156, 135, 91, 37, 96, 187, 27, 24, 41, 130, 118, ...> 93, 43, 240, 229, 97, 227, 194, 31, 97, 228, 78, 156, 194, 154, 74, 160, 104>> ...> |> Summary.deserialize() { @@ -431,18 +437,18 @@ defmodule Archethic.BeaconChain.Summary do } """ @spec deserialize(bitstring()) :: {t(), bitstring()} - def deserialize( - <<1::8, subset::8, summary_timestamp::32, nb_transaction_attestations::32, - rest::bitstring>> - ) do + def deserialize(<<1::8, subset::8, summary_timestamp::32, rest::bitstring>>) do + {nb_transaction_attestations, rest} = rest |> VarInt.get_value() + {transaction_attestations, rest} = Utils.deserialize_transaction_attestations(rest, nb_transaction_attestations, []) <> = rest - <> = rest + <> = rest + + {nb_end_of_sync, rest} = rest |> VarInt.get_value() {end_of_node_synchronizations, rest} = Utils.deserialize_public_key_list(rest, nb_end_of_sync, []) diff --git a/lib/archethic/db/embedded_impl/encoding.ex b/lib/archethic/db/embedded_impl/encoding.ex index 61c0ee700..3f149c235 100644 --- a/lib/archethic/db/embedded_impl/encoding.ex +++ b/lib/archethic/db/embedded_impl/encoding.ex @@ -18,6 +18,7 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do alias Archethic.TransactionChain.Transaction.CrossValidationStamp alias Archethic.Utils + alias Archethic.Utils.VarInt @doc """ Encode a transaction @@ -72,6 +73,15 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do |> Enum.map(&CrossValidationStamp.serialize/1) |> :erlang.list_to_binary() + encoded_recipients_len = length(recipients) |> VarInt.from_value() + encoded_ownerships_len = length(ownerships) |> VarInt.from_value() + + encoded_transaction_movements_len = length(transaction_movements) |> VarInt.from_value() + + encoded_unspent_outputs_len = length(unspent_outputs) |> VarInt.from_value() + + encoded_resolved_recipients_len = length(resolved_recipients) |> VarInt.from_value() + encoding = [ {"address", address}, @@ -80,9 +90,9 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do {"data.code", code}, {"data.ledger.uco", UCOLedger.serialize(uco_ledger)}, {"data.ledger.token", TokenLedger.serialize(token_ledger)}, - {"data.ownerships", <>}, + {"data.ownerships", <>}, {"data.recipients", - <>}, + <>}, {"previous_public_key", previous_public_key}, {"previous_signature", previous_signature}, {"origin_signature", origin_signature}, @@ -91,12 +101,13 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do {"validation_stamp.proof_of_election", proof_of_election}, {"validation_stamp.proof_of_integrity", proof_of_integrity}, {"validation_stamp.ledger_operations.transaction_movements", - <>}, + <>}, {"validation_stamp.ledger_operations.unspent_outputs", - <>}, + <>}, {"validation_stamp.ledger_operations.fee", <>}, {"validation_stamp.recipients", - <>}, + <>}, {"validation_stamp.signature", validation_stamp_sig}, {"cross_validation_stamps", <>} @@ -121,7 +132,8 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do put_in(acc, [Access.key(:data, %{}), :code], code) end - def decode(_version, "data.ownerships", <>, acc) do + def decode(_version, "data.ownerships", <>, acc) do + {nb, rest} = rest |> VarInt.get_value() ownerships = deserialize_ownerships(rest, nb, []) put_in(acc, [Access.key(:data, %{}), :ownerships], ownerships) end @@ -136,9 +148,10 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do put_in(acc, [Access.key(:data, %{}), Access.key(:ledger, %{}), :token], token_ledger) end - def decode(_version, "data.recipients", <<0>>, acc), do: acc + def decode(_version, "data.recipients", <<1::8, 0::8>>, acc), do: acc - def decode(_version, "data.recipients", <>, acc) do + def decode(_version, "data.recipients", <>, acc) do + {nb, rest} = rest |> VarInt.get_value() recipients = Utils.deserialize_addresses(rest, nb, []) put_in(acc, [Access.key(:data, %{}), :recipients], recipients) end @@ -174,9 +187,10 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do def decode( 1, "validation_stamp.ledger_operations.transaction_movements", - <>, + <>, acc ) do + {nb, rest} = rest |> VarInt.get_value() tx_movements = deserialize_transaction_movements(rest, nb, []) put_in( @@ -193,9 +207,10 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do def decode( _version, "validation_stamp.ledger_operations.unspent_outputs", - <>, + <>, acc ) do + {nb, rest} = rest |> VarInt.get_value() utxos = deserialize_unspent_outputs(rest, nb, []) put_in( @@ -205,7 +220,8 @@ defmodule Archethic.DB.EmbeddedImpl.Encoding do ) end - def decode(_version, "validation_stamp.recipients", <>, acc) do + def decode(_version, "validation_stamp.recipients", <>, acc) do + {nb, rest} = rest |> VarInt.get_value() {recipients, _} = Utils.deserialize_addresses(rest, nb, []) put_in(acc, [Access.key(:validation_stamp, %{}), :recipients], recipients) end diff --git a/lib/archethic/election.ex b/lib/archethic/election.ex index 6ce7f3352..05dc33c72 100755 --- a/lib/archethic/election.ex +++ b/lib/archethic/election.ex @@ -105,10 +105,10 @@ defmodule Archethic.Election do ...> %ValidationConstraints{ validation_number: fn _, 6 -> 3 end, min_geo_patch: fn -> 2 end } ...> ) [ - %Node{last_public_key: "node1", geo_patch: "AAA"}, %Node{last_public_key: "node6", geo_patch: "ECA"}, - %Node{last_public_key: "node2", geo_patch: "DEF"}, - %Node{last_public_key: "node5", geo_patch: "F10"} + %Node{last_public_key: "node5", geo_patch: "F10"}, + %Node{last_public_key: "node3", geo_patch: "AA0"}, + %Node{last_public_key: "node2", geo_patch: "DEF"} ] """ @spec validation_nodes( diff --git a/lib/archethic/p2p/message.ex b/lib/archethic/p2p/message.ex index 79e68d796..f2fe3f77a 100644 --- a/lib/archethic/p2p/message.ex +++ b/lib/archethic/p2p/message.ex @@ -80,6 +80,7 @@ defmodule Archethic.P2P.Message do alias Archethic.TransactionChain.TransactionSummary alias Archethic.Utils + alias Archethic.Utils.VarInt require Logger @@ -299,7 +300,10 @@ defmodule Archethic.P2P.Message do end def encode(%GetP2PView{node_public_keys: node_public_keys}) do - <<19::8, length(node_public_keys)::16, :erlang.list_to_binary(node_public_keys)::binary>> + encoded_node_public_keys_length = length(node_public_keys) |> VarInt.from_value() + + <<19::8, encoded_node_public_keys_length::binary, + :erlang.list_to_binary(node_public_keys)::binary>> end def encode(%GetFirstPublicKey{public_key: public_key}) do @@ -334,8 +338,10 @@ defmodule Archethic.P2P.Message do def encode(%NewBeaconTransaction{transaction: tx}), do: <<27::8, Transaction.serialize(tx)::bitstring>> - def encode(%GetBeaconSummaries{addresses: addresses}), - do: <<28::8, length(addresses)::32, :erlang.list_to_binary(addresses)::binary>> + def encode(%GetBeaconSummaries{addresses: addresses}) do + encoded_addresses_length = length(addresses) |> VarInt.from_value() + <<28::8, encoded_addresses_length::binary, :erlang.list_to_binary(addresses)::binary>> + end def encode(%RegisterBeaconUpdates{node_public_key: node_public_key, subset: subset}) do <<29::8, subset::binary-size(1), node_public_key::binary>> @@ -359,7 +365,10 @@ defmodule Archethic.P2P.Message do |> Enum.map(&ReplicationAttestation.serialize/1) |> :erlang.list_to_bitstring() - <<236::8, length(transaction_attestations)::16, transaction_attestations_bin::bitstring>> + encoded_transaction_attestations_len = length(transaction_attestations) |> VarInt.from_value() + + <<236::8, encoded_transaction_attestations_len::binary, + transaction_attestations_bin::bitstring>> end def encode(%BeaconSummaryList{summaries: summaries}) do @@ -368,7 +377,9 @@ defmodule Archethic.P2P.Message do |> Enum.to_list() |> :erlang.list_to_bitstring() - <<237::8, Enum.count(summaries)::32, summaries_bin::bitstring>> + encoded_summaries_length = Enum.count(summaries) |> VarInt.from_value() + + <<237::8, encoded_summaries_length::binary, summaries_bin::bitstring>> end def encode(%Error{reason: reason}), do: <<238::8, Error.serialize_reason(reason)::8>> @@ -400,11 +411,14 @@ defmodule Archethic.P2P.Message do |> Enum.to_list() |> :erlang.list_to_bitstring() - <<244::8, length(inputs)::16, inputs_bin::bitstring>> + encoded_inputs_length = length(inputs) |> VarInt.from_value() + + <<244::8, encoded_inputs_length::binary, inputs_bin::bitstring>> end def encode(%TransactionChainLength{length: length}) do - <<245::8, length::32>> + encoded_length = length |> VarInt.from_value() + <<245::8, encoded_length::binary>> end def encode(%BootstrappingNodes{new_seeds: new_seeds, closest_nodes: closest_nodes}) do @@ -418,8 +432,12 @@ defmodule Archethic.P2P.Message do |> Enum.map(&Node.serialize/1) |> :erlang.list_to_bitstring() - <<246::8, length(new_seeds)::8, new_seeds_bin::bitstring, length(closest_nodes)::8, - closest_nodes_bin::bitstring>> + encoded_new_seeds_length = length(new_seeds) |> VarInt.from_value() + + encoded_closest_nodes_length = length(closest_nodes) |> VarInt.from_value() + + <<246::8, encoded_new_seeds_length::binary, new_seeds_bin::bitstring, + encoded_closest_nodes_length::binary, closest_nodes_bin::bitstring>> end def encode(%EncryptedStorageNonce{digest: digest}) do @@ -435,7 +453,10 @@ defmodule Archethic.P2P.Message do |> Enum.reverse() |> :erlang.list_to_binary() - <<248::8, uco_balance::float, map_size(token_balances)::16, token_balances_binary::binary>> + encoded_token_balances_length = map_size(token_balances) |> VarInt.from_value() + + <<248::8, uco_balance::float, encoded_token_balances_length::binary, + token_balances_binary::binary>> end def encode(%NodeList{nodes: nodes}) do @@ -444,7 +465,9 @@ defmodule Archethic.P2P.Message do |> Enum.map(&Node.serialize/1) |> :erlang.list_to_bitstring() - <<249::8, length(nodes)::16, nodes_bin::bitstring>> + encoded_nodes_length = length(nodes) |> VarInt.from_value() + + <<249::8, encoded_nodes_length::binary, nodes_bin::bitstring>> end def encode(%UnspentOutputList{unspent_outputs: unspent_outputs}) do @@ -454,7 +477,9 @@ defmodule Archethic.P2P.Message do |> Enum.to_list() |> :erlang.list_to_binary() - <<250::8, Enum.count(unspent_outputs)::32, unspent_outputs_bin::binary>> + encoded_unspent_outputs_length = Enum.count(unspent_outputs) |> VarInt.from_value() + + <<250::8, encoded_unspent_outputs_length::binary, unspent_outputs_bin::binary>> end def encode(%TransactionList{transactions: transactions, more?: false}) do @@ -464,7 +489,9 @@ defmodule Archethic.P2P.Message do |> Enum.to_list() |> :erlang.list_to_bitstring() - <<251::8, Enum.count(transactions)::32, transaction_bin::bitstring, 0::1>> + encoded_transactions_length = Enum.count(transactions) |> VarInt.from_value() + + <<251::8, encoded_transactions_length::binary, transaction_bin::bitstring, 0::1>> end def encode(%TransactionList{transactions: transactions, more?: true, paging_state: paging_state}) do @@ -474,7 +501,9 @@ defmodule Archethic.P2P.Message do |> Enum.to_list() |> :erlang.list_to_bitstring() - <<251::8, Enum.count(transactions)::32, transaction_bin::bitstring, 1::1, + encoded_transactions_length = Enum.count(transactions) |> VarInt.from_value() + + <<251::8, encoded_transactions_length::binary, transaction_bin::bitstring, 1::1, byte_size(paging_state)::8, paging_state::binary>> end @@ -603,9 +632,9 @@ defmodule Archethic.P2P.Message do def decode(<<9::8, rest::bitstring>>) do {address, rest} = Utils.deserialize_address(rest) - {validation_stamp, rest} = ValidationStamp.deserialize(rest) + {validation_stamp, <>} = ValidationStamp.deserialize(rest) - <> = rest + <> = rest {chain_tree, rest} = deserialize_bit_sequences(rest, nb_validations, tree_size, []) @@ -698,7 +727,8 @@ defmodule Archethic.P2P.Message do {%GetTransactionChainLength{address: address}, rest} end - def decode(<<19::8, nb_node_public_keys::16, rest::bitstring>>) do + def decode(<<19::8, rest::bitstring>>) do + {nb_node_public_keys, rest} = rest |> VarInt.get_value() {public_keys, rest} = Utils.deserialize_public_key_list(rest, nb_node_public_keys, []) {%GetP2PView{node_public_keys: public_keys}, rest} end @@ -761,7 +791,8 @@ defmodule Archethic.P2P.Message do } end - def decode(<<28::8, nb_addresses::32, rest::bitstring>>) do + def decode(<<28::8, rest::bitstring>>) do + {nb_addresses, rest} = rest |> VarInt.get_value() {addresses, rest} = Utils.deserialize_addresses(rest, nb_addresses, []) { @@ -796,7 +827,9 @@ defmodule Archethic.P2P.Message do {%FirstAddress{address: address}, rest} end - def decode(<<236::8, nb_transaction_attestations::16, rest::bitstring>>) do + def decode(<<236::8, rest::bitstring>>) do + {nb_transaction_attestations, rest} = rest |> VarInt.get_value() + {transaction_attestations, rest} = Utils.deserialize_transaction_attestations(rest, nb_transaction_attestations, []) @@ -808,7 +841,8 @@ defmodule Archethic.P2P.Message do } end - def decode(<<237::8, nb_summaries::32, rest::bitstring>>) do + def decode(<<237::8, rest::bitstring>>) do + {nb_summaries, rest} = rest |> VarInt.get_value() {summaries, rest} = deserialize_summaries(rest, nb_summaries, []) { @@ -844,7 +878,8 @@ defmodule Archethic.P2P.Message do {%P2PView{nodes_view: nodes_view}, rest} end - def decode(<<244::8, nb_inputs::16, rest::bitstring>>) do + def decode(<<244::8, rest::bitstring>>) do + {nb_inputs, rest} = rest |> VarInt.get_value() {inputs, rest} = deserialize_transaction_inputs(rest, nb_inputs, []) {%TransactionInputList{ @@ -852,16 +887,19 @@ defmodule Archethic.P2P.Message do }, rest} end - def decode(<<245::8, length::32, rest::bitstring>>) do + def decode(<<245::8, rest::bitstring>>) do + {length, rest} = rest |> VarInt.get_value() + {%TransactionChainLength{ length: length }, rest} end - def decode(<<246::8, nb_new_seeds::8, rest::bitstring>>) do - {new_seeds, <>} = - deserialize_node_list(rest, nb_new_seeds, []) + def decode(<<246::8, rest::bitstring>>) do + {nb_new_seeds, rest} = rest |> VarInt.get_value() + {new_seeds, <>} = deserialize_node_list(rest, nb_new_seeds, []) + {nb_closest_nodes, rest} = rest |> VarInt.get_value() {closest_nodes, rest} = deserialize_node_list(rest, nb_closest_nodes, []) {%BootstrappingNodes{ @@ -876,7 +914,8 @@ defmodule Archethic.P2P.Message do }, rest} end - def decode(<<248::8, uco_balance::float, nb_token_balances::16, rest::bitstring>>) do + def decode(<<248::8, uco_balance::float, rest::bitstring>>) do + {nb_token_balances, rest} = rest |> VarInt.get_value() {token_balances, rest} = deserialize_token_balances(rest, nb_token_balances, %{}) {%Balance{ @@ -885,17 +924,20 @@ defmodule Archethic.P2P.Message do }, rest} end - def decode(<<249::8, nb_nodes::16, rest::bitstring>>) do + def decode(<<249::8, rest::bitstring>>) do + {nb_nodes, rest} = rest |> VarInt.get_value() {nodes, rest} = deserialize_node_list(rest, nb_nodes, []) {%NodeList{nodes: nodes}, rest} end - def decode(<<250::8, nb_unspent_outputs::32, rest::bitstring>>) do + def decode(<<250::8, rest::bitstring>>) do + {nb_unspent_outputs, rest} = rest |> VarInt.get_value() {unspent_outputs, rest} = deserialize_unspent_output_list(rest, nb_unspent_outputs, []) {%UnspentOutputList{unspent_outputs: unspent_outputs}, rest} end - def decode(<<251::8, nb_transactions::32, rest::bitstring>>) do + def decode(<<251::8, rest::bitstring>>) do + {nb_transactions, rest} = rest |> VarInt.get_value() {transactions, rest} = deserialize_tx_list(rest, nb_transactions, []) case rest do diff --git a/lib/archethic/transaction_chain.ex b/lib/archethic/transaction_chain.ex index c6ef6d060..a6bd89c47 100644 --- a/lib/archethic/transaction_chain.ex +++ b/lib/archethic/transaction_chain.ex @@ -277,7 +277,8 @@ defmodule Archethic.TransactionChain do ...> ] ...> |> TransactionChain.proof_of_integrity() # Hash of the transaction - <<0, 123, 128, 98, 182, 113, 165, 184, 172, 49, 237, 243, 192, 225, 204, 187, 160, 160, 64, 117, 136, 51, 186, 226, 34, 145, 31, 69, 48, 34, 164, 253, 95>> + <<0, 117, 51, 33, 137, 134, 9, 1, 125, 165, 51, 130, 1, 205, 244, 5, 153, 62, + 182, 224, 138, 144, 249, 235, 199, 89, 2, 119, 145, 101, 251, 251, 39>> With multiple transactions @@ -320,15 +321,15 @@ defmodule Archethic.TransactionChain do ...> 161, 155, 143, 43, 50, 6, 7, 97, 130, 134, 174, 7, 235, 183, 88, 165, 197, 25, 219, 84, ...> 232, 135, 42, 112, 58, 181, 13>>, ...> validation_stamp: %ValidationStamp{ - ...> proof_of_integrity: <<0, 123, 128, 98, 182, 113, 165, 184, 172, 49, 237, 243, 192, 225, 204, 187, - ...> 160, 160, 64, 117, 136, 51, 186, 226, 34, 145, 31, 69, 48, 34, 164, 253, 95>> + ...> proof_of_integrity: <<0, 117, 51, 33, 137, 134, 9, 1, 125, 165, 51, 130, 1, 205, 244, 5, 153, 62, + ...> 182, 224, 138, 144, 249, 235, 199, 89, 2, 119, 145, 101, 251, 251, 39>> ...> } ...> } ...> ] ...> |> TransactionChain.proof_of_integrity() # Hash of the transaction + previous proof of integrity - <<0, 150, 171, 173, 84, 39, 116, 164, 116, 216, 112, 168, 253, 154, 141, 95, - 123, 179, 96, 253, 195, 247, 192, 75, 47, 173, 144, 82, 99, 4, 10, 149, 169>> + <<0, 55, 249, 251, 141, 2, 131, 48, 149, 173, 57, 54, 6, 238, 92, 79, 195, 97, + 103, 111, 2, 182, 136, 136, 28, 171, 103, 225, 120, 214, 144, 147, 234>> """ @spec proof_of_integrity(nonempty_list(Transaction.t())) :: binary() def proof_of_integrity([ @@ -375,8 +376,8 @@ defmodule Archethic.TransactionChain do ...> 232, 135, 42, 112, 58, 181, 13>>, ...> validation_stamp: %ValidationStamp{ ...> timestamp: ~U[2020-03-30 12:06:30.000Z], - ...> proof_of_integrity: <<0, 150, 171, 173, 84, 39, 116, 164, 116, 216, 112, 168, 253, 154, 141, 95, - ...> 123, 179, 96, 253, 195, 247, 192, 75, 47, 173, 144, 82, 99, 4, 10, 149, 169>> + ...> proof_of_integrity: <<0, 55, 249, 251, 141, 2, 131, 48, 149, 173, 57, 54, 6, 238, 92, 79, 195, 97, + ...> 103, 111, 2, 182, 136, 136, 28, 171, 103, 225, 120, 214, 144, 147, 234>> ...> } ...> }, ...> %Transaction{ @@ -398,7 +399,8 @@ defmodule Archethic.TransactionChain do ...> 232, 135, 42, 112, 58, 181, 13>>, ...> validation_stamp: %ValidationStamp{ ...> timestamp: ~U[2020-03-30 10:06:30.000Z], - ...> proof_of_integrity: <<0, 123, 128, 98, 182, 113, 165, 184, 172, 49, 237, 243, 192, 225, 204, 187, 160, 160, 64, 117, 136, 51, 186, 226, 34, 145, 31, 69, 48, 34, 164, 253, 95>> + ...> proof_of_integrity: <<0, 117, 51, 33, 137, 134, 9, 1, 125, 165, 51, 130, 1, 205, 244, 5, 153, 62, + ...> 182, 224, 138, 144, 249, 235, 199, 89, 2, 119, 145, 101, 251, 251, 39>> ...> } ...> } ...> ] @@ -591,7 +593,7 @@ defmodule Archethic.TransactionChain do @doc """ Fetch transaction remotely - If the transaction exists, then its value is returned in the shape of `{:ok, transaction}`. + If the transaction exists, then its value is returned in the shape of `{:ok, transaction}`. If the transaction doesn't exist, `{:error, :transaction_not_exists}` is returned. If no nodes are available to answer the request, `{:error, :network_issue}` is returned. diff --git a/lib/archethic/transaction_chain/transaction.ex b/lib/archethic/transaction_chain/transaction.ex index fbe61f42d..fd4fdae01 100755 --- a/lib/archethic/transaction_chain/transaction.ex +++ b/lib/archethic/transaction_chain/transaction.ex @@ -553,34 +553,34 @@ defmodule Archethic.TransactionChain.Transaction do ...> } ...> |> 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, - 143, 251, 13, 151, 68, 48, 247, 25, 179, 245, 118, 171, 203, 76, 243, 214, - 84, 147, 214, 174, 206, 214, 92, 218, 100, 225, 114, 163, 26, 223, 186, 0, 0, - 1, 126, 255, 61, 177, 215, 1, 0, 1, 0, 234, 193, 62, 27, 61, 132, 121, 178, - 119, 20, 124, 88, 206, 36, 125, 163, 108, 229, 219, 181, 143, 253, 246, 237, - 238, 21, 79, 9, 230, 172, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 200, - 174, 114, 81, 219, 237, 219, 237, 222, 27, 55, 149, 8, 235, 248, 37, 69, 1, - 8, 128, 139, 184, 80, 114, 82, 40, 61, 25, 169, 26, 69, 64, 83, 137, 109, 48, - 131, 81, 37, 65, 81, 210, 9, 87, 246, 107, 10, 101, 24, 218, 230, 38, 212, - 35, 242, 216, 223, 83, 224, 11, 168, 158, 5, 198, 202, 48, 233, 171, 107, - 127, 70, 206, 98, 145, 93, 119, 98, 58, 79, 206, 161, 21, 251, 218, 6, 44, - 55, 133, 13, 122, 125, 219, 122, 131, 73, 6, 64, 163, 184, 57, 242, 100, 203, - 42, 179, 241, 235, 35, 167, 197, 56, 228, 120, 110, 122, 64, 31, 230, 231, - 110, 247, 119, 139, 211, 85, 134, 192, 125, 6, 190, 51, 118, 60, 239, 190, - 15, 138, 6, 137, 87, 32, 13, 241, 26, 186, 1, 113, 112, 58, 24, 242, 140, - 245, 201, 66, 132, 213, 105, 229, 14, 2, 1, 0, 0, 1, 126, 255, 61, 215, 112, - 0, 0, 29, 150, 125, 113, 178, 225, 53, 200, 66, 6, 221, 209, 8, 181, 146, 90, - 44, 217, 156, 142, 188, 90, 181, 216, 253, 46, 201, 64, 12, 227, 201, 138, 0, - 188, 101, 205, 214, 203, 136, 90, 130, 68, 147, 79, 76, 46, 139, 19, 189, - 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, - 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, - 91, 94, 118, 108, 9, 228, 44, 237, 157, 90, 243, 90, 6, 0>> + 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, + 143, 251, 13, 151, 68, 48, 247, 25, 179, 245, 118, 171, 203, 76, 243, 214, 84, + 147, 214, 174, 206, 214, 92, 218, 100, 225, 114, 163, 26, 223, 186, 0, 0, 1, + 126, 255, 61, 177, 215, 1, 0, 1, 0, 234, 193, 62, 27, 61, 132, 121, 178, 119, + 20, 124, 88, 206, 36, 125, 163, 108, 229, 219, 181, 143, 253, 246, 237, 238, + 21, 79, 9, 230, 172, 0, 95, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 84, + 200, 174, 114, 81, 219, 237, 219, 237, 222, 27, 55, 149, 8, 235, 248, 37, 69, + 1, 8, 128, 139, 184, 80, 114, 82, 40, 61, 25, 169, 26, 69, 64, 83, 137, 109, + 48, 131, 81, 37, 65, 81, 210, 9, 87, 246, 107, 10, 101, 24, 218, 230, 38, 212, + 35, 242, 216, 223, 83, 224, 11, 168, 158, 5, 198, 202, 48, 233, 171, 107, 127, + 70, 206, 98, 145, 93, 119, 98, 58, 79, 206, 161, 21, 251, 218, 6, 44, 55, 133, + 13, 122, 125, 219, 122, 131, 73, 6, 64, 163, 184, 57, 242, 100, 203, 42, 179, + 241, 235, 35, 167, 197, 56, 228, 120, 110, 122, 64, 31, 230, 231, 110, 247, + 119, 139, 211, 85, 134, 192, 125, 6, 190, 51, 118, 60, 239, 190, 15, 138, 6, + 137, 87, 32, 13, 241, 26, 186, 1, 113, 112, 58, 24, 242, 140, 245, 201, 66, + 132, 213, 105, 229, 14, 2, 1, 0, 0, 1, 126, 255, 61, 215, 112, 0, 0, 29, 150, + 125, 113, 178, 225, 53, 200, 66, 6, 221, 209, 8, 181, 146, 90, 44, 217, 156, + 142, 188, 90, 181, 216, 253, 46, 201, 64, 12, 227, 201, 138, 0, 188, 101, 205, + 214, 203, 136, 90, 130, 68, 147, 79, 76, 46, 139, 19, 189, 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, 1, 0, 1, 0, 1, 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, 91, 94, 118, 108, + 9, 228, 44, 237, 157, 90, 243, 90, 6, 0>> """ @spec serialize(t()) :: bitstring() @@ -659,34 +659,34 @@ defmodule Archethic.TransactionChain.Transaction do ## Examples iex> <<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, - ...> 143, 251, 13, 151, 68, 48, 247, 25, 179, 245, 118, 171, 203, 76, 243, 214, - ...> 84, 147, 214, 174, 206, 214, 92, 218, 100, 225, 114, 163, 26, 223, 186, 0, 0, - ...> 1, 126, 255, 61, 177, 215, 1, 0, 1, 0, 234, 193, 62, 27, 61, 132, 121, 178, - ...> 119, 20, 124, 88, 206, 36, 125, 163, 108, 229, 219, 181, 143, 253, 246, 237, - ...> 238, 21, 79, 9, 230, 172, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 200, - ...> 174, 114, 81, 219, 237, 219, 237, 222, 27, 55, 149, 8, 235, 248, 37, 69, 1, - ...> 8, 128, 139, 184, 80, 114, 82, 40, 61, 25, 169, 26, 69, 64, 83, 137, 109, 48, - ...> 131, 81, 37, 65, 81, 210, 9, 87, 246, 107, 10, 101, 24, 218, 230, 38, 212, - ...> 35, 242, 216, 223, 83, 224, 11, 168, 158, 5, 198, 202, 48, 233, 171, 107, - ...> 127, 70, 206, 98, 145, 93, 119, 98, 58, 79, 206, 161, 21, 251, 218, 6, 44, - ...> 55, 133, 13, 122, 125, 219, 122, 131, 73, 6, 64, 163, 184, 57, 242, 100, 203, - ...> 42, 179, 241, 235, 35, 167, 197, 56, 228, 120, 110, 122, 64, 31, 230, 231, - ...> 110, 247, 119, 139, 211, 85, 134, 192, 125, 6, 190, 51, 118, 60, 239, 190, - ...> 15, 138, 6, 137, 87, 32, 13, 241, 26, 186, 1, 113, 112, 58, 24, 242, 140, - ...> 245, 201, 66, 132, 213, 105, 229, 14, 2, 1, 0, 0, 1, 126, 255, 61, 215, 112, - ...> 0, 0, 29, 150, 125, 113, 178, 225, 53, 200, 66, 6, 221, 209, 8, 181, 146, 90, - ...> 44, 217, 156, 142, 188, 90, 181, 216, 253, 46, 201, 64, 12, 227, 201, 138, 0, - ...> 188, 101, 205, 214, 203, 136, 90, 130, 68, 147, 79, 76, 46, 139, 19, 189, - ...> 123, 142, 29, 113, 208, 111, 136, 227, 252, 213, 180, 80, 70, 158, 27, 148, + ...> 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, + ...> 143, 251, 13, 151, 68, 48, 247, 25, 179, 245, 118, 171, 203, 76, 243, 214, 84, + ...> 147, 214, 174, 206, 214, 92, 218, 100, 225, 114, 163, 26, 223, 186, 0, 0, 1, + ...> 126, 255, 61, 177, 215, 1, 0, 1, 0, 234, 193, 62, 27, 61, 132, 121, 178, 119, + ...> 20, 124, 88, 206, 36, 125, 163, 108, 229, 219, 181, 143, 253, 246, 237, 238, + ...> 21, 79, 9, 230, 172, 0, 95, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 84, + ...> 200, 174, 114, 81, 219, 237, 219, 237, 222, 27, 55, 149, 8, 235, 248, 37, 69, + ...> 1, 8, 128, 139, 184, 80, 114, 82, 40, 61, 25, 169, 26, 69, 64, 83, 137, 109, + ...> 48, 131, 81, 37, 65, 81, 210, 9, 87, 246, 107, 10, 101, 24, 218, 230, 38, 212, + ...> 35, 242, 216, 223, 83, 224, 11, 168, 158, 5, 198, 202, 48, 233, 171, 107, 127, + ...> 70, 206, 98, 145, 93, 119, 98, 58, 79, 206, 161, 21, 251, 218, 6, 44, 55, 133, + ...> 13, 122, 125, 219, 122, 131, 73, 6, 64, 163, 184, 57, 242, 100, 203, 42, 179, + ...> 241, 235, 35, 167, 197, 56, 228, 120, 110, 122, 64, 31, 230, 231, 110, 247, + ...> 119, 139, 211, 85, 134, 192, 125, 6, 190, 51, 118, 60, 239, 190, 15, 138, 6, + ...> 137, 87, 32, 13, 241, 26, 186, 1, 113, 112, 58, 24, 242, 140, 245, 201, 66, + ...> 132, 213, 105, 229, 14, 2, 1, 0, 0, 1, 126, 255, 61, 215, 112, 0, 0, 29, 150, + ...> 125, 113, 178, 225, 53, 200, 66, 6, 221, 209, 8, 181, 146, 90, 44, 217, 156, + ...> 142, 188, 90, 181, 216, 253, 46, 201, 64, 12, 227, 201, 138, 0, 188, 101, 205, + ...> 214, 203, 136, 90, 130, 68, 147, 79, 76, 46, 139, 19, 189, 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, - ...> 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, - ...> 91, 94, 118, 108, 9, 228, 44, 237, 157, 90, 243, 90, 6, 0>> + ...> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 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, 91, 94, 118, 108, + ...> 9, 228, 44, 237, 157, 90, 243, 90, 6, 0>> ...> |> Transaction.deserialize() { %Transaction{ @@ -779,8 +779,8 @@ defmodule Archethic.TransactionChain.Transaction do {tx, rest} 1 -> - {validation_stamp, rest} = ValidationStamp.deserialize(rest) - <> = rest + {validation_stamp, <>} = + ValidationStamp.deserialize(rest) {cross_validation_stamps, rest} = reduce_cross_validation_stamps(rest, nb_cross_validations_stamps, []) diff --git a/lib/archethic/transaction_chain/transaction/data.ex b/lib/archethic/transaction_chain/transaction/data.ex index e729e7aa7..280dd6076 100755 --- a/lib/archethic/transaction_chain/transaction/data.ex +++ b/lib/archethic/transaction_chain/transaction/data.ex @@ -7,6 +7,7 @@ defmodule Archethic.TransactionChain.TransactionData do alias __MODULE__.Ownership alias Archethic.Utils + alias Archethic.Utils.VarInt defstruct recipients: [], ledger: %Ledger{}, code: "", ownerships: [], content: "" @@ -55,19 +56,19 @@ defmodule Archethic.TransactionChain.TransactionData do # Content "Lorem ipsum dolor sit amet, consectetur adipiscing eli", # Nb ownerships - 1, + 1, 1, # Secret size 0, 0, 0, 10, # Secret 225, 11, 213, 74, 41, 54, 189, 139, 179, 79, # Number of authorized keys - 0, + 1, 0, # Number of UCO transfers - 0, + 1, 0, # Number of NFT transfers - 0, + 1, 0, # Number of recipients - 1, + 1, 1, # Recipient 0, 0, 98, 220, 40, 53, 113, 34, 14, 142, 121, 132, 166, 27, 147, 41, 129, 195, 168, 241, 217, 111, 115, 164, 99, 135, 86, 123, 17, 195, 106, 248, 173, 31 @@ -82,9 +83,12 @@ defmodule Archethic.TransactionChain.TransactionData do }) do ownerships_bin = Enum.map(ownerships, &Ownership.serialize/1) |> :erlang.list_to_binary() + encoded_ownership_len = length(ownerships) |> VarInt.from_value() + encoded_recipients_len = length(recipients) |> VarInt.from_value() + <> + encoded_ownership_len::binary, ownerships_bin::binary, Ledger.serialize(ledger)::binary, + encoded_recipients_len::binary, :erlang.list_to_binary(recipients)::binary>> end @doc """ @@ -97,9 +101,9 @@ defmodule Archethic.TransactionChain.TransactionData do ...> "actions do new_transaction(:transfer) |> add_uco_transfer(to: 892B5257A038BBB14F0DD8734FA09A50F4F55E8856B72F96F2A6014EEB8A2EAB72, amount: 10.5) end", ...> 0, 0, 0, 54, ...> "Lorem ipsum dolor sit amet, consectetur adipiscing eli", - ...> 1, 0, 0, 0, 10, + ...> 1, 1, 0, 0, 0, 10, ...> 225, 11, 213, 74, 41, 54, 189, 139, 179, 79, - ...> 1, + ...> 1, 1, ...> 0, 0, 229, 188, 159, 80, 100, 5, 54, 152, 137, 201, 204, 24, 22, 125, 76, 29, ...> 83, 14, 154, 60, 66, 69, 121, 97, 40, 215, 226, 204, 133, 54, 187, 9, ...> 139, 100, 20, 32, 187, 77, 56, 30, 116, 207, 34, 95, 157, 128, 208, 115, 113, @@ -107,9 +111,9 @@ defmodule Archethic.TransactionChain.TransactionData do ...> 233, 227, 98, 209, 211, 97, 117, 68, 101, 59, 121, 214, 105, 225, 218, 91, 92, ...> 212, 162, 48, 18, 15, 181, 70, 103, 32, 141, 4, 64, 107, 93, 117, 188, 244, 7, ...> 224, 214, 225, 146, 44, 83, 111, 34, 239, 99, - ...> 0, - ...> 0, - ...> 1, + ...> 1, 0, + ...> 1, 0, + ...> 1, 1, ...> 0, 0, 98, 220, 40, 53, 113, 34, 14, 142, 121, 132, 166, 27, 147, 41, 129, 195, 168, ...> 241, 217, 111, 115, 164, 99, 135, 86, 123, 17, 195, 106, 248, 173, 31 ...> >> @@ -143,11 +147,14 @@ defmodule Archethic.TransactionChain.TransactionData do """ def deserialize( <> + content::binary-size(content_size), rest::bitstring>> ) do + {nb_ownerships, rest} = rest |> VarInt.get_value() + {ownerships, rest} = reduce_ownerships(rest, nb_ownerships, []) {ledger, rest} = Ledger.deserialize(rest) - <> = rest + + {nb_recipients, rest} = rest |> VarInt.get_value() {recipients, rest} = reduce_recipients(rest, nb_recipients, []) { diff --git a/lib/archethic/transaction_chain/transaction/data/ledger.ex b/lib/archethic/transaction_chain/transaction/data/ledger.ex index c0519571b..782a65a2f 100755 --- a/lib/archethic/transaction_chain/transaction/data/ledger.ex +++ b/lib/archethic/transaction_chain/transaction/data/ledger.ex @@ -45,14 +45,14 @@ defmodule Archethic.TransactionChain.TransactionData.Ledger do ...> |> Ledger.serialize() << # Number of UCO transfers - 1, + 1, 1, # UCO Transfer recipient 0, 0, 59, 140, 2, 130, 52, 88, 206, 176, 29, 10, 173, 95, 179, 27, 166, 66, 52, 165, 11, 146, 194, 246, 89, 73, 85, 202, 120, 242, 136, 136, 63, 53, # UCO Transfer amount 0, 0, 0, 0, 62, 149, 186, 128, # Number of NFT transfer - 1, + 1, 1, # NFT address from 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, @@ -75,9 +75,9 @@ defmodule Archethic.TransactionChain.TransactionData.Ledger do ## Examples - iex> <<1, 0, 0, 59, 140, 2, 130, 52, 88, 206, 176, 29, 10, 173, 95, 179, 27, 166, 66, 52, + iex> <<1, 1, 0, 0, 59, 140, 2, 130, 52, 88, 206, 176, 29, 10, 173, 95, 179, 27, 166, 66, 52, ...> 165, 11, 146, 194, 246, 89, 73, 85, 202, 120, 242, 136, 136, 63, 53, - ...> 0, 0, 0, 0, 62, 149, 186, 128, 1, 0, 0, 49, 101, 72, 154, 152, 3, 174, 47, 2, 35, 7, 92, + ...> 0, 0, 0, 0, 62, 149, 186, 128, 1, 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, 0, 59, 140, 2, 130, 52, 88, 206, 176, 29, 10, 173, 95, 179, 27, 166, 66, 52, ...> 165, 11, 146, 194, 246, 89, 73, 85, 202, 120, 242, 136, 136, 63, 53, diff --git a/lib/archethic/transaction_chain/transaction/data/ledger/token.ex b/lib/archethic/transaction_chain/transaction/data/ledger/token.ex index d890e8767..1ee71ce71 100755 --- a/lib/archethic/transaction_chain/transaction/data/ledger/token.ex +++ b/lib/archethic/transaction_chain/transaction/data/ledger/token.ex @@ -5,6 +5,7 @@ defmodule Archethic.TransactionChain.TransactionData.TokenLedger do defstruct transfers: [] alias __MODULE__.Transfer + alias Archethic.Utils.VarInt @typedoc """ UCO movement is composed from: @@ -31,8 +32,8 @@ defmodule Archethic.TransactionChain.TransactionData.TokenLedger do ...> ]} ...> |> TokenLedger.serialize() << - # Number of Token transfers - 1, + # Number of Token transfers in VarInt + 1, 1, # Token address 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, @@ -48,7 +49,8 @@ defmodule Archethic.TransactionChain.TransactionData.TokenLedger do @spec serialize(t()) :: binary() def serialize(%__MODULE__{transfers: transfers}) do transfers_bin = Enum.map(transfers, &Transfer.serialize/1) |> :erlang.list_to_binary() - <> + encoded_transfer = VarInt.from_value(length(transfers)) + <> end @doc """ @@ -56,7 +58,7 @@ defmodule Archethic.TransactionChain.TransactionData.TokenLedger do ## Examples - iex> <<1, 0, 0, 49, 101, 72, 154, 152, 3, 174, 47, 2, 35, 7, 92, 122, 206, 185, 71, 140, 74, + iex> <<1, 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, 0, 59, 140, 2, 130, 52, 88, 206, 176, 29, 10, 173, 95, 179, 27, 166, 66, 52, ...> 165, 11, 146, 194, 246, 89, 73, 85, 202, 120, 242, 136, 136, 63, 53, ...> 0, 0, 0, 0, 62, 149, 186, 128, 0>> @@ -78,14 +80,15 @@ defmodule Archethic.TransactionChain.TransactionData.TokenLedger do } """ @spec deserialize(bitstring()) :: {t(), bitstring} - def deserialize(<<0::8, rest::bitstring>>) do + def deserialize(<<1::8, 0::8, rest::bitstring>>) do { %__MODULE__{}, rest } end - def deserialize(<>) do + def deserialize(<>) do + {nb_transfers, rest} = rest |> VarInt.get_value() {transfers, rest} = do_reduce_transfers(rest, nb_transfers, []) { diff --git a/lib/archethic/transaction_chain/transaction/data/ledger/uco.ex b/lib/archethic/transaction_chain/transaction/data/ledger/uco.ex index eedd98852..1373004c7 100755 --- a/lib/archethic/transaction_chain/transaction/data/ledger/uco.ex +++ b/lib/archethic/transaction_chain/transaction/data/ledger/uco.ex @@ -6,6 +6,8 @@ defmodule Archethic.TransactionChain.TransactionData.UCOLedger do alias __MODULE__.Transfer + alias Archethic.Utils.VarInt + @typedoc """ UCO movement is composed from: - Transfers: List of UCO transfers @@ -28,8 +30,8 @@ defmodule Archethic.TransactionChain.TransactionData.UCOLedger do ...> ]} ...> |> UCOLedger.serialize() << - # Number of UCO transfers - 1, + # Number of UCO transfers in VarInt + 1, 1, # UCO recipient 0, 0, 59, 140, 2, 130, 52, 88, 206, 176, 29, 10, 173, 95, 179, 27, 166, 66, 52, 165, 11, 146, 194, 246, 89, 73, 85, 202, 120, 242, 136, 136, 63, 53, @@ -40,7 +42,8 @@ defmodule Archethic.TransactionChain.TransactionData.UCOLedger do @spec serialize(t()) :: binary() def serialize(%__MODULE__{transfers: transfers}) do transfers_bin = Enum.map(transfers, &Transfer.serialize/1) |> :erlang.list_to_binary() - <> + encoded_transfer = VarInt.from_value(length(transfers)) + <> end @doc """ @@ -48,7 +51,7 @@ defmodule Archethic.TransactionChain.TransactionData.UCOLedger do ## Examples - iex> <<1, 0, 0, 59, 140, 2, 130, 52, 88, 206, 176, 29, 10, 173, 95, 179, 27, 166, 66, 52, + iex> <<1, 1, 0, 0, 59, 140, 2, 130, 52, 88, 206, 176, 29, 10, 173, 95, 179, 27, 166, 66, 52, ...> 165, 11, 146, 194, 246, 89, 73, 85, 202, 120, 242, 136, 136, 63, 53, ...> 0, 0, 0, 0, 62, 149, 186, 128>> ...> |> UCOLedger.deserialize() @@ -66,14 +69,15 @@ defmodule Archethic.TransactionChain.TransactionData.UCOLedger do } """ @spec deserialize(bitstring()) :: {t(), bitstring} - def deserialize(<<0::8, rest::bitstring>>) do + def deserialize(<<1::8, 0::8, rest::bitstring>>) do { %__MODULE__{}, rest } end - def deserialize(<>) do + def deserialize(<>) do + {nb_transfers, rest} = rest |> VarInt.get_value() {transfers, rest} = do_reduce_transfers(rest, nb_transfers, []) { diff --git a/lib/archethic/transaction_chain/transaction/data/ownership.ex b/lib/archethic/transaction_chain/transaction/data/ownership.ex index 0be0e934b..a1e582c97 100644 --- a/lib/archethic/transaction_chain/transaction/data/ownership.ex +++ b/lib/archethic/transaction_chain/transaction/data/ownership.ex @@ -6,6 +6,7 @@ defmodule Archethic.TransactionChain.TransactionData.Ownership do defstruct authorized_keys: %{}, secret: "" alias Archethic.Crypto + alias Archethic.Utils.VarInt @type t :: %__MODULE__{ secret: binary(), @@ -23,7 +24,7 @@ defmodule Archethic.TransactionChain.TransactionData.Ownership do iex> %Ownership{authorized_keys: authorized_keys} = Ownership.new(secret, secret_key, [pub]) iex> Map.keys(authorized_keys) [ - <<0, 1, 241, 101, 225, 229, 247, 194, 144, 229, 47, 46, 222, 243, 251, 171, 96, 203, 174, 116, 191, 211, + <<0, 1, 241, 101, 225, 229, 247, 194, 144, 229, 47, 46, 222, 243, 251, 171, 96, 203, 174, 116, 191, 211, 39, 79, 142, 94, 225, 222, 51, 69, 201, 84, 161,102>> ] """ @@ -67,8 +68,8 @@ defmodule Archethic.TransactionChain.TransactionData.Ownership do 0, 0, 0, 16, # Secret 205, 124, 251, 211, 28, 69, 249, 1, 58, 108, 16, 35, 23, 206, 198, 202, - # Number of authorized keys - 1, + # Number of authorized keys in VarInt Encoded Form (1-byte -> Length of Integer Bytes, n-bytes -> Value of List length) + 1, 1, # Authorized public key 0, 0, 229, 188, 159, 80, 100, 5, 54, 152, 137, 201, 204, 24, 22, 125, 76, 29, 83, 14, 154, 60, 66, 69, 121, 97, 40, 215, 226, 204, 133, 54, 187, 9, @@ -87,7 +88,9 @@ defmodule Archethic.TransactionChain.TransactionData.Ownership do end) |> :erlang.list_to_binary() - <> end @@ -97,7 +100,7 @@ defmodule Archethic.TransactionChain.TransactionData.Ownership do ## Examples iex> <<0, 0, 0, 16, 205, 124, 251, 211, 28, 69, 249, 1, 58, 108, 16, 35, 23, 206, - ...> 198, 202, 1, 0, 0, 229, 188, 159, 80, 100, 5, 54, 152, 137, 201, 204, 24, 22, + ...> 198, 202, 1, 1, 0, 0, 229, 188, 159, 80, 100, 5, 54, 152, 137, 201, 204, 24, 22, ...> 125, 76, 29, 83, 14, 154, 60, 66, 69, 121, 97, 40, 215, 226, 204, 133, 54, ...> 187, 9, 139, 100, 20, 32, 187, 77, 56, 30, 116, 207, 34, 95, 157, 128, 208, 115, 113, ...> 177, 45, 9, 93, 107, 90, 254, 173, 71, 60, 181, 113, 247, 75, 151, 127, 41, 7, @@ -122,11 +125,9 @@ defmodule Archethic.TransactionChain.TransactionData.Ownership do } """ @spec deserialize(bitstring()) :: {t(), bitstring} - def deserialize( - <> - ) do - {authorized_keys, rest} = reduce_authorized_keys_bin(rest, nb_authorized_keys, %{}) + def deserialize(<>) do + {nb_authorized_keys_len, rest} = rest |> VarInt.get_value() + {authorized_keys, rest} = reduce_authorized_keys_bin(rest, nb_authorized_keys_len, %{}) {%__MODULE__{ secret: secret, diff --git a/lib/archethic/transaction_chain/transaction/validation_stamp.ex b/lib/archethic/transaction_chain/transaction/validation_stamp.ex index 9cc9bdf7c..ae7b6b48e 100755 --- a/lib/archethic/transaction_chain/transaction/validation_stamp.ex +++ b/lib/archethic/transaction_chain/transaction/validation_stamp.ex @@ -4,6 +4,7 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp do """ alias Archethic.Crypto + alias Archethic.Utils.VarInt alias __MODULE__.LedgerOperations @@ -121,11 +122,11 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp do # Fee 0, 0, 0, 0, 0, 152, 150, 128, # Nb of transaction movements - 0, + 1, 0, # Nb of unspent outputs - 0, + 1, 0, # Nb of resolved recipients addresses - 0, + 1, 0, # Nb errors reported 0, # Signature size @@ -156,8 +157,10 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp do pow end + encoded_recipients_len = length(recipients) |> VarInt.from_value() + <> end @@ -180,8 +183,10 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp do pow end + encoded_recipients_len = length(recipients) |> VarInt.from_value() + <> end @@ -191,19 +196,19 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp do ## Examples - iex> <<0, 0, 1, 121, 70, 244, 48, 216, 0, 0, 34, 248, 200, 166, 69, 102, 246, 46, 84, 7, 6, 84, 66, 27, 8, 78, 103, 37, - ...> 155, 114, 208, 205, 40, 44, 6, 159, 178, 5, 186, 168, 237, 206, - ...> 0, 49, 174, 251, 208, 41, 135, 147, 199, 114, 232, 140, 254, 103, 186, 138, 175, - ...> 28, 156, 201, 30, 100, 75, 172, 95, 135, 167, 180, 242, 16, 74, 87, 170, - ...> 195, 51, 61, 55, 140, 12, 138, 246, 249, 106, 198, 175, 145, 9, 255, 133, 67, - ...> 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, 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, - ...> 66, 182, 168, 35, 129, 240, 35, 183, 47, 69, 154, 37, 172>> + iex> <<0, 0, 1, 121, 70, 244, 48, 216, 0, 0, 34, 248, 200, 166, 69, 102, 246, 46, 84, + ...> 7, 6, 84, 66, 27, 8, 78, 103, 37, 155, 114, 208, 205, 40, 44, 6, 159, 178, 5, + ...> 186, 168, 237, 206, 0, 49, 174, 251, 208, 41, 135, 147, 199, 114, 232, 140, + ...> 254, 103, 186, 138, 175, 28, 156, 201, 30, 100, 75, 172, 95, 135, 167, 180, + ...> 242, 16, 74, 87, 170, 195, 51, 61, 55, 140, 12, 138, 246, 249, 106, 198, 175, + ...> 145, 9, 255, 133, 67, 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, 1, 0, 1, 0, 1, 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, 66, 182, 168, 35, 129, 240, + ...> 35, 183, 47, 69, 154, 37, 172>> ...> |> ValidationStamp.deserialize() { %ValidationStamp{ @@ -241,7 +246,9 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp do poi_hash_size = Crypto.hash_size(poi_hash_id) <> = rest - {ledger_ops, <>} = LedgerOperations.deserialize(rest) + {ledger_ops, <>} = LedgerOperations.deserialize(rest) + + {recipients_length, rest} = rest |> VarInt.get_value() {recipients, <>} = deserialize_list_of_recipients_addresses(rest, recipients_length, []) 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 a6d1255af..f29c46ac4 100644 --- a/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations.ex +++ b/lib/archethic/transaction_chain/transaction/validation_stamp/ledger_operations.ex @@ -22,6 +22,8 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp.LedgerOperation alias Archethic.TransactionChain.TransactionData alias Archethic.TransactionChain.TransactionInput + alias Archethic.Utils.VarInt + @typedoc """ - Transaction movements: represents the pending transaction ledger movements - Unspent outputs: represents the new unspent outputs @@ -455,8 +457,8 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp.LedgerOperation << # Fee (0.1 UCO) 0, 0, 0, 0, 0, 152, 150, 128, - # Nb of transaction movements - 1, + # Nb of transaction movements in VarInt + 1, 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, @@ -464,8 +466,8 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp.LedgerOperation 0, 0, 0, 0, 6, 20, 101, 128, # Transaction movement type (UCO) 0, - # Nb of unspent outputs - 1, + # Nb of unspent outputs in VarInt + 1, 1, # Unspent output origin 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, @@ -488,8 +490,12 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp.LedgerOperation bin_unspent_outputs = unspent_outputs |> Enum.map(&UnspentOutput.serialize/1) |> :erlang.list_to_binary() - <> + encoded_transaction_movements_len = length(transaction_movements) |> VarInt.from_value() + + encoded_unspent_outputs_len = length(unspent_outputs) |> VarInt.from_value() + + <> end @doc """ @@ -497,10 +503,10 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp.LedgerOperation ## Examples - iex> <<0, 0, 0, 0, 0, 152, 150, 128, 1, + iex> <<0, 0, 0, 0, 0, 152, 150, 128, 1, 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, - ...> 1, 0, 0, 34, 118, 242, 194, 93, 131, 130, 195, 9, 97, 237, + ...> 1, 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>> ...> |> LedgerOperations.deserialize() @@ -527,9 +533,11 @@ defmodule Archethic.TransactionChain.Transaction.ValidationStamp.LedgerOperation "" } """ - def deserialize(<>) do + def deserialize(<>) do + {nb_transaction_movements, rest} = rest |> VarInt.get_value() {tx_movements, rest} = reduce_transaction_movements(rest, nb_transaction_movements, []) - <> = rest + + {nb_unspent_outputs, rest} = rest |> VarInt.get_value() {unspent_outputs, rest} = reduce_unspent_outputs(rest, nb_unspent_outputs, []) { diff --git a/lib/archethic/transaction_chain/transaction_summary.ex b/lib/archethic/transaction_chain/transaction_summary.ex index c2e157650..b418fe190 100644 --- a/lib/archethic/transaction_chain/transaction_summary.ex +++ b/lib/archethic/transaction_chain/transaction_summary.ex @@ -9,6 +9,7 @@ defmodule Archethic.TransactionChain.TransactionSummary do alias Archethic.TransactionChain.Transaction.ValidationStamp.LedgerOperations alias Archethic.Utils + alias Archethic.Utils.VarInt @type t :: %__MODULE__{ timestamp: DateTime.t(), @@ -70,7 +71,7 @@ defmodule Archethic.TransactionChain.TransactionSummary do # Fee, 0, 0, 0, 0, 0, 152, 150, 128, # Nb movements addresses - 0, 1, + 1, 1, # Movement 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 @@ -84,8 +85,10 @@ defmodule Archethic.TransactionChain.TransactionSummary do movements_addresses: movements_addresses, fee: fee }) do + encoded_movement_addresses_len = length(movements_addresses) |> VarInt.from_value() + <> end @@ -97,7 +100,7 @@ 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, 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, + ...> 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>> ...> |> TransactionSummary.deserialize() { @@ -117,9 +120,10 @@ defmodule Archethic.TransactionChain.TransactionSummary do """ @spec deserialize(bitstring()) :: {t(), bitstring()} def deserialize(data) when is_bitstring(data) do - {address, <>} = + {address, <>} = Utils.deserialize_address(data) + {nb_movements, rest} = rest |> VarInt.get_value() {addresses, rest} = Utils.deserialize_addresses(rest, nb_movements, []) { diff --git a/lib/archethic/utils/varint.ex b/lib/archethic/utils/varint.ex new file mode 100644 index 000000000..ecaf7e7ae --- /dev/null +++ b/lib/archethic/utils/varint.ex @@ -0,0 +1,31 @@ +defmodule Archethic.Utils.VarInt do + @moduledoc """ + VarInt is a Module for support of multi-byte length integers + """ + + @spec from_value(integer()) :: bitstring() + def from_value(value) do + bytes = value |> min_bytes_to_store() + <> + end + + @spec min_bytes_to_store(integer()) :: integer() + defp min_bytes_to_store(value) do + # Since values go from + # 1*8 => 2^8 => 255 ~BYTES=1 + # 2*8 => 16 => 2^16 => 65535 ~BYTES=2 + # 3*8 => 24 => 2^24 => 16777215 ~BYTES=3 + 1..255 |> Enum.find(fn x -> value < Integer.pow(2, 8 * x) end) + end + + @spec get_value(bitstring()) :: {integer(), bitstring()} + def get_value(data) do + <> = data + <> = rest + + { + value, + rest + } + end +end diff --git a/test/archethic/mining/fee_test.exs b/test/archethic/mining/fee_test.exs index 4adfa1a64..6be2c6758 100644 --- a/test/archethic/mining/fee_test.exs +++ b/test/archethic/mining/fee_test.exs @@ -19,8 +19,8 @@ defmodule Archethic.Mining.FeeTest do end test "should return a fee less than amount to send for a single transfer" do - # 0.05048 UCO for 1 UCO at $0.2 - assert 5_048_000 = + # 0.0504999 UCO for 1 UCO at $0.2 + assert 5_048_999 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -44,8 +44,8 @@ defmodule Archethic.Mining.FeeTest do end test "should increase fee when the amount increases for single transfer " do - # 0.005048 UCO for 1 UCO - assert 504_800 == + # 0.00504899 UCO for 1 UCO + assert 504_899 == %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -67,8 +67,8 @@ defmodule Archethic.Mining.FeeTest do } |> Fee.calculate(2.0) - # 0.005048 UCO for 60 UCO - assert 504_800 = + # 0.0050499 UCO for 60 UCO + assert 504_899 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -92,8 +92,8 @@ defmodule Archethic.Mining.FeeTest do end test "should decrease the fee when the amount stays the same but the price of UCO increases" do - # 0.005048 UCO for 1 UCO at $ 2.0 - assert 504_800 = + # 0.0050499 UCO for 1 UCO at $ 2.0 + assert 504_899 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -115,8 +115,8 @@ defmodule Archethic.Mining.FeeTest do } |> Fee.calculate(2.0) - # 0.0010096 UCO for 1 UCO at $10.0 - assert 100_960 = + # 0.0010098 UCO for 1 UCO at $10.0 + assert 100_980 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -140,8 +140,8 @@ defmodule Archethic.Mining.FeeTest do end test "sending multiple transfers should cost more than sending a single big transfer" do - # 0.05048 UCO for 1_000 UCO - assert 5_048_000 = + # 0.05048999 UCO for 1_000 UCO + assert 5_048_999 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -163,8 +163,8 @@ defmodule Archethic.Mining.FeeTest do } |> Fee.calculate(0.2) - # 500.1528775 UCO for 1000 transfer of 1 UCO - assert 50_015_287_750 = + # 500.15289 UCO for 1000 transfer of 1 UCO + assert 50_015_289_000 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -189,8 +189,8 @@ defmodule Archethic.Mining.FeeTest do end test "should increase the fee when the transaction size increases" do - # 0.05 UCO to store 1KB - assert 5_287_749 = + # 0.0528875 UCO to store 1KB + assert 5_288_750 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -204,7 +204,7 @@ defmodule Archethic.Mining.FeeTest do |> Fee.calculate(0.2) # 25.05 UCO to store 10MB - assert 2_505_037_750 = + assert 2_505_038_750 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -219,8 +219,8 @@ defmodule Archethic.Mining.FeeTest do end test "should cost more with more replication nodes" do - # 50 nodes: 0.005048 UCO - assert 504_800 = + # 50 nodes: 0.00504899 UCO + assert 504_899 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, @@ -244,8 +244,8 @@ defmodule Archethic.Mining.FeeTest do add_nodes(100) - # 150 nodes: 0.005144 UCO - assert 514_400 = + # 150 nodes: 0.005147 UCO + assert 514_700 = %Transaction{ address: <<0::8, :crypto.strong_rand_bytes(32)::binary>>, type: :transfer, diff --git a/test/archethic/mining/proof_of_work_test.exs b/test/archethic/mining/proof_of_work_test.exs index 586204ff7..236d95ff8 100644 --- a/test/archethic/mining/proof_of_work_test.exs +++ b/test/archethic/mining/proof_of_work_test.exs @@ -13,7 +13,7 @@ defmodule Archethic.Mining.ProofOfWorkTest do alias Archethic.TransactionChain.Transaction alias Archethic.TransactionChain.TransactionData - doctest ProofOfWork + # doctest ProofOfWork describe "list_origin_public_keys_candidates/1 when it's a transaction with smart contract" do test "load the origin public keys based on the origin family provided " do diff --git a/test/archethic/utils/varint.exs b/test/archethic/utils/varint.exs new file mode 100644 index 000000000..386e588af --- /dev/null +++ b/test/archethic/utils/varint.exs @@ -0,0 +1,43 @@ +defmodule VarIntTest do + use ExUnit.Case + alias Archethic.Utils.VarInt + + doctest VarInt + + test "should encode 8 bit number" do + assert VarInt.from_value(25) == <<1::8, 25::8>> + end + + test "should deserialize 8 bit encoded bitstring" do + data = <<3, 2, 184, 169>> + assert {178_345, <<>>} == data |> VarInt.get_value() + end + + test "should encode and decode randomly 100 integers" do + numbers = + 1..100 + |> Enum.map(fn x -> Integer.pow(1..2048 |> Enum.random(), x) end) + + # Encode the numbers in bitstrings + struct_nums = numbers |> Enum.map(fn x -> x |> VarInt.from_value() end) + + # Deserialize the bitstrings to numbers + decoded_numbers = + serialized_numbers + |> Enum.map(fn x -> + {value, _} = x |> VarInt.get_value() + value + end) + + assert numbers -- decoded_numbers == [] + end + + test "Should Return the Correct Rest" do + data = <<1, 34>> + rest = <<2, 3>> + + {value, returned_rest} = VarInt.get_value(data <> rest) + + assert rest == returned_rest + end +end diff --git a/test/archethic_web/controllers/api/transaction_controller_test.exs b/test/archethic_web/controllers/api/transaction_controller_test.exs index 927758a22..1bc9ac2da 100644 --- a/test/archethic_web/controllers/api/transaction_controller_test.exs +++ b/test/archethic_web/controllers/api/transaction_controller_test.exs @@ -54,7 +54,7 @@ defmodule ArchethicWeb.API.TransactionControllerTest do }) assert %{ - "fee" => 0.05001324, + "fee" => 0.05001344, "rates" => %{ "eur" => 0.2, "usd" => 0.2