Contract creation fixes

This commit is contained in:
Daniel Lubarov 2023-03-20 21:40:58 -07:00
parent 893b88c309
commit afded1682b
9 changed files with 149 additions and 49 deletions

View File

@ -43,4 +43,4 @@ global sys_selfbalance:
%address
%jump(balance)
%%after:
%endmacro
%endmacro

View File

@ -1,3 +1,7 @@
// TODO: This file needs to be cleaned up.
// `create` is no longer being used for contract-creation txns,
// so it can be inlined. Also need to set metadata on new ctx.
// The CREATE syscall.
//
// Pre stack: kexit_info, value, code_offset, code_len
@ -24,8 +28,8 @@ sys_create_finish:
// Note: CODE_ADDR refers to a (context, segment, offset) tuple.
global create:
// stack: sender, endowment, CODE_ADDR, code_len, retdest
// TODO: Charge gas.
DUP1 %get_nonce
DUP1 %nonce
// stack: nonce, sender, endowment, CODE_ADDR, code_len, retdest
// Call get_create_address and have it return to create_inner.
%stack (nonce, sender)
@ -67,12 +71,14 @@ sys_create2_finish:
// Pre stack: address, sender, endowment, CODE_ADDR, code_len, retdest
// Post stack: address
// Note: CODE_ADDR refers to a (context, segment, offset) tuple.
create_inner:
global create_inner:
// stack: address, sender, endowment, CODE_ADDR, code_len, retdest
%stack (address, sender, endowment)
-> (sender, address, endowment, sender, address)
// TODO: Need to handle insufficient balance failure.
%transfer_eth
// stack: transfer_eth_status, sender, address, CODE_ADDR, code_len, retdest
%jumpi(fault_exception)
// stack: sender, address, CODE_ADDR, code_len, retdest
%increment_nonce

View File

@ -5,14 +5,32 @@
// Post stack: address
global get_create_address:
// stack: sender, nonce, retdest
// TODO: Replace with actual implementation.
%pop2
PUSH 123
%alloc_rlp_block
// stack: rlp_start, sender, nonce, retdest
%stack (rlp_start, sender, nonce) -> (rlp_start, sender, nonce, rlp_start)
// stack: rlp_start, sender, nonce, rlp_start, retdest
%encode_rlp_160 // TODO: or encode_rlp_scalar?
// stack: rlp_pos, nonce, rlp_start, retdest
%encode_rlp_scalar
// stack: rlp_pos, rlp_start, retdest
%prepend_rlp_list_prefix
// stack: rlp_prefix_start, rlp_len, retdest
PUSH @SEGMENT_RLP_RAW
PUSH 0 // context
// stack: RLP_ADDR: 3, rlp_len, retdest
KECCAK_GENERAL
// stack: address, retdest
%observe_new_address
SWAP1
JUMP
// Convenience macro to call get_create_address and return where we left off.
%macro get_create_address
%stack (sender, nonce) -> (sender, nonce, %%after)
%jump(get_create_address)
%%after:
%endmacro
// Computes the address for a contract based on the CREATE2 rule, i.e.
// address = KEC(0xff || sender || salt || code_hash)[12:]
//

View File

@ -1,17 +1,21 @@
// Increment the nonce of the given account.
// Get the nonce of the given account.
// Pre stack: address, retdest
// Post stack: (empty)
global get_nonce:
global nonce:
// stack: address, retdest
// TODO: Replace with actual implementation.
POP
JUMP
%mpt_read_state_trie
// stack: account_ptr, retdest
// The nonce is the first account field, so we deref the account pointer itself.
// Note: We don't need to handle account_ptr=0, as trie_data[0] = 0,
// so the deref will give 0 (the default nonce) as desired.
%mload_trie_data
// stack: nonce, retdest
SWAP1 JUMP
// Convenience macro to call get_nonce and return where we left off.
%macro get_nonce
// Convenience macro to call nonce and return where we left off.
%macro nonce
%stack (address) -> (address, %%after)
%jump(get_nonce)
%jump(nonce)
%%after:
%endmacro
@ -20,7 +24,7 @@ global increment_nonce:
// stack: address, retdest
%mpt_read_state_trie
// stack: account_ptr, retdest
DUP1 ISZERO %jumpi(panic)
DUP1 ISZERO %jumpi(increment_nonce_no_such_account)
// stack: nonce_ptr, retdest
DUP1 %mload_trie_data
// stack: nonce, nonce_ptr, retdest
@ -30,6 +34,8 @@ global increment_nonce:
%mstore_trie_data
// stack: retdest
JUMP
global increment_nonce_no_such_account:
PANIC
// Convenience macro to call increment_nonce and return where we left off.
%macro increment_nonce

