blockchain v0.1.1 Blockchain.Block
This module effective encodes a Block, the heart of the blockchain. A chain is formed when blocks point to previous blocks, either as a parent or an ommer (uncle). For more information, see Section 4.4 of the Yellow Paper.
Link to this section Summary
Functions
Attaches an ommer to a block. We do no validation at this stage
For a given block, this will add the given transactions to its list of transaction and update the header state accordingly. That is, we will execute each transaction and update the state root, transaction receipts, etc. We effectively implement Eq.(2), Eq.(3) and Eq.(4) of the Yellow Paper, referred to as Π
Decodes a block from an RLP encoding. Effectively inverts L_B defined in Eq.(33)
Creates a new block from a parent block. This will handle setting
the block number, the difficulty and will keep the gas_limit
the
same as the parent’s block unless specified in opts
Returns a given block from the database, if the node exists in the database
Returns the cumulative gas used by a block based on the listed transactions. This is defined in largely in the note after Eq.(66) referenced as l(B_R)_u, or the last receipt’s cumulative gas
Gets an ommer for a given block, based on the ommers_hash
Returns the parent node for a given block, if it exists
Returns a given receipt from a block. This is based on the receipts root where all receipts are stored for the given block
Returns a given transaction from a block. This is based on the transactions root where all transactions are stored for the given block
Returns the total number of transactions included in a block. This is based on the transaction list for a given block
Computes hash of a block
Checks the validity of a block, including the validity of the header and the transactions. This should verify that we should accept the authenticity of a block
Determines whether or not a block is valid. This is defined in Eq.(29) of the Yellow Paper
Stores a given block in the database
Updates a block by adding a receipt to the list of receipts
at position i
Updates a block by adding a transaction to the list of transactions
and updating the transactions_root in the header at position i
, which
should be equilvant to the current number of transactions
Encodes a block such that it can be represented in
RLP encoding. This is defined as L_B
Eq.(33) in the Yellow Paper
Set the difficulty of a new block based on Eq.(39), better defined in Blockchain.Block.Header`
Sets the gas limit of a given block, or raises if the block limit is not acceptable. The validity check is defined in Eq.(45), Eq.(46) and Eq.(47) of the Yellow Paper
Calculates the number
for a new block. This implements Eq.(38) from
the Yellow Paper
Link to this section Types
t() :: %Blockchain.Block{block_hash: EVM.hash | nil, header: Blockchain.Block.Header.t, ommers: [Blockchain.Block.Header.t], transactions: [Blockchain.Transaction.t]}
Link to this section Functions
add_ommers_to_block(t, [Blockchain.Block.Header.t], MerklePatriciaTree.DB.db) :: t
Attaches an ommer to a block. We do no validation at this stage.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> Blockchain.Block.add_ommers_to_block(%Blockchain.Block{}, [%Blockchain.Block.Header{parent_hash: <<1::256>>, ommers_hash: <<2::256>>, beneficiary: <<3::160>>, state_root: <<4::256>>, transactions_root: <<5::256>>, receipts_root: <<6::256>>, logs_bloom: <<>>, difficulty: 5, number: 1, gas_limit: 5, gas_used: 3, timestamp: 6, extra_data: "Hi mom", mix_hash: <<7::256>>, nonce: <<8::64>>}], db)
%Blockchain.Block{ommers: [%Blockchain.Block.Header{parent_hash: <<1::256>>, ommers_hash: <<2::256>>, beneficiary: <<3::160>>, state_root: <<4::256>>, transactions_root: <<5::256>>, receipts_root: <<6::256>>, logs_bloom: <<>>, difficulty: 5, number: 1, gas_limit: 5, gas_used: 3, timestamp: 6, extra_data: "Hi mom", mix_hash: <<7::256>>, nonce: <<8::64>>}], header: %Blockchain.Block.Header{ommers_hash: <<190, 9, 197, 156, 71, 81, 153, 34, 225, 51, 54, 6, 58, 77, 126, 175, 115, 90, 67, 152, 206, 76, 29, 150, 88, 205, 30, 201, 161, 111, 252, 103>>}}
add_transactions_to_block(t, [Blockchain.Transaction.t], MerklePatriciaTree.DB.db) :: t
For a given block, this will add the given transactions to its list of transaction and update the header state accordingly. That is, we will execute each transaction and update the state root, transaction receipts, etc. We effectively implement Eq.(2), Eq.(3) and Eq.(4) of the Yellow Paper, referred to as Π.
The trie db refers to where we expect our trie to exist, e.g.
in :ets
or :leveldb
. See MerklePatriciaTree.DB
.
TODO: Add a rich set of test cases in block_test.exs
Examples
# Create a contract
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> beneficiary = <<0x05::160>>
iex> private_key = <<1::256>>
iex> sender = <<82, 43, 246, 253, 8, 130, 229, 143, 111, 235, 9, 107, 65, 65, 123, 79, 140, 105, 44, 57>> # based on simple private key
iex> contract_address = Blockchain.Contract.new_contract_address(sender, 6)
iex> machine_code = EVM.MachineCode.compile([:push1, 3, :push1, 5, :add, :push1, 0x00, :mstore, :push1, 0, :push1, 32, :return])
iex> trx = %Blockchain.Transaction{nonce: 5, gas_price: 3, gas_limit: 100_000, to: <<>>, value: 5, init: machine_code}
...> |> Blockchain.Transaction.Signature.sign_transaction(private_key)
iex> state = MerklePatriciaTree.Trie.new(db)
...> |> Blockchain.Account.put_account(sender, %Blockchain.Account{balance: 400_000, nonce: 5})
iex> block = %Blockchain.Block{header: %Blockchain.Block.Header{state_root: state.root_hash, beneficiary: beneficiary}, transactions: []}
...> |> Blockchain.Block.add_transactions_to_block([trx], db)
iex> Enum.count(block.transactions)
1
iex> Blockchain.Block.get_receipt(block, 0, db)
%Blockchain.Transaction.Receipt{bloom_filter: "", cumulative_gas: 53756, logs: "", state: block.header.state_root}
iex> Blockchain.Block.get_transaction(block, 0, db)
%Blockchain.Transaction{data: "", gas_limit: 100000, gas_price: 3, init: <<96, 3, 96, 5, 1, 96, 0, 82, 96, 0, 96, 32, 243>>, nonce: 5, r: 110274197540583527170567040609004947678532096020311055824363076718114581104395, s: 15165203061950746568488278734700551064641299899120962819352765267479743108366, to: "", v: 27, value: 5}
iex> MerklePatriciaTree.Trie.new(db, block.header.state_root)
...> |> Blockchain.Account.get_accounts([sender, beneficiary, contract_address])
[%Blockchain.Account{balance: 238727, nonce: 6}, %Blockchain.Account{balance: 161268}, %Blockchain.Account{balance: 5, code_hash: <<184, 49, 71, 53, 90, 147, 31, 209, 13, 252, 14, 242, 188, 146, 213, 98, 3, 169, 138, 178, 91, 23, 65, 191, 149, 7, 79, 68, 207, 121, 218, 225>>}]
Decodes a block from an RLP encoding. Effectively inverts L_B defined in Eq.(33).
Examples
iex> Blockchain.Block.deserialize([
...> [<<1::256>>, <<2::256>>, <<3::160>>, <<4::256>>, <<5::256>>, <<6::256>>, <<>>, <<5>>, <<1>>, <<5>>, <<3>>, <<6>>, "Hi mom", <<7::256>>, <<8::64>>],
...> [[<<5>>, <<6>>, <<7>>, <<1::160>>, <<8>>, "hi", <<27>>, <<9>>, <<10>>]],
...> [[<<11::256>>, <<12::256>>, <<13::160>>, <<14::256>>, <<15::256>>, <<16::256>>, <<>>, <<5>>, <<1>>, <<5>>, <<3>>, <<6>>, "Hi mom", <<17::256>>, <<18::64>>]]
...> ])
%Blockchain.Block{
header: %Blockchain.Block.Header{parent_hash: <<1::256>>, ommers_hash: <<2::256>>, beneficiary: <<3::160>>, state_root: <<4::256>>, transactions_root: <<5::256>>, receipts_root: <<6::256>>, logs_bloom: <<>>, difficulty: 5, number: 1, gas_limit: 5, gas_used: 3, timestamp: 6, extra_data: "Hi mom", mix_hash: <<7::256>>, nonce: <<8::64>>},
transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: "hi"}],
ommers: [%Blockchain.Block.Header{parent_hash: <<11::256>>, ommers_hash: <<12::256>>, beneficiary: <<13::160>>, state_root: <<14::256>>, transactions_root: <<15::256>>, receipts_root: <<16::256>>, logs_bloom: <<>>, difficulty: 5, number: 1, gas_limit: 5, gas_used: 3, timestamp: 6, extra_data: "Hi mom", mix_hash: <<17::256>>, nonce: <<18::64>>}]
}
gen_child_block(t, [timestamp: EVM.timestamp, gas_limit: EVM.val, beneficiary: EVM.address, extra_data: binary, state_root: EVM.hash]) :: t
Creates a new block from a parent block. This will handle setting
the block number, the difficulty and will keep the gas_limit
the
same as the parent’s block unless specified in opts
.
A timestamp is required for difficulty calculation. If it’s not specified, it will default to the current system time.
This function is not directly addressed in the Yellow Paper.
Examples
iex> %Blockchain.Block{header: %Blockchain.Block.Header{state_root: <<1::256>>, number: 100_000, difficulty: 131072, timestamp: 5000, gas_limit: 500_000}}
...> |> Blockchain.Block.gen_child_block(timestamp: 5010, extra_data: "hi", beneficiary: <<5::160>>)
%Blockchain.Block{header: %Blockchain.Block.Header{state_root: <<1::256>>, beneficiary: <<5::160>>, number: 100_001, difficulty: 131136, timestamp: 5010, gas_limit: 500_000, extra_data: "hi"}}
iex> %Blockchain.Block{header: %Blockchain.Block.Header{state_root: <<1::256>>, number: 100_000, difficulty: 131072, timestamp: 5000, gas_limit: 500_000}}
...> |> Blockchain.Block.gen_child_block(state_root: <<2::256>>, timestamp: 5010, extra_data: "hi", beneficiary: <<5::160>>)
%Blockchain.Block{header: %Blockchain.Block.Header{state_root: <<2::256>>, beneficiary: <<5::160>>, number: 100_001, difficulty: 131136, timestamp: 5010, gas_limit: 500_000, extra_data: "hi"}}
get_block(EVM.hash, MerklePatriciaTree.DB.db) :: {:ok, t} | :not_found
Returns a given block from the database, if the node exists in the database.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> Blockchain.Block.get_block(<<1, 2, 3>>, db)
:not_found
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> block = %Blockchain.Block{
...> transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: "hi"}],
...> header: %Blockchain.Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}
...> }
iex> Blockchain.Block.put_block(block, db)
iex> Blockchain.Block.get_block(block |> Blockchain.Block.hash, db)
{:ok, %Blockchain.Block{
transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: "hi"}],
header: %Blockchain.Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}
}}
Returns the cumulative gas used by a block based on the listed transactions. This is defined in largely in the note after Eq.(66) referenced as l(B_R)_u, or the last receipt’s cumulative gas.
The receipts aren’t directly included in the block, so we’ll need to pull it from the receipts root.
Note: this will case if we do not have a receipt for the most recent transaction.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{transactions: [1,2,3,4,5,6,7]}
...> |> Blockchain.Block.put_receipt(6, %Blockchain.Transaction.Receipt{state: <<1, 2, 3>>, cumulative_gas: 10, bloom_filter: <<2, 3, 4>>, logs: "hi mom"}, db)
...> |> Blockchain.Block.put_receipt(7, %Blockchain.Transaction.Receipt{state: <<4, 5, 6>>, cumulative_gas: 11, bloom_filter: <<5, 6, 7>>, logs: "hi dad"}, db)
...> |> Blockchain.Block.get_cumulative_gas(db)
11
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{transactions: [1,2,3,4,5,6]}
...> |> Blockchain.Block.put_receipt(6, %Blockchain.Transaction.Receipt{state: <<1, 2, 3>>, cumulative_gas: 10, bloom_filter: <<2, 3, 4>>, logs: "hi mom"}, db)
...> |> Blockchain.Block.put_receipt(7, %Blockchain.Transaction.Receipt{state: <<4, 5, 6>>, cumulative_gas: 11, bloom_filter: <<5, 6, 7>>, logs: "hi dad"}, db)
...> |> Blockchain.Block.get_cumulative_gas(db)
10
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{}
...> |> Blockchain.Block.get_cumulative_gas(db)
0
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{transactions: [1,2,3,4,5,6,7,8]}
...> |> Blockchain.Block.put_receipt(6, %Blockchain.Transaction.Receipt{state: <<1, 2, 3>>, cumulative_gas: 10, bloom_filter: <<2, 3, 4>>, logs: "hi mom"}, db)
...> |> Blockchain.Block.put_receipt(7, %Blockchain.Transaction.Receipt{state: <<4, 5, 6>>, cumulative_gas: 11, bloom_filter: <<5, 6, 7>>, logs: "hi dad"}, db)
...> |> Blockchain.Block.get_cumulative_gas(db)
** (RuntimeError) cannot find receipt
get_ommer(t, integer, MerklePatriciaTree.DB.db) :: Blockchain.Block.Header.t
Gets an ommer for a given block, based on the ommers_hash.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{}
...> |> Blockchain.Block.add_ommers_to_block([%Blockchain.Block.Header{parent_hash: <<1::256>>, ommers_hash: <<2::256>>, beneficiary: <<3::160>>, state_root: <<4::256>>, transactions_root: <<5::256>>, receipts_root: <<6::256>>, logs_bloom: <<>>, difficulty: 5, number: 1, gas_limit: 5, gas_used: 3, timestamp: 6, extra_data: "Hi mom", mix_hash: <<7::256>>, nonce: <<8::64>>}], db)
...> |> Blockchain.Block.get_ommer(0, db)
%Blockchain.Block.Header{parent_hash: <<1::256>>, ommers_hash: <<2::256>>, beneficiary: <<3::160>>, state_root: <<4::256>>, transactions_root: <<5::256>>, receipts_root: <<6::256>>, logs_bloom: <<>>, difficulty: 5, number: 1, gas_limit: 5, gas_used: 3, timestamp: 6, extra_data: "Hi mom", mix_hash: <<7::256>>, nonce: <<8::64>>}
get_parent_block(t, MerklePatriciaTree.DB.db) :: {:ok, t} | :genesis | :not_found
Returns the parent node for a given block, if it exists.
We assume a block is a genesis block if it does not have
a valid parent_hash
set.
Examples
iex> Blockchain.Block.get_parent_block(%Blockchain.Block{}, nil)
:genesis
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> block = %Blockchain.Block{header: %Blockchain.Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}}
iex> Blockchain.Block.put_block(block, db)
iex> Blockchain.Block.get_parent_block(%Blockchain.Block{header: %Blockchain.Block.Header{parent_hash: block |> Blockchain.Block.hash}}, db)
{:ok, %Blockchain.Block{header: %Blockchain.Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}}}
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> block = %Blockchain.Block{header: %Blockchain.Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}}
iex> Blockchain.Block.get_parent_block(%Blockchain.Block{header: %Blockchain.Block.Header{parent_hash: block |> Blockchain.Block.hash}}, db)
:not_found
get_receipt(t, integer, MerklePatriciaTree.DB.db) :: Blockchain.Transaction.Receipt.t | nil
Returns a given receipt from a block. This is based on the receipts root where all receipts are stored for the given block.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{}
...> |> Blockchain.Block.put_receipt(6, %Blockchain.Transaction.Receipt{state: <<1, 2, 3>>, cumulative_gas: 10, bloom_filter: <<2, 3, 4>>, logs: "hi mom"}, db)
...> |> Blockchain.Block.put_receipt(7, %Blockchain.Transaction.Receipt{state: <<4, 5, 6>>, cumulative_gas: 11, bloom_filter: <<5, 6, 7>>, logs: "hi dad"}, db)
...> |> Blockchain.Block.get_receipt(6, db)
%Blockchain.Transaction.Receipt{state: <<1, 2, 3>>, cumulative_gas: 10, bloom_filter: <<2, 3, 4>>, logs: "hi mom"}
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{}
...> |> Blockchain.Block.put_receipt(6, %Blockchain.Transaction.Receipt{state: <<1, 2, 3>>, cumulative_gas: 10, bloom_filter: <<2, 3, 4>>, logs: "hi mom"}, db)
...> |> Blockchain.Block.get_receipt(7, db)
nil
get_transaction(t, integer, MerklePatriciaTree.DB.db) :: Blockchain.Transaction.t | nil
Returns a given transaction from a block. This is based on the transactions root where all transactions are stored for the given block.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{}
...> |> Blockchain.Block.put_transaction(6, %Blockchain.Transaction{nonce: 1, v: 1, r: 2, s: 3}, db)
...> |> Blockchain.Block.put_transaction(7, %Blockchain.Transaction{nonce: 2, v: 1, r: 2, s: 3}, db)
...> |> Blockchain.Block.get_transaction(6, db)
%Blockchain.Transaction{nonce: 1, v: 1, r: 2, s: 3}
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{}
...> |> Blockchain.Block.put_transaction(6, %Blockchain.Transaction{data: "", gas_limit: 100000, gas_price: 3, init: <<96, 3, 96, 5, 1, 96, 0, 82, 96, 0, 96, 32, 243>>, nonce: 5, r: 110274197540583527170567040609004947678532096020311055824363076718114581104395, s: 15165203061950746568488278734700551064641299899120962819352765267479743108366, to: "", v: 27, value: 5}, db)
...> |> Blockchain.Block.get_transaction(6, db)
%Blockchain.Transaction{data: "", gas_limit: 100000, gas_price: 3, init: <<96, 3, 96, 5, 1, 96, 0, 82, 96, 0, 96, 32, 243>>, nonce: 5, r: 110274197540583527170567040609004947678532096020311055824363076718114581104395, s: 15165203061950746568488278734700551064641299899120962819352765267479743108366, to: "", v: 27, value: 5}
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> %Blockchain.Block{}
...> |> Blockchain.Block.put_transaction(6, %Blockchain.Transaction{nonce: 1, v: 1, r: 2, s: 3}, db)
...> |> Blockchain.Block.get_transaction(7, db)
nil
Returns the total number of transactions included in a block. This is based on the transaction list for a given block.
Examples
iex> Blockchain.Block.get_transaction_count(%Blockchain.Block{transactions: [%Blockchain.Transaction{}, %Blockchain.Transaction{}]})
2
Computes hash of a block
TODO: Make better, a lot better
Examples
iex> %Blockchain.Block{header: %Blockchain.Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}}
...> |> Blockchain.Block.hash()
<<68, 49, 193, 242, 44, 38, 138, 251, 173, 218, 208, 122, 65, 243, 58, 62, 238, 9, 129, 60, 160, 52, 44, 197, 160, 36, 207, 136, 17, 170, 157, 230>>
is_fully_valid?(t, t, MerklePatriciaTree.DB.db) :: :valid | {:invalid, [atom]}
Checks the validity of a block, including the validity of the header and the transactions. This should verify that we should accept the authenticity of a block.
TODO: Add examples
is_holistic_valid?(t, t, MerklePatriciaTree.DB.db) :: :valid | {:invalid, [atom]}
Determines whether or not a block is valid. This is defined in Eq.(29) of the Yellow Paper.
Note, this is a serious intensive operation, and not faint of heart (since we need to run all transaction in the block to validate the block).
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> beneficiary = <<0x05::160>>
iex> private_key = <<1::256>>
iex> sender = <<82, 43, 246, 253, 8, 130, 229, 143, 111, 235, 9, 107, 65, 65, 123, 79, 140, 105, 44, 57>> # based on simple private key
iex> machine_code = EVM.MachineCode.compile([:push1, 3, :push1, 5, :add, :push1, 0x00, :mstore, :push1, 0, :push1, 32, :return])
iex> trx = %Blockchain.Transaction{nonce: 5, gas_price: 3, gas_limit: 100_000, to: <<>>, value: 5, init: machine_code}
...> |> Blockchain.Transaction.Signature.sign_transaction(private_key)
iex> state = MerklePatriciaTree.Trie.new(db)
...> |> Blockchain.Account.put_account(sender, %Blockchain.Account{balance: 400_000, nonce: 5})
iex> parent_block = %Blockchain.Block{header: %Blockchain.Block.Header{number: 50, state_root: state.root_hash, difficulty: 50_000, timestamp: 9999, gas_limit: 125_001}}
iex> block = Blockchain.Block.gen_child_block(parent_block, beneficiary: beneficiary, timestamp: 10000, gas_limit: 125_001)
...> |> Blockchain.Block.add_transactions_to_block([trx], db)
iex> Blockchain.Block.is_holistic_valid?(block, parent_block, db)
:valid
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> beneficiary = <<0x05::160>>
iex> private_key = <<1::256>>
iex> sender = <<82, 43, 246, 253, 8, 130, 229, 143, 111, 235, 9, 107, 65, 65, 123, 79, 140, 105, 44, 57>> # based on simple private key
iex> machine_code = EVM.MachineCode.compile([:push1, 3, :push1, 5, :add, :push1, 0x00, :mstore, :push1, 0, :push1, 32, :return])
iex> trx = %Blockchain.Transaction{nonce: 5, gas_price: 3, gas_limit: 100_000, to: <<>>, value: 5, init: machine_code}
...> |> Blockchain.Transaction.Signature.sign_transaction(private_key)
iex> state = MerklePatriciaTree.Trie.new(db)
...> |> Blockchain.Account.put_account(sender, %Blockchain.Account{balance: 400_000, nonce: 5})
iex> parent_block = %Blockchain.Block{header: %Blockchain.Block.Header{number: 50, state_root: state.root_hash, difficulty: 50_000, timestamp: 9999, gas_limit: 125_001}}
iex> block = Blockchain.Block.gen_child_block(parent_block, beneficiary: beneficiary, timestamp: 10000, gas_limit: 125_001)
...> |> Blockchain.Block.add_transactions_to_block([trx], db)
iex> %{block | header: %{block.header | state_root: <<1,2,3>>, ommers_hash: <<2,3,4>>, transactions_root: <<3,4,5>>, receipts_root: <<4,5,6>>}}
...> |> Blockchain.Block.is_holistic_valid?(parent_block, db)
{:invalid, [:state_root_mismatch, :ommers_hash_mismatch, :transactions_root_mismatch, :receipts_root_mismatch]}
put_block(t, MerklePatriciaTree.DB.db) :: {:ok, EVM.hash}
Stores a given block in the database.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> block = %Blockchain.Block{header: %Blockchain.Block.Header{number: 5, parent_hash: <<1, 2, 3>>, beneficiary: <<2, 3, 4>>, difficulty: 100, timestamp: 11, mix_hash: <<1>>, nonce: <<2>>}}
iex> Blockchain.Block.put_block(block, db)
{:ok, <<68, 49, 193, 242, 44, 38, 138, 251, 173, 218, 208, 122, 65, 243, 58, 62, 238, 9, 129, 60, 160, 52, 44, 197, 160, 36, 207, 136, 17, 170, 157, 230>>}
iex> MerklePatriciaTree.DB.get(db, block |> Blockchain.Block.hash)
{:ok, <<220, 217, 131, 1, 2, 3, 129, 128, 131, 2, 3, 4, 129, 128, 129, 128, 129, 128, 128, 100, 5, 128, 128, 11, 128, 1, 2, 192, 192>>}
put_receipt(t, integer, Blockchain.Transaction.Receipt.t, MerklePatriciaTree.DB.db) :: t
Updates a block by adding a receipt to the list of receipts
at position i
.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> block = Blockchain.Block.put_receipt(%Blockchain.Block{}, 5, %Blockchain.Transaction.Receipt{state: <<1, 2, 3>>, cumulative_gas: 10, bloom_filter: <<2, 3, 4>>, logs: "hi mom"}, db)
iex> MerklePatriciaTree.Trie.new(db, block.header.receipts_root)
...> |> MerklePatriciaTree.Trie.Inspector.all_values()
[{<<5>>, <<208, 131, 1, 2, 3, 10, 131, 2, 3, 4, 134, 104, 105, 32, 109, 111, 109>>}]
put_transaction(t, integer, Blockchain.Transaction.t, MerklePatriciaTree.DB.db) :: t
Updates a block by adding a transaction to the list of transactions
and updating the transactions_root in the header at position i
, which
should be equilvant to the current number of transactions.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db()
iex> block = Blockchain.Block.put_transaction(%Blockchain.Block{}, 0, %Blockchain.Transaction{nonce: 1, v: 2, r: 3, s: 4}, db)
iex> block.transactions
[%Blockchain.Transaction{nonce: 1, v: 2, r: 3, s: 4}]
iex> MerklePatriciaTree.Trie.new(db, block.header.transactions_root)
...> |> MerklePatriciaTree.Trie.Inspector.all_values()
[{<<0x80>>, <<201, 1, 128, 128, 128, 128, 128, 2, 3, 4>>}]
Encodes a block such that it can be represented in
RLP encoding. This is defined as L_B
Eq.(33) in the Yellow Paper.
Examples
iex> Blockchain.Block.serialize(%Blockchain.Block{ …> header: %Blockchain.Block.Header{parent_hash: <<1::256>>, ommers_hash: <<2::256>>, beneficiary: <<3::160>>, state_root: <<4::256>>, transactions_root: <<5::256>>, receipts_root: <<6::256>>, logs_bloom: <<>>, difficulty: 5, number: 1, gas_limit: 5, gas_used: 3, timestamp: 6, extra_data: “Hi mom”, mix_hash: <<7::256>>, nonce: <<8::64>>}, …> transactions: [%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1::160>>, value: 8, v: 27, r: 9, s: 10, data: “hi”}], …> ommers: [%Blockchain.Block.Header{parent_hash: <<11::256>>, ommers_hash: <<12::256>>, beneficiary: <<13::160>>, state_root: <<14::256>>, transactions_root: <<15::256>>, receipts_root: <<16::256>>, logs_bloom: <<>>, difficulty: 5, number: 1, gas_limit: 5, gas_used: 3, timestamp: 6, extra_data: “Hi mom”, mix_hash: <<17::256>>, nonce: <<18::64>>}] …> }) [
[<<1::256>>, <<2::256>>, <<3::160>>, <<4::256>>, <<5::256>>, <<6::256>>, <<>>, 5, 1, 5, 3, 6, "Hi mom", <<7::256>>, <<8::64>>],
[[5, 6, 7, <<1::160>>, 8, "hi", 27, 9, 10]],
[[<<11::256>>, <<12::256>>, <<13::160>>, <<14::256>>, <<15::256>>, <<16::256>>, <<>>, 5, 1, 5, 3, 6, "Hi mom", <<17::256>>, <<18::64>>]]
]
iex> Blockchain.Block.serialize(%Blockchain.Block{}) [[“”, <<128>>, “”, <<128>>, <<128>>, <<128>>, “”, nil, nil, 0, 0, nil, “”, nil, nil], [], []]
Set the difficulty of a new block based on Eq.(39), better defined in Blockchain.Block.Header`. # TODO: Validate these results ## Examples iex> Blockchain.Block.set_block_difficulty( …> %Blockchain.Block{header: %Blockchain.Block.Header{number: 0, timestamp: 55}}, …> nil …> ) %Blockchain.Block{header: %Blockchain.Block.Header{number: 0, timestamp: 55, difficulty: 131_072}} iex> Blockchain.Block.set_block_difficulty( …> %Blockchain.Block{header: %Blockchain.Block.Header{number: 33, timestamp: 66}}, …> %Blockchain.Block{header: %Blockchain.Block.Header{number: 32, timestamp: 55, difficulty: 300_000}} …> ) %Blockchain.Block{header: %Blockchain.Block.Header{number: 33, timestamp: 66, difficulty: 300_146}}
Sets the gas limit of a given block, or raises if the block limit is not acceptable. The validity check is defined in Eq.(45), Eq.(46) and Eq.(47) of the Yellow Paper.
Examples
iex> Blockchain.Block.set_block_gas_limit(
...> %Blockchain.Block{header: %Blockchain.Block.Header{}},
...> %Blockchain.Block{header: %Blockchain.Block.Header{gas_limit: 1_000_000}},
...> 1_000_500
...> )
%Blockchain.Block{header: %Blockchain.Block.Header{gas_limit: 1_000_500}}
iex> Blockchain.Block.set_block_gas_limit(
...> %Blockchain.Block{header: %Blockchain.Block.Header{}},
...> %Blockchain.Block{header: %Blockchain.Block.Header{gas_limit: 1_000_000}},
...> 2_000_000
...> )
** (RuntimeError) Block gas limit not valid
Calculates the number
for a new block. This implements Eq.(38) from
the Yellow Paper.
Examples
iex> Blockchain.Block.set_block_number(%Blockchain.Block{header: %Blockchain.Block.Header{extra_data: "hello"}}, %Blockchain.Block{header: %Blockchain.Block.Header{number: 32}})
%Blockchain.Block{header: %Blockchain.Block.Header{number: 33, extra_data: "hello"}}