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

Link to this type t()
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

Link to this function add_ommers_to_block(block, ommers, db)

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>>}}
Link to this function add_transactions_to_block(block, transactions, db)
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>>}]
Link to this function deserialize(rlp)
deserialize(ExRLP.t) :: t

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>>}]
}
Link to this function gen_child_block(parent_block, opts \\ [])
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"}}
Link to this function get_block(block_hash, db)
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>>}
}}
Link to this function get_cumulative_gas(block, db)
get_cumulative_gas(t, atom) :: EVM.Gas.t

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
Link to this function get_ommer(block, i, db)

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>>}
Link to this function get_parent_block(block, db)
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
Link to this function get_receipt(block, i, db)

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
Link to this function get_transaction(block, i, db)
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
Link to this function get_transaction_count(block)
get_transaction_count(t) :: integer

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
Link to this function hash(block)
hash(t) :: EVM.hash

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>>
Link to this function identity(block)
identity(t) :: t
Link to this function is_fully_valid?(block, parent_block, db)
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

Link to this function is_holistic_valid?(block, parent_block, db)
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]}
Link to this function put_block(block, db)
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>>}
Link to this function put_receipt(block, i, receipt, db)

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>>}]
Link to this function put_transaction(block, i, trx, db)
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>>}]
Link to this function serialize(block)
serialize(t) :: ExRLP.t

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], [], []]

Link to this function set_block_difficulty(block, parent_block)
set_block_difficulty(t, t) :: t

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}}

Link to this function set_block_gas_limit(block, parent_block, gas_limit)
set_block_gas_limit(t, t, EVM.Gas.t) :: t

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
Link to this function set_block_number(block1, block2)
set_block_number(t, t) :: t

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"}}