View File

@ -50,23 +50,76 @@ global process_based_on_type:
global process_contract_creation_txn:
// stack: retdest
PUSH process_contract_creation_txn_after_create
// stack: process_contract_creation_txn_after_create, retdest
%mload_txn_field(@TXN_FIELD_DATA_LEN)
// stack: code_len, process_contract_creation_txn_after_create, retdest
PUSH 0
// stack: code_offset, code_len, process_contract_creation_txn_after_create, retdest
PUSH @SEGMENT_TXN_DATA
// stack: code_segment, code_offset, code_len, process_contract_creation_txn_after_create, retdest
PUSH 0 // context
// stack: CODE_ADDR, code_len, process_contract_creation_txn_after_create, retdest
%mload_txn_field(@TXN_FIELD_ORIGIN)
// stack: origin, retdest
DUP1 %nonce
// stack: origin_nonce, origin, retdest
SWAP1
// stack: origin, origin_nonce, retdest
%get_create_address
// stack: address, retdest
// Deduct value from caller.
%mload_txn_field(@TXN_FIELD_VALUE)
%mload_txn_field(@TXN_FIELD_ORIGIN)
// stack: sender, endowment, CODE_ADDR, code_len, process_contract_creation_txn_after_create, retdest
%jump(create)
%deduct_eth
// stack: deduct_eth_status, address, retdest
%jumpi(panic)
// stack: address, retdest
global process_contract_creation_txn_after_create:
// stack: new_address, retdest
// Write the new account's data to MPT data, and get a pointer to it.
%get_trie_data_size
// stack: account_ptr, address, retdest
PUSH 1 %append_to_trie_data // nonce = 1
// stack: account_ptr, address, retdest
DUP2 %balance %mload_txn_field(@TXN_FIELD_VALUE) ADD %append_to_trie_data // balance = old_balance + txn_value
// stack: account_ptr, address, retdest
PUSH 0 %append_to_trie_data // storage_root = nil
// stack: account_ptr, address, retdest
PUSH @EMPTY_STRING_HASH %append_to_trie_data // code_hash = keccak('')
// stack: account_ptr, address, retdest
DUP2
// stack: address, account_ptr, address, retdest
%mpt_insert_state_trie
// stack: address, retdest
%create_context
// stack: new_ctx, address, retdest
// Copy the code from txdata to the new context's code segment.
PUSH process_contract_creation_txn_after_code_loaded
%mload_txn_field(@TXN_FIELD_DATA_LEN)
PUSH 0 // SRC.offset
PUSH @SEGMENT_TXN_DATA // SRC.segment
PUSH 0 // SRC.context
PUSH 0 // DST.offset
PUSH @SEGMENT_CODE // DST.segment
DUP7 // DST.context = new_ctx
%jump(memcpy)
process_contract_creation_txn_after_code_loaded:
// stack: new_ctx, address, retdest
// Each line in the block below does not change the stack.
DUP2 %set_new_ctx_addr
%mload_txn_field(@TXN_FIELD_ORIGIN) %set_new_ctx_caller
%mload_txn_field(@TXN_FIELD_VALUE) %set_new_ctx_value
%set_new_ctx_parent_ctx
%set_new_ctx_parent_pc(process_contract_creation_txn_after_constructor)
%non_intrinisic_gas %set_new_ctx_gas_limit
// stack: new_ctx, address, retdest
%enter_new_ctx
// (Old context) stack: new_ctx, address, retdest
global process_contract_creation_txn_after_constructor:
// stack: success, leftover_gas, new_ctx, address, retdest
POP // TODO: Success will go into the receipt when we support that.
// stack: leftover_gas, new_ctx, address, retdest
%pay_coinbase_and_refund_sender
// stack: new_ctx, address, retdest
POP
POP
JUMP
@ -105,9 +158,8 @@ global process_message_txn_insufficient_balance:
global process_message_txn_return:
// stack: retdest
%mload_txn_field(@TXN_FIELD_INTRINSIC_GAS)
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
SUB
// Since no code was executed, the leftover gas is the non-intrinsic gas.
%non_intrinisic_gas
// stack: leftover_gas, retdest
%pay_coinbase_and_refund_sender
// stack: retdest
@ -124,18 +176,13 @@ global process_message_txn_code_loaded:
%mload_txn_field(@TXN_FIELD_VALUE) %set_new_ctx_value
%set_new_ctx_parent_ctx
%set_new_ctx_parent_pc(process_message_txn_after_call)
// stack: new_ctx, retdest
// The gas provided to the callee is gas_limit - intrinsic_gas.
%mload_txn_field(@TXN_FIELD_INTRINSIC_GAS)
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
SUB
%set_new_ctx_gas_limit
%non_intrinisic_gas %set_new_ctx_gas_limit
// stack: new_ctx, retdest
// TODO: Copy TXN_DATA to CALLDATA
%enter_new_ctx
// (Old context) stack: new_ctx, retdest
global process_message_txn_after_call:
// stack: success, leftover_gas, new_ctx, retdest
@ -206,3 +253,11 @@ global process_message_txn_after_call:
%mstore_txn_field(@TXN_FIELD_COMPUTED_PRIORITY_FEE_PER_GAS)
// stack: (empty)
%endmacro
%macro non_intrinisic_gas
// stack: (empty)
%mload_txn_field(@TXN_FIELD_INTRINSIC_GAS)
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
SUB
// stack: gas_limit - intrinsic_gas
%endmacro

