blockchain v0.1.7 Blockchain.Contract
Defines functions on create and making message calls to contracts. The core of the module is to implement Λ and Θ, as defined in Eq.(70) and described in detail in sections 7 and 8 of the Yellow Paper.
Link to this section Summary
Functions
Creates a blank contract prior to initialization code being run, as defined in Eq.(83), Eq.(84) and Eq.(85) of the Yellow Paper
Creates a new contract, as defined in Section 7 Eq.(81) and Eq.(87) of the Yellow Paper as Λ
Creates an execution environment for a create contract call
Creates an execution environment for a message call
Returns the additional cost after creating a new contract
Returns the given function to run given a contract address. This covers selecting a pre-defined function if specified. This is defined in Eq.(106) of the Yellow Paper
Initiates message call by transfering balance from sender to receiver
Executes a message call to a contract, defiend in Section 8 Eq.(99) of the Yellow Paper as Θ
Determines the address of a new contract based on the sender and the sender’s current nonce
Link to this section Functions
create_blank_contract(EVM.state, EVM.address, EVM.address, EVM.Wei.t) :: EVM.state
Creates a blank contract prior to initialization code being run, as defined in Eq.(83), Eq.(84) and Eq.(85) of the Yellow Paper.
We also indirectly cover Eq.(86)
Examples
iex> MerklePatriciaTree.Trie.new(MerklePatriciaTree.Test.random_ets_db())
...> |> Blockchain.Account.put_account(<<0x01::160>>, %Blockchain.Account{balance: 10})
...> |> Blockchain.Contract.create_blank_contract(<<0x02::160>>, <<0x01::160>>, 6)
...> |> Blockchain.Account.get_accounts([<<0x01::160>>, <<0x02::160>>])
[%Blockchain.Account{balance: 4}, %Blockchain.Account{balance: 6}]
create_contract(EVM.state, EVM.address, EVM.address, EVM.Gas.t, EVM.Gas.gas_price, EVM.Wei.t, EVM.MachineCode.t, integer, Block.Header.t) :: {EVM.state, EVM.Gas.t, EVM.SubState.t}
Creates a new contract, as defined in Section 7 Eq.(81) and Eq.(87) of the Yellow Paper as Λ.
We are also inlining Eq.(97) and Eq.(98), I think.
TODO: Block header? “I_H has no special treatment and is determined from the blockchain”
TODO: Do we need to break this function up further?
TODO: Add rich tests in contract_test.exs
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db(:contract_create_test)
iex> {state, _gas, _sub_state} = MerklePatriciaTree.Trie.new(db)
...> |> Blockchain.Account.put_account(<<0x10::160>>, %Blockchain.Account{balance: 11, nonce: 5})
...> |> Blockchain.Contract.create_contract(<<0x10::160>>, <<0x10::160>>, 1000, 1, 5, EVM.MachineCode.compile([:push1, 3, :push1, 5, :add, :push1, 0x00, :mstore, :push1, 32, :push1, 0, :return]), 5, %Block.Header{nonce: 1})
{
%MerklePatriciaTree.Trie{db: {MerklePatriciaTree.DB.ETS, :contract_create_test}, root_hash: <<9, 235, 32, 146, 153, 242, 209, 192, 224, 61, 214, 174, 48, 24, 148, 28, 51, 254, 7, 82, 58, 82, 220, 157, 29, 159, 203, 51, 52, 240, 37, 122>>},
976,
%EVM.SubState{}
}
iex> Blockchain.Account.get_accounts(state, [<<0x10::160>>, Blockchain.Contract.new_contract_address(<<0x10::160>>, 5)])
[%Blockchain.Account{balance: 6, nonce: 5}, %Blockchain.Account{balance: 5, code_hash: <<243, 247, 169, 254, 54, 79, 170, 185, 59, 33, 109, 165, 10, 50, 20, 21, 79, 34, 160, 162, 180, 21, 178, 58, 132, 200, 22, 158, 139, 99, 110, 227>>}]
iex> Blockchain.Account.get_machine_code(state, Blockchain.Contract.new_contract_address(<<0x10::160>>, 5))
{:ok, <<0x08::256>>}
iex> MerklePatriciaTree.Trie.Inspector.all_keys(state) |> Enum.count
2
create_contract_exec_env(EVM.address, EVM.address, EVM.Wei.t, EVM.address, EVM.Wei.t, EVM.MachineCode.t, integer, Block.Header.t, EVM.state) :: EVM.ExecEnv.t
Creates an execution environment for a create contract call.
This is defined in Eq.(88), Eq.(89), Eq.(90), Eq.(91), Eq.(92), Eq.(93), Eq.(94) and Eq.(95) of the Yellow Paper.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db(:create_contract_exec_env)
iex> state = MerklePatriciaTree.Trie.new(db)
iex> Blockchain.Contract.create_contract_exec_env(<<0x01::160>>, <<0x02::160>>, 5, <<0x03::160>>, 6, <<1, 2, 3>>, 14, %Block.Header{nonce: 1}, state)
%EVM.ExecEnv{
address: <<0x01::160>>,
originator: <<0x02::160>>,
gas_price: 5,
data: <<>>,
sender: <<0x03::160>>,
value_in_wei: 6,
machine_code: <<1, 2, 3>>,
stack_depth: 14,
block_interface: %Blockchain.Interface.BlockInterface{block_header: %Block.Header{nonce: 1}, db: {MerklePatriciaTree.DB.ETS, :create_contract_exec_env}},
account_interface: %Blockchain.Interface.AccountInterface{state: %MerklePatriciaTree.Trie{db: {MerklePatriciaTree.DB.ETS, :create_contract_exec_env}, root_hash: <<86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33>>}}
}
create_message_call_exec_env(EVM.address, EVM.address, EVM.address, EVM.Wei.t, EVM.Wei.t, binary, integer, EVM.MachineCode.t, Block.Header.t, EVM.state) :: EVM.ExecEnv.t
Creates an execution environment for a message call.
This is defined in Eq.(107), Eq.(108), Eq.(109), Eq.(110), Eq.(111), Eq.(112), Eq.(113) and Eq.(114) of the Yellow Paper.
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db(:create_message_call_exec_env)
iex> state = MerklePatriciaTree.Trie.new(db)
iex> Blockchain.Contract.create_message_call_exec_env(<<0x01::160>>, <<0x02::160>>, <<0x03::160>>, 4, 5, <<1, 2, 3>>, 14, <<2, 3, 4>>, %Block.Header{nonce: 1}, state)
%EVM.ExecEnv{
address: <<0x03::160>>,
originator: <<0x02::160>>,
gas_price: 4,
data: <<1, 2, 3>>,
sender: <<0x01::160>>,
value_in_wei: 5,
machine_code: <<2, 3, 4>>,
stack_depth: 14,
block_interface: %Blockchain.Interface.BlockInterface{block_header: %Block.Header{nonce: 1}, db: {MerklePatriciaTree.DB.ETS, :create_message_call_exec_env}},
account_interface: %Blockchain.Interface.AccountInterface{state: %MerklePatriciaTree.Trie{db: {MerklePatriciaTree.DB.ETS, :create_message_call_exec_env}, root_hash: <<86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33>>}}
}
get_contract_creation_cost(binary) :: EVM.Wei.t
Returns the additional cost after creating a new contract.
This is defined as Eq.(96) of the Yellow Paper.
TODO: Implement and examples
get_message_call_exec_fun(EVM.address) :: (EVM.Gas.t, EVM.ExecEnv.t -> {EVM.state, EVM.Gas.t, EVM.SubState.t, EVM.VM.output})
Returns the given function to run given a contract address. This covers selecting a pre-defined function if specified. This is defined in Eq.(106) of the Yellow Paper.
Examples
iex> Blockchain.Contract.get_message_call_exec_fun(<<1::160>>)
&EVM.Builtin.run_ecrec/2
iex> Blockchain.Contract.get_message_call_exec_fun(<<2::160>>)
&EVM.Builtin.run_sha256/2
iex> Blockchain.Contract.get_message_call_exec_fun(<<3::160>>)
&EVM.Builtin.run_rip160/2
iex> Blockchain.Contract.get_message_call_exec_fun(<<4::160>>)
&EVM.Builtin.run_id/2
iex> Blockchain.Contract.get_message_call_exec_fun(<<5::160>>)
&EVM.VM.run/2
iex> Blockchain.Contract.get_message_call_exec_fun(<<6::160>>)
&EVM.VM.run/2
initialize_message_call(EVM.state, EVM.address, EVM.address, EVM.Wei.t) :: EVM.state
Initiates message call by transfering balance from sender to receiver.
This covers Eq.(101), Eq.(102), Eq.(103) and Eq.(104) of the Yellow Paper.
Examples
iex> MerklePatriciaTree.Trie.new(MerklePatriciaTree.Test.random_ets_db())
...> |> Blockchain.Account.put_account(<<0x01::160>>, %Blockchain.Account{balance: 10})
...> |> Blockchain.Contract.initialize_message_call(<<0x01::160>>, <<0x02::160>>, 6)
...> |> Blockchain.Account.get_accounts([<<0x01::160>>, <<0x02::160>>])
[%Blockchain.Account{balance: 4}, %Blockchain.Account{balance: 6}]
message_call(EVM.state, EVM.address, EVM.address, EVM.address, EVM.address, EVM.Gas.t, EVM.Gas.gas_price, EVM.Wei.t, EVM.Wei.t, binary, integer, Block.Header.t) :: {EVM.state, EVM.Gas.t, EVM.SubState.t, EVM.VM.output}
Executes a message call to a contract, defiend in Section 8 Eq.(99) of the Yellow Paper as Θ.
We are also inlining Eq.(105).
TODO: Determine whether or not we should be passing in the block header directly.
TODO: Add serious (less trivial) test cases in contract_test.exs
Examples
iex> db = MerklePatriciaTree.Test.random_ets_db(:message_call_test)
iex> {state, _gas, _sub_state, _output} = MerklePatriciaTree.Trie.new(db)
...> |> Blockchain.Account.put_account(<<0x10::160>>, %Blockchain.Account{balance: 10})
...> |> Blockchain.Account.put_account(<<0x20::160>>, %Blockchain.Account{balance: 20})
...> |> Blockchain.Account.put_code(<<0x20::160>>, EVM.MachineCode.compile([:push1, 3, :push1, 5, :add, :push1, 0x00, :mstore, :push1, 32, :push1, 0, :return]))
...> |> Blockchain.Contract.message_call(<<0x10::160>>, <<0x10::160>>, <<0x20::160>>, <<0x20::160>>, 1000, 1, 5, 5, <<1, 2, 3>>, 5, %Block.Header{nonce: 1})
{
%MerklePatriciaTree.Trie{db: {MerklePatriciaTree.DB.ETS, :message_call_test}, root_hash: <<163, 151, 95, 0, 149, 63, 81, 220, 74, 101, 219, 175, 240, 97, 153, 167, 249, 229, 144, 75, 101, 233, 126, 177, 8, 188, 105, 165, 28, 248, 67, 156>>},
976,
%EVM.SubState{},
<<0x08::256>>
}
iex> Blockchain.Account.get_accounts(state, [<<0x10::160>>, <<0x20::160>>])
[%Blockchain.Account{balance: 5}, %Blockchain.Account{balance: 25, code_hash: <<135, 110, 129, 59, 111, 55, 97, 45, 238, 64, 115, 133, 37, 188, 196, 107, 160, 151, 31, 167, 249, 187, 243, 251, 173, 170, 244, 204, 78, 134, 208, 239>>}]
iex> MerklePatriciaTree.Trie.Inspector.all_keys(state) |> Enum.count
2
new_contract_address(EVM.address, integer) :: EVM.address
Determines the address of a new contract based on the sender and the sender’s current nonce.
This is defined as Eq.(82) in the Yellow Paper.
Note: we should use the pre-incremented nonce when calling this function.
Examples
iex> Blockchain.Contract.new_contract_address(<<0x01::160>>, 1)
<<82, 43, 50, 148, 230, 208, 106, 162, 90, 208, 241, 184, 137, 18, 66, 227, 53, 211, 180, 89>>
iex> Blockchain.Contract.new_contract_address(<<0x01::160>>, 2)
<<83, 91, 61, 122, 37, 47, 160, 52, 237, 113, 240, 197, 62, 192, 198, 247, 132, 203, 100, 225>>
iex> Blockchain.Contract.new_contract_address(<<0x02::160>>, 3)
<<30, 208, 147, 166, 216, 88, 183, 173, 67, 180, 70, 173, 88, 244, 201, 236, 9, 101, 145, 49>>