View File

@ -97,6 +97,15 @@ global terminate_common:
%shr_const(192)
// stack: gas_used
%mload_context_metadata(@CTX_METADATA_GAS_LIMIT)
// stack: gas_limit, gas_used
SWAP1
// stack: gas_used, gas_limit
DUP2 DUP2 LT
// stack: gas_used < gas_limit, gas_used, gas_limit
SWAP2
// stack: gas_limit, gas_used, gas_used < gas_limit
SUB
// stack: leftover_gas
// stack: gas_limit - gas_used, gas_used < gas_limit
MUL
// stack: leftover_gas = (gas_limit - gas_used) * (gas_used < gas_limit)
%endmacro

View File

@ -15,3 +15,9 @@ mpt_insert_state_trie_save:
// stack: updated_node_ptr, retdest
%mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT)
JUMP
%macro mpt_insert_state_trie
%stack (key, value_ptr) -> (key, value_ptr, %%after)
%jump(mpt_insert_state_trie)
%%after:
%endmacro

View File

@ -102,7 +102,7 @@ type_0_compute_signed_data:
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_TO)
SWAP1 %encode_rlp_160
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_VALUE)

View File

@ -1,6 +1,6 @@
use std::collections::HashMap;
use ethereum_types::{Address, H160, H256, U256};
use ethereum_types::{Address, BigEndianHash, H160, H256, U256};
use keccak_hash::keccak;
use plonky2::field::types::Field;
@ -72,10 +72,10 @@ impl<F: Field> GenerationState<F> {
pub fn jump_to(&mut self, dst: usize) {
self.registers.program_counter = dst;
if dst == KERNEL.global_labels["observe_new_address"] {
let address = stack_peek(self, 0).expect("Empty stack");
let mut address_bytes = [0; 20];
address.to_big_endian(&mut address_bytes);
self.observe_address(H160(address_bytes));
let tip_u256 = stack_peek(self, 0).expect("Empty stack");
let tip_h256 = H256::from_uint(&tip_u256);
let tip_h160 = H160::from(tip_h256);
self.observe_address(tip_h160);
}
}