Program Listing for File evm.cuh#
↰ Return to documentation for file (src/evm.cuh
)
#ifndef _EVM_H_
#define _EVM_H_
#include "utils.h"
#include "stack.cuh"
#include "message.cuh"
#include "memory.cuh"
#include "returndata.cuh"
#include "block.cuh"
#include "tracer.cuh"
#include "state.cuh"
#include "keccak.cuh"
#include "jump_destinations.cuh"
#include "logs.cuh"
#include "alu_operations.cuh"
#include "env_operations.cuh"
#include "internal_operations.cuh"
template <class params>
class evm_t
{
public:
typedef arith_env_t<params> arith_t;
typedef typename arith_t::bn_t bn_t;
typedef block_t<params> block_t;
typedef block_t::block_data_t block_data_t;
typedef world_state_t<params> world_state_t;
typedef world_state_t::state_data_t state_data_t;
typedef world_state_t::account_t account_t;
typedef accessed_state_t<params> accessed_state_t;
typedef accessed_state_t::accessed_state_data_t accessed_state_data_t;
typedef touch_state_t<params> touch_state_t;
typedef touch_state_t::touch_state_data_t touch_state_data_t;
typedef stack_t<params> stack_t;
typedef memory_t<params> memory_t;
typedef transaction_t<params> transaction_t;
typedef typename transaction_t::transaction_data_t transaction_data_t;
typedef message_t<params> message_t;
typedef typename message_t::message_data_t message_data_t;
typedef tracer_t<params> tracer_t;
typedef typename tracer_t::tracer_data_t tracer_data_t;
typedef keccak::keccak_t keccak_t;
typedef typename keccak_t::sha3_parameters_t sha3_parameters_t;
typedef log_state_t<params> log_state_t;
typedef log_state_t::log_state_data_t log_state_data_t;
typedef arithmetic_operations<params> arithmetic_operations;
typedef comparison_operations<params> comparison_operations;
typedef bitwise_operations<params> bitwise_operations;
typedef stack_operations<params> stack_operations;
typedef block_operations<params> block_operations;
typedef environmental_operations<params> environmental_operations;
typedef internal_operations<params> internal_operations;
// constants
static const uint32_t MAX_DEPTH = 1024;
static const uint32_t MAX_EXECUTION_STEPS = 30000;
static const uint32_t DEPTH_PAGE_SIZE = 32;
static const uint32_t MAX_CODE_SIZE = 24576;
static const uint32_t MAX_INIT_CODE_SIZE = 2 * MAX_CODE_SIZE;
static const uint32_t HASH_BYTES = 32;
typedef struct
{
state_data_t *world_state_data;
block_data_t *block_data;
sha3_parameters_t *sha3_parameters;
transaction_data_t *transactions_data;
accessed_state_data_t *accessed_states_data;
touch_state_data_t *touch_states_data;
log_state_data_t *logs_data;
#ifdef TRACER
tracer_data_t *tracers_data;
#endif
uint32_t *errors;
size_t count;
} evm_instances_t;
arith_t _arith;
world_state_t *_world_state;
block_t *_block;
keccak_t *_keccak;
transaction_t *_transaction;
accessed_state_t *_accessed_state;
touch_state_t *_transaction_touch_state;
log_state_t *_transaction_log_state;
uint32_t _instance;
#ifdef TRACER
tracer_t *_tracer;
uint32_t _trace_pc;
uint8_t _trace_opcode;
bn_t _trace_address;
#endif
touch_state_t **_touch_state_ptrs;
log_state_t **_log_state_ptrs;
return_data_t **_last_return_data_ptrs;
return_data_t *_final_return_data;
message_t **_message_ptrs;
memory_t **_memory_ptrs;
stack_t **_stack_ptrs;
bn_t *_gas_useds;
bn_t *_gas_refunds;
uint32_t *_pcs;
accessed_state_data_t *_final_accessed_state_data;
touch_state_data_t *_final_touch_state_data;
log_state_data_t *_final_log_state_data;
uint32_t _depth;
uint32_t _allocated_depth;
bn_t _gas_limit;
bn_t _gas_price;
bn_t _gas_priority_fee;
uint8_t *_bytecode;
uint32_t _code_size;
uint8_t _opcode;
jump_destinations_t *_jump_destinations;
uint32_t _error_code;
uint32_t *_final_error;
/*
* Internal execution environment
* I_{a} = message.get_recipient
* I_{o} = _last_return_data_ptrs[_depth-1]
* I_{p} = _gas_price
* I_{d} = message.get_data
* I_{s} = _stack_ptrs[_depth]
* I_{v} = message.get_value
* I_{b} = _bytecode
* I_{e} = _depth
* I_{w} = message.get_static_env
*/
__host__ __device__ __forceinline__ evm_t(
arith_t arith,
state_data_t *world_state_data,
block_data_t *block_data,
sha3_parameters_t *sha3_parameters,
transaction_data_t *transaction_data,
accessed_state_data_t *accessed_state_data,
touch_state_data_t *touch_state_data,
log_state_data_t *log_state_data,
#ifdef TRACER
tracer_data_t *tracer_data,
#endif
uint32_t instance,
uint32_t *error) : _arith(arith), _instance(instance), _final_error(error)
{
_world_state = new world_state_t(arith, world_state_data);
_block = new block_t(arith, block_data);
_keccak = new keccak_t(sha3_parameters);
_transaction = new transaction_t(arith, transaction_data);
_accessed_state = new accessed_state_t(_world_state);
_transaction_touch_state = new touch_state_t(_accessed_state, NULL);
_transaction_log_state = new log_state_t(arith);
_final_accessed_state_data = accessed_state_data;
_final_touch_state_data = touch_state_data;
_final_log_state_data = log_state_data;
_depth = 0;
_allocated_depth = DEPTH_PAGE_SIZE;
_touch_state_ptrs = new touch_state_t *[_allocated_depth];
_log_state_ptrs = new log_state_t *[_allocated_depth];
_last_return_data_ptrs = new return_data_t *[_allocated_depth];
_final_return_data = new return_data_t();
_message_ptrs = new message_t *[_allocated_depth];
_memory_ptrs = new memory_t *[_allocated_depth];
_stack_ptrs = new stack_t *[_allocated_depth];
// TODO: infeficient but because of their form
// we allocate them with maximum depth from the
// begining
_gas_useds = new bn_t[MAX_DEPTH];
_gas_refunds = new bn_t[MAX_DEPTH];
_pcs = new uint32_t[MAX_DEPTH];
/*
_gas_useds = new bn_t[_allocated_depth];
_gas_refunds = new bn_t[_allocated_depth];
_pcs = new uint32_t[_allocated_depth];
*/
#ifdef TRACER
_tracer = new tracer_t(arith, tracer_data);
#endif
_jump_destinations = NULL;
_error_code = ERR_NONE;
}
__host__ __device__ __forceinline__ ~evm_t()
{
// save the final data
_accessed_state->to_accessed_state_data_t(*_final_accessed_state_data);
_transaction_touch_state->to_touch_state_data_t(*_final_touch_state_data);
_transaction_log_state->to_log_state_data_t(*_final_log_state_data);
delete _world_state;
delete _block;
delete _keccak;
delete _transaction;
delete _accessed_state;
delete _transaction_touch_state;
delete _transaction_log_state;
#ifdef TRACER
delete _tracer;
#endif
delete[] _touch_state_ptrs;
delete[] _log_state_ptrs;
delete[] _last_return_data_ptrs;
delete _final_return_data;
delete[] _message_ptrs;
delete[] _memory_ptrs;
delete[] _stack_ptrs;
delete[] _gas_useds;
delete[] _gas_refunds;
delete[] _pcs;
_allocated_depth = 0;
_depth = 0;
}
__host__ __device__ __forceinline__ void grow()
{
uint32_t new_allocated_depth = _allocated_depth + DEPTH_PAGE_SIZE;
touch_state_t **new_touch_state_ptrs = new touch_state_t *[new_allocated_depth];
log_state_t **new_log_state_ptrs = new log_state_t *[new_allocated_depth];
return_data_t **new_return_data_ptrs = new return_data_t *[new_allocated_depth];
message_t **new_message_ptrs = new message_t *[new_allocated_depth];
memory_t **new_memory_ptrs = new memory_t *[new_allocated_depth];
stack_t **new_stack_ptrs = new stack_t *[new_allocated_depth];
/*
bn_t *new_gas_useds = new bn_t[new_allocated_depth];
bn_t *new_gas_refunds = new bn_t[new_allocated_depth];
uint32_t *new_pcs = new uint32_t[new_allocated_depth];
*/
memcpy(
new_touch_state_ptrs,
_touch_state_ptrs,
_allocated_depth * sizeof(touch_state_t *));
memcpy(
new_log_state_ptrs,
_log_state_ptrs,
_allocated_depth * sizeof(log_state_t *));
memcpy(
new_return_data_ptrs,
_last_return_data_ptrs,
_allocated_depth * sizeof(return_data_t *));
memcpy(
new_message_ptrs,
_message_ptrs,
_allocated_depth * sizeof(message_t *));
memcpy(
new_memory_ptrs,
_memory_ptrs,
_allocated_depth * sizeof(memory_t *));
memcpy(
new_stack_ptrs,
_stack_ptrs,
_allocated_depth * sizeof(stack_t *));
/*
memcpy(
new_gas_useds,
_gas_useds,
_allocated_depth * sizeof(bn_t));
memcpy(
new_gas_refunds,
_gas_refunds,
_allocated_depth * sizeof(bn_t));
memcpy(
new_pcs,
_pcs,
_allocated_depth * sizeof(uint32_t));
*/
delete[] _touch_state_ptrs;
delete[] _log_state_ptrs;
delete[] _last_return_data_ptrs;
delete[] _message_ptrs;
delete[] _memory_ptrs;
delete[] _stack_ptrs;
/*
delete[] _gas_useds;
delete[] _gas_refunds;
delete[] _pcs;
*/
_touch_state_ptrs = new_touch_state_ptrs;
_log_state_ptrs = new_log_state_ptrs;
_last_return_data_ptrs = new_return_data_ptrs;
_message_ptrs = new_message_ptrs;
_memory_ptrs = new_memory_ptrs;
_stack_ptrs = new_stack_ptrs;
/*
_gas_useds = new_gas_useds;
_gas_refunds = new_gas_refunds;
_pcs = new_pcs;
*/
_allocated_depth = new_allocated_depth;
}
__host__ __device__ void start_TRANSACTION(
bn_t &gas_used,
uint32_t &error_code)
{
bn_t block_base_fee; // YP: \f$H_{f}\f$
_block->get_base_fee(block_base_fee);
bn_t block_gas_limit;
_block->get_gas_limit(block_gas_limit);
_transaction->validate_transaction(
*_transaction_touch_state,
gas_used,
_gas_price,
_gas_priority_fee,
error_code,
block_base_fee,
block_gas_limit);
// EIP-3651 - Warm um coinbase account
bn_t coin_base_address;
_block->get_coin_base(coin_base_address);
_accessed_state->get_account(coin_base_address, READ_BALANCE);
}
__host__ __device__ void update_CALL()
{
_message_ptrs[_depth]->get_gas_limit(_gas_limit);
_bytecode = _message_ptrs[_depth]->get_byte_code();
_code_size = _message_ptrs[_depth]->get_code_size();
#ifdef TRACER
_message_ptrs[_depth]->get_contract_address(_trace_address);
#endif
if (_jump_destinations != NULL)
{
delete _jump_destinations;
_jump_destinations = NULL;
}
_jump_destinations = new jump_destinations_t(_bytecode, _code_size);
}
__host__ __device__ void start_CALL(
uint32_t &error_code)
{
// update the current context
update_CALL();
// allocate the memory, the stack, the touch state, the log state, the return data
_last_return_data_ptrs[_depth] = new return_data_t();
_stack_ptrs[_depth] = new stack_t(_arith);
_memory_ptrs[_depth] = new memory_t(_arith);
if (_depth > 0)
{
_touch_state_ptrs[_depth] = new touch_state_t(
_accessed_state,
_touch_state_ptrs[_depth - 1]);
}
else
{
_touch_state_ptrs[_depth] = new touch_state_t(
_accessed_state,
_transaction_touch_state);
}
_log_state_ptrs[_depth] = new log_state_t(_arith);
// reset the program counter, the gas used and the gas refunds
_pcs[_depth] = 0;
cgbn_set_ui32(_arith._env, _gas_useds[_depth], 0);
cgbn_set_ui32(_arith._env, _gas_refunds[_depth], 0);
// Gets the information of the sender and the receiver
bn_t sender, receiver, value;
bn_t sender_balance, receiver_balance;
_message_ptrs[_depth]->get_sender(sender);
_message_ptrs[_depth]->get_recipient(receiver);
_message_ptrs[_depth]->get_value(value);
uint32_t call_type;
call_type = _message_ptrs[_depth]->get_call_type();
// in create call verify if the the account at the
// address is not a contract
if ((call_type == OP_CREATE) ||
(call_type == OP_CREATE2))
{
if (_touch_state_ptrs[_depth]->is_contract(receiver))
{
error_code = ERROR_MESSAGE_CALL_CREATE_CONTRACT_EXISTS;
return;
}
// set the account nonce to 1
bn_t contract_nonce;
cgbn_set_ui32(_arith._env, contract_nonce, 1);
_touch_state_ptrs[_depth]->set_account_nonce(receiver, contract_nonce);
}
// Transfer the value from sender to receiver
if ((cgbn_compare_ui32(_arith._env, value, 0) > 0) && // value>0
(cgbn_compare(_arith._env, sender, receiver) != 0) && // sender != receiver
(call_type != OP_DELEGATECALL) // no delegatecall
)
{
_touch_state_ptrs[_depth]->get_account_balance(sender, sender_balance);
_touch_state_ptrs[_depth]->get_account_balance(receiver, receiver_balance);
cgbn_sub(_arith._env, sender_balance, sender_balance, value);
cgbn_add(_arith._env, receiver_balance, receiver_balance, value);
_touch_state_ptrs[_depth]->set_account_balance(sender, sender_balance);
_touch_state_ptrs[_depth]->set_account_balance(receiver, receiver_balance);
}
// warm up the accounts
account_t *account;
account = _touch_state_ptrs[_depth]->get_account(sender, READ_NONE);
account = _touch_state_ptrs[_depth]->get_account(receiver, READ_NONE);
account = NULL;
// if is a call to a non-contract account
// if code size is zero. TODO: verify if is consider a last return data
// only for calls not for create
if ((_code_size == 0) &&
(call_type != OP_CREATE) &&
(call_type != OP_CREATE2))
{
if (_depth == 0)
{
system_operations::operation_STOP(
*_final_return_data,
error_code);
}
else
{
system_operations::operation_STOP(
*_last_return_data_ptrs[_depth - 1],
error_code);
}
}
}
class system_operations
{
public:
__host__ __device__ __forceinline__ static int32_t valid_CALL(
arith_t &arith,
message_t &message,
touch_state_t &touch_state)
{
bn_t sender, receiver, value;
bn_t sender_balance;
// bn_t receiver_balance;
uint8_t call_type;
uint32_t depth;
message.get_sender(sender);
// message.get_recipient(receiver);
message.get_value(value);
call_type = message.get_call_type();
depth = message.get_depth();
// verify depth
if (depth >= MAX_DEPTH)
{
// error_code = ERROR_MESSAGE_CALL_DEPTH_EXCEEDED;
return 0;
}
// verify if the value can be transfered
// if the sender has enough balance
if ((cgbn_compare_ui32(arith._env, value, 0) > 0) && // value>0
//(cgbn_compare(arith._env, sender, receiver) != 0) && // sender != receiver matter only on transfer
(call_type != OP_DELEGATECALL) // no delegatecall
)
{
touch_state.get_account_balance(sender, sender_balance);
// touch_state.get_account_balance(receiver, receiver_balance);
// verify the balance before transfer
if (cgbn_compare(arith._env, sender_balance, value) < 0)
{
// error_code = ERROR_MESSAGE_CALL_SENDER_BALANCE;
return 0;
}
}
return 1;
}
__host__ __device__ __forceinline__ static int32_t valid_CREATE(
arith_t &arith,
message_t &message,
touch_state_t &touch_state)
{
bn_t sender;
message.get_sender(sender);
if (touch_state.is_contract(sender))
{
bn_t sender_nonce;
touch_state.get_account_nonce(sender, sender_nonce);
cgbn_add_ui32(arith._env, sender_nonce, sender_nonce, 1);
size_t nonce;
if (arith.uint64_t_from_cgbn(nonce, sender_nonce))
{
// error_code = ERROR_MESSAGE_CALL_CREATE_NONCE_EXCEEDED;
return 0;
}
}
return valid_CALL(arith, message, touch_state);
}
__host__ __device__ __forceinline__ static void generic_CALL(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
stack_t &stack,
message_t &message,
memory_t &memory,
touch_state_t &touch_state,
evm_t &evm,
message_t &new_message,
bn_t &args_offset,
bn_t &args_size,
return_data_t &return_data)
{
// try to send value in static call
bn_t value;
new_message.get_value(value);
if (message.get_static_env())
{
if (
(cgbn_compare_ui32(arith._env, value, 0) != 0) &&
(new_message.get_call_type() == OP_CALL) // TODO: akward that is just CALL
)
{
error_code = ERROR_STATIC_CALL_CONTEXT_CALL_VALUE;
}
}
// charge the gas for the call
// memory call data
memory.grow_cost(
args_offset,
args_size,
gas_used,
error_code);
// memory return data
bn_t ret_offset, ret_size;
new_message.get_return_data_offset(ret_offset);
new_message.get_return_data_size(ret_size);
memory.grow_cost(
ret_offset,
ret_size,
gas_used,
error_code);
// adress warm call
bn_t contract_address;
new_message.get_contract_address(contract_address);
touch_state.charge_gas_access_account(
contract_address,
gas_used);
// positive value call cost (except delegate call)
// empty account call cost
bn_t gas_stippend;
cgbn_set_ui32(arith._env, gas_stippend, 0);
if (new_message.get_call_type() != OP_DELEGATECALL)
{
if (cgbn_compare_ui32(arith._env, value, 0) > 0)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_CALL_VALUE);
cgbn_set_ui32(arith._env, gas_stippend, GAS_CALL_STIPEND);
// If the empty account is called
if (touch_state.is_empty_account(contract_address))
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_NEW_ACCOUNT);
};
}
}
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t gas;
new_message.get_gas_limit(gas);
// gas capped = (63/64) * gas_left
bn_t gas_capped;
arith.max_gas_call(gas_capped, gas_limit, gas_used);
if (cgbn_compare(arith._env, gas, gas_capped) > 0)
{
cgbn_set(arith._env, gas, gas_capped);
}
// add to gas used the sent gas
cgbn_add(arith._env, gas_used, gas_used, gas);
// add the call stippend
cgbn_add(arith._env, gas, gas, gas_stippend);
// set the new gas limit
new_message.set_gas_limit(gas);
// set the byte code
account_t *contract;
contract = touch_state.get_account(contract_address, READ_CODE);
new_message.set_byte_code(
contract->bytecode,
contract->code_size);
uint8_t *call_data;
size_t call_data_size;
call_data = memory.get(
args_offset,
args_size,
error_code);
arith.size_t_from_cgbn(call_data_size, args_size);
new_message.set_data(call_data, call_data_size);
if (valid_CALL(arith, new_message, touch_state))
{
// new message done
// call the child
evm.child_CALL(
error_code,
new_message);
}
else
{
bn_t child_success;
cgbn_set_ui32(arith._env, child_success, 0);
stack.push(child_success, error_code);
return_data.set(
NULL,
0);
// TODO: verify better if contains the GAS STIPPEND
cgbn_sub(arith._env, gas_used, gas_used, gas);
delete &new_message;
}
}
else
{
delete &new_message;
}
}
__host__ __device__ __forceinline__ static void generic_CREATE(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
stack_t &stack,
message_t &message,
memory_t &memory,
touch_state_t &touch_state,
evm_t &evm,
message_t &new_message,
bn_t &args_offset,
bn_t &args_size,
return_data_t &return_data)
{
if (message.get_static_env())
{
error_code = ERROR_STATIC_CALL_CONTEXT_CREATE;
delete &new_message;
}
else if (cgbn_compare_ui32(arith._env, args_size, MAX_INIT_CODE_SIZE) >= 0)
{
// EIP-3860
error_code = ERROR_CREATE_INIT_CODE_SIZE_EXCEEDED;
delete &new_message;
}
else
{
// set the init code
SHARED_MEMORY data_content_t initialisation_code;
arith.size_t_from_cgbn(initialisation_code.size, args_size);
initialisation_code.data = memory.get(
args_offset,
args_size,
error_code);
new_message.set_byte_code(
initialisation_code.data,
initialisation_code.size);
// set the gas limit
bn_t gas_capped;
arith.max_gas_call(gas_capped, gas_limit, gas_used);
new_message.set_gas_limit(gas_capped);
// add to gas used
cgbn_add(arith._env, gas_used, gas_used, gas_capped);
// warm up the contract address
bn_t contract_address;
new_message.get_recipient(contract_address);
account_t *account = touch_state.get_account(contract_address, READ_NONE);
// setup return offset to null
bn_t ret_offset, ret_size;
cgbn_set_ui32(arith._env, ret_offset, 0);
cgbn_set_ui32(arith._env, ret_size, 0);
new_message.set_return_data_offset(ret_offset);
new_message.set_return_data_size(ret_size);
if (valid_CREATE(arith, new_message, touch_state))
{
// increase the nonce if the sender is a contract
// TODO: seems like an akward think to do
// why in the parent and not in the child the nonce
// if the contract deployment fails the nonce is still
// increased?
bn_t sender;
new_message.get_sender(sender);
if (touch_state.is_contract(sender))
{
bn_t sender_nonce;
touch_state.get_account_nonce(sender, sender_nonce);
cgbn_add_ui32(arith._env, sender_nonce, sender_nonce, 1);
touch_state.set_account_nonce(sender, sender_nonce);
}
// new message done
// call the child
evm.child_CALL(
error_code,
new_message);
}
else
{
bn_t child_success;
cgbn_set_ui32(arith._env, child_success, 0);
stack.push(child_success, error_code);
cgbn_sub(arith._env, gas_used, gas_used, gas_capped);
return_data.set(
NULL,
0);
delete &new_message;
}
}
}
__host__ __device__ __forceinline__ static void operation_STOP(
return_data_t &return_data,
uint32_t &error_code)
{
return_data.set(
NULL,
0);
error_code = ERR_RETURN;
}
__host__ __device__ __forceinline__ static void operation_CREATE(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
message_t &message,
memory_t &memory,
touch_state_t &touch_state,
uint8_t &opcode,
keccak_t &keccak,
evm_t &evm,
return_data_t &return_data)
{
bn_t value, memory_offset, length;
stack.pop(value, error_code);
stack.pop(memory_offset, error_code);
stack.pop(length, error_code);
// create cost
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_CREATE);
// compute the memory cost
memory.grow_cost(
memory_offset,
length,
gas_used,
error_code);
// compute the initcode gas cost
arith.initcode_cost(
gas_used,
length);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t sender_address;
message.get_recipient(sender_address); // I_{a}
bn_t sender_nonce;
touch_state.get_account_nonce(sender_address, sender_nonce);
// compute the address
bn_t address;
message_t::get_create_contract_address(
arith,
address,
sender_address,
sender_nonce,
keccak);
message_t *new_message = new message_t(
arith,
sender_address,
address,
address,
gas_limit,
value,
message.get_depth() + 1,
opcode,
address,
NULL,
0,
NULL,
0,
memory_offset,
length,
message.get_static_env());
generic_CREATE(
arith,
gas_limit,
gas_used,
error_code,
stack,
message,
memory,
touch_state,
evm,
*new_message,
memory_offset,
length,
return_data);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_CALL(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
message_t &message,
memory_t &memory,
touch_state_t &touch_state,
uint8_t &opcode,
evm_t &evm,
return_data_t &return_data)
{
bn_t gas, address, value, args_offset, args_size, ret_offset, ret_size;
stack.pop(gas, error_code);
stack.pop(address, error_code);
stack.pop(value, error_code);
stack.pop(args_offset, error_code);
stack.pop(args_size, error_code);
stack.pop(ret_offset, error_code);
stack.pop(ret_size, error_code);
if (error_code == ERR_NONE)
{
// clean the address
arith.address_conversion(address);
bn_t sender;
message.get_recipient(sender); // I_{a}
bn_t recipient;
cgbn_set(arith._env, recipient, address); // t
bn_t contract_address;
cgbn_set(arith._env, contract_address, address); // t
bn_t storage_address;
cgbn_set(arith._env, storage_address, address); // t
message_t *new_message = new message_t(
arith,
sender,
recipient,
contract_address,
gas,
value,
message.get_depth() + 1,
opcode,
storage_address,
NULL,
0,
NULL,
0,
ret_offset,
ret_size,
message.get_static_env());
generic_CALL(
arith,
gas_limit,
gas_used,
error_code,
stack,
message,
memory,
touch_state,
evm,
*new_message,
args_offset,
args_size,
return_data);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_CALLCODE(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
message_t &message,
memory_t &memory,
touch_state_t &touch_state,
uint8_t &opcode,
evm_t &evm,
return_data_t &return_data)
{
bn_t gas, address, value, args_offset, args_size, ret_offset, ret_size;
stack.pop(gas, error_code);
stack.pop(address, error_code);
stack.pop(value, error_code);
stack.pop(args_offset, error_code);
stack.pop(args_size, error_code);
stack.pop(ret_offset, error_code);
stack.pop(ret_size, error_code);
if (error_code == ERR_NONE)
{
// clean the address
arith.address_conversion(address);
bn_t sender;
message.get_recipient(sender); // I_{a}
bn_t recipient;
cgbn_set(arith._env, recipient, sender); // I_{a}
bn_t contract_address;
cgbn_set(arith._env, contract_address, address); // t
bn_t storage_address;
cgbn_set(arith._env, storage_address, sender); // I_{a}
message_t *new_message = new message_t(
arith,
sender,
recipient,
contract_address,
gas,
value,
message.get_depth() + 1,
opcode,
storage_address,
NULL,
0,
NULL,
0,
ret_offset,
ret_size,
message.get_static_env());
generic_CALL(
arith,
gas_limit,
gas_used,
error_code,
stack,
message,
memory,
touch_state,
evm,
*new_message,
args_offset,
args_size,
return_data);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_RETURN(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
stack_t &stack,
memory_t &memory,
return_data_t &return_data)
{
bn_t memory_offset, length;
stack.pop(memory_offset, error_code);
stack.pop(length, error_code);
if (error_code == ERR_NONE)
{
memory.grow_cost(
memory_offset,
length,
gas_used,
error_code);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
uint8_t *data;
size_t data_size;
data = memory.get(
memory_offset,
length,
error_code);
arith.size_t_from_cgbn(data_size, length);
if (error_code == ERR_NONE)
{
return_data.set(
data,
data_size);
error_code = ERR_RETURN;
}
}
}
}
__host__ __device__ __forceinline__ static void operation_DELEGATECALL(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
message_t &message,
memory_t &memory,
touch_state_t &touch_state,
uint8_t &opcode,
evm_t &evm,
return_data_t &return_data)
{
bn_t gas, address, value, args_offset, args_size, ret_offset, ret_size;
stack.pop(gas, error_code);
stack.pop(address, error_code);
message.get_value(value);
stack.pop(args_offset, error_code);
stack.pop(args_size, error_code);
stack.pop(ret_offset, error_code);
stack.pop(ret_size, error_code);
if (error_code == ERR_NONE)
{
// clean the address
arith.address_conversion(address);
bn_t sender;
message.get_sender(sender); // keep the message call sender I_{s}
bn_t recipient;
message.get_recipient(recipient); // I_{a}
bn_t contract_address;
cgbn_set(arith._env, contract_address, address); // t
bn_t storage_address;
message.get_recipient(storage_address); // I_{a}
message_t *new_message = new message_t(
arith,
sender,
recipient,
contract_address,
gas,
value,
message.get_depth() + 1,
opcode,
storage_address,
NULL,
0,
NULL,
0,
ret_offset,
ret_size,
message.get_static_env());
generic_CALL(
arith,
gas_limit,
gas_used,
error_code,
stack,
message,
memory,
touch_state,
evm,
*new_message,
args_offset,
args_size,
return_data);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_CREATE2(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
message_t &message,
memory_t &memory,
touch_state_t &touch_state,
uint8_t &opcode,
keccak_t &keccak,
evm_t &evm,
return_data_t &return_data)
{
bn_t value, memory_offset, length, salt;
stack.pop(value, error_code);
stack.pop(memory_offset, error_code);
stack.pop(length, error_code);
stack.pop(salt, error_code);
// create cost
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_CREATE);
// compute the keccak gas cost
arith.keccak_cost(
gas_used,
length);
// compute the memory cost
memory.grow_cost(
memory_offset,
length,
gas_used,
error_code);
// compute the initcode gas cost
arith.initcode_cost(
gas_used,
length);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
SHARED_MEMORY data_content_t initialisation_code;
arith.size_t_from_cgbn(initialisation_code.size, length);
initialisation_code.data = memory.get(
memory_offset,
length,
error_code);
bn_t sender_address;
message.get_recipient(sender_address); // I_{a}
// compute the address
bn_t address;
message_t::get_create2_contract_address(
arith,
address,
sender_address,
salt,
initialisation_code,
keccak);
// create the message
message_t *new_message = new message_t(
arith,
sender_address,
address,
address,
gas_limit,
value,
message.get_depth() + 1,
opcode,
address,
NULL,
0,
NULL,
0,
memory_offset,
length,
message.get_static_env());
generic_CREATE(
arith,
gas_limit,
gas_used,
error_code,
stack,
message,
memory,
touch_state,
evm,
*new_message,
memory_offset,
length,
return_data);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_STATICCALL(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
message_t &message,
memory_t &memory,
touch_state_t &touch_state,
uint8_t &opcode,
evm_t &evm,
return_data_t &return_data)
{
bn_t gas, address, value, args_offset, args_size, ret_offset, ret_size;
stack.pop(gas, error_code);
stack.pop(address, error_code);
cgbn_set_ui32(arith._env, value, 0);
stack.pop(args_offset, error_code);
stack.pop(args_size, error_code);
stack.pop(ret_offset, error_code);
stack.pop(ret_size, error_code);
if (error_code == ERR_NONE)
{
// clean the address
arith.address_conversion(address);
bn_t sender;
message.get_recipient(sender); // I_{a}
bn_t recipient;
cgbn_set(arith._env, recipient, address); // t
bn_t contract_address;
cgbn_set(arith._env, contract_address, address); // t
bn_t storage_address;
cgbn_set(arith._env, storage_address, address); // t
message_t *new_message = new message_t(
arith,
sender,
recipient,
contract_address,
gas,
value,
message.get_depth() + 1,
opcode,
storage_address,
NULL,
0,
NULL,
0,
ret_offset,
ret_size,
1);
generic_CALL(
arith,
gas_limit,
gas_used,
error_code,
stack,
message,
memory,
touch_state,
evm,
*new_message,
args_offset,
args_size,
return_data);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_REVERT(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
stack_t &stack,
memory_t &memory,
return_data_t &return_data)
{
bn_t memory_offset, length;
stack.pop(memory_offset, error_code);
stack.pop(length, error_code);
if (error_code == ERR_NONE)
{
memory.grow_cost(
memory_offset,
length,
gas_used,
error_code);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
uint8_t *data;
size_t data_size;
data = memory.get(
memory_offset,
length,
error_code);
arith.size_t_from_cgbn(data_size, length);
if (error_code == ERR_NONE)
{
return_data.set(
data,
data_size);
error_code = ERR_REVERT;
}
}
}
}
__host__ __device__ __forceinline__ static void operation_INVALID(
uint32_t &error_code)
{
error_code = ERR_NOT_IMPLEMENTED;
}
__host__ __device__ __forceinline__ static void operation_SELFDESTRUCT(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
message_t &message,
touch_state_t &touch_state,
return_data_t &return_data,
evm_t &evm)
{
if (message.get_static_env())
{
error_code = ERROR_STATIC_CALL_CONTEXT_SELFDESTRUCT;
}
else
{
bn_t recipient;
stack.pop(recipient, error_code);
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_SELFDESTRUCT);
bn_t dummy_gas;
cgbn_set_ui32(arith._env, dummy_gas, 0);
touch_state.charge_gas_access_account(
recipient,
dummy_gas);
if (cgbn_compare_ui32(arith._env, dummy_gas, GAS_WARM_ACCESS) != 0)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_COLD_ACCOUNT_ACCESS);
}
bn_t sender;
message.get_recipient(sender); // I_{a}
bn_t sender_balance;
touch_state.get_account_balance(sender, sender_balance);
if (cgbn_compare_ui32(arith._env, sender_balance, 0) > 0)
{
if (touch_state.is_empty_account(recipient))
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_NEW_ACCOUNT);
}
}
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t recipient_balance;
touch_state.get_account_balance(recipient, recipient_balance);
if (cgbn_compare(arith._env, recipient, sender) != 0)
{
cgbn_add(arith._env, recipient_balance, recipient_balance, sender_balance);
touch_state.set_account_balance(recipient, recipient_balance);
}
cgbn_set_ui32(arith._env, sender_balance, 0);
touch_state.set_account_balance(sender, sender_balance);
// TODO: delete or not the storage/code?
touch_state.delete_account(sender);
return_data.set(
NULL,
0);
error_code = ERR_RETURN;
}
}
}
};
__host__ __device__ void run(
uint32_t &error_code)
{
// get the first message call from transaction
_message_ptrs[_depth] = _transaction->get_message_call(*_accessed_state, *_keccak);
// process the transaction
bn_t intrsinc_gas_used;
start_TRANSACTION(intrsinc_gas_used, error_code);
start_CALL(error_code);
// if it is a invalid transaction or not enough gas to start the call
if (error_code != ERR_NONE)
{
finish_TRANSACTION(error_code);
free_CALL();
return;
}
// add the transaction cost
cgbn_add(_arith._env, _gas_useds[_depth], _gas_useds[_depth], intrsinc_gas_used);
// run the message call
uint32_t execution_step = 0;
while (
(execution_step < MAX_EXECUTION_STEPS))
{
// if the program counter is out of bounds
// it is a STOP operation
if (_pcs[_depth] >= _code_size)
{
_opcode = OP_STOP;
}
else
{
_opcode = _bytecode[_pcs[_depth]];
}
ONE_THREAD_PER_INSTANCE(
printf("pc: %d opcode: %d\n", _pcs[_depth], _opcode);)
#ifdef TRACER
_trace_pc = _pcs[_depth];
_trace_opcode = _opcode;
#endif
// PUSHX
if (((_opcode & 0xF0) == 0x60) || ((_opcode & 0xF0) == 0x70))
{
stack_operations::operation_PUSHX(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
_bytecode,
_code_size,
_opcode);
}
else if ((_opcode & 0xF0) == 0x80) // DUPX
{
stack_operations::operation_DUPX(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
_opcode);
}
else if ((_opcode & 0xF0) == 0x90) // SWAPX
{
stack_operations::operation_SWAPX(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
_opcode);
}
else if ((_opcode & 0xF0) == 0xA0) // LOGX
{
internal_operations::operation_LOGX(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_message_ptrs[_depth],
*_log_state_ptrs[_depth],
_opcode);
}
else
{
// Depending on the opcode execute the operation
switch (_opcode)
{
case OP_STOP: // STOP
{
if (_depth == 0)
{
system_operations::operation_STOP(
*_final_return_data,
error_code);
}
else
{
system_operations::operation_STOP(
*_last_return_data_ptrs[_depth - 1],
error_code);
}
}
break;
case OP_ADD: // ADD
{
arithmetic_operations::operation_ADD(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_MUL: // MUL
{
arithmetic_operations::operation_MUL(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SUB: // SUB
{
arithmetic_operations::operation_SUB(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_DIV: // DIV
{
arithmetic_operations::operation_DIV(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SDIV: // SDIV
{
arithmetic_operations::operation_SDIV(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_MOD: // MOD
{
arithmetic_operations::operation_MOD(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SMOD: // SMOD
{
arithmetic_operations::operation_SMOD(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_ADDMOD: // ADDMOD
{
arithmetic_operations::operation_ADDMOD(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_MULMOD: // MULMOD
{
arithmetic_operations::operation_MULMOD(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_EXP: // EXP
{
arithmetic_operations::operation_EXP(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SIGNEXTEND: // SIGNEXTEND
{
arithmetic_operations::operation_SIGNEXTEND(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_LT: // LT
{
comparison_operations::operation_LT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_GT: // GT
{
comparison_operations::operation_GT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SLT: // SLT
{
comparison_operations::operation_SLT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SGT: // SGT
{
comparison_operations::operation_SGT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_EQ: // EQ
{
comparison_operations::operation_EQ(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_ISZERO: // ISZERO
{
comparison_operations::operation_ISZERO(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_AND: // AND
{
bitwise_operations::operation_AND(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_OR: // OR
{
bitwise_operations::operation_OR(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_XOR: // XOR
{
bitwise_operations::operation_XOR(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_NOT: // NOT
{
bitwise_operations::operation_NOT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_BYTE: // BYTE
{
bitwise_operations::operation_BYTE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SHL: // SHL
{
bitwise_operations::operation_SHL(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SHR: // SHR
{
bitwise_operations::operation_SHR(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SAR: // SAR
{
bitwise_operations::operation_SAR(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_SHA3: // SHA3
{
environmental_operations::operation_SHA3(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_keccak,
*_memory_ptrs[_depth]);
}
break;
case OP_ADDRESS: // ADDRESS
{
environmental_operations::operation_ADDRESS(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_BALANCE: // BALANCE
{
environmental_operations::operation_BALANCE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_touch_state_ptrs[_depth]);
}
break;
case OP_ORIGIN: // ORIGIN
{
environmental_operations::operation_ORIGIN(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_transaction);
}
break;
case OP_CALLER: // CALLER
{
environmental_operations::operation_CALLER(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_CALLVALUE: // CALLVALUE
{
environmental_operations::operation_CALLVALUE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_CALLDATALOAD: // CALLDATALOAD
{
environmental_operations::operation_CALLDATALOAD(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_CALLDATASIZE: // CALLDATASIZE
{
environmental_operations::operation_CALLDATASIZE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_CALLDATACOPY: // CALLDATACOPY
{
environmental_operations::operation_CALLDATACOPY(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_memory_ptrs[_depth]);
}
break;
case OP_CODESIZE: // CODESIZE
{
environmental_operations::operation_CODESIZE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_CODECOPY: // CODECOPY
{
environmental_operations::operation_CODECOPY(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_memory_ptrs[_depth]);
}
break;
case OP_GASPRICE: // GASPRICE
{
environmental_operations::operation_GASPRICE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block,
*_transaction);
}
break;
case OP_EXTCODESIZE: // EXTCODESIZE
{
environmental_operations::operation_EXTCODESIZE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_touch_state_ptrs[_depth]);
}
break;
case OP_EXTCODECOPY: // EXTCODECOPY
{
environmental_operations::operation_EXTCODECOPY(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_touch_state_ptrs[_depth],
*_memory_ptrs[_depth]);
}
break;
case OP_RETURNDATASIZE: // RETURNDATASIZE
{
environmental_operations::operation_RETURNDATASIZE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_last_return_data_ptrs[_depth]);
}
break;
case OP_RETURNDATACOPY: // RETURNDATACOPY
{
environmental_operations::operation_RETURNDATACOPY(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_last_return_data_ptrs[_depth]);
}
break;
case OP_EXTCODEHASH: // EXTCODEHASH
{
environmental_operations::operation_EXTCODEHASH(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_touch_state_ptrs[_depth],
*_keccak);
}
break;
case OP_BLOCKHASH: // BLOCKHASH
{
block_operations::operation_BLOCKHASH(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block);
}
break;
case OP_COINBASE: // COINBASE
{
block_operations::operation_COINBASE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block);
}
break;
case OP_TIMESTAMP: // TIMESTAMP
{
block_operations::operation_TIMESTAMP(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block);
}
break;
case OP_NUMBER: // NUMBER
{
block_operations::operation_NUMBER(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block);
}
break;
case OP_DIFFICULTY: // DIFFICULTY
{
block_operations::operation_PREVRANDAO(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block);
}
break;
case OP_GASLIMIT: // GASLIMIT
{
block_operations::operation_GASLIMIT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block);
}
break;
case OP_CHAINID: // CHAINID
{
block_operations::operation_CHAINID(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block);
}
break;
case OP_SELFBALANCE: // SELFBALANCE
{
environmental_operations::operation_SELFBALANCE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_touch_state_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_BASEFEE: // BASEFEE
{
block_operations::operation_BASEFEE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_block);
}
break;
case OP_POP: // POP
{
stack_operations::operation_POP(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_MLOAD: // MLOAD
{
internal_operations::operation_MLOAD(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_memory_ptrs[_depth]);
}
break;
case OP_MSTORE: // MSTORE
{
internal_operations::operation_MSTORE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_memory_ptrs[_depth]);
}
break;
case OP_MSTORE8: // MSTORE8
{
internal_operations::operation_MSTORE8(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_memory_ptrs[_depth]);
}
break;
case OP_SLOAD: // SLOAD
{
internal_operations::operation_SLOAD(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_touch_state_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_SSTORE: // SSTORE
{
internal_operations::operation_SSTORE(
_arith,
_gas_limit,
_gas_useds[_depth],
_gas_refunds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_touch_state_ptrs[_depth],
*_message_ptrs[_depth]);
}
break;
case OP_JUMP: // JUMP
{
internal_operations::operation_JUMP(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_jump_destinations);
}
break;
case OP_JUMPI: // JUMPI
{
internal_operations::operation_JUMPI(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_jump_destinations);
}
break;
case OP_PC: // PC
{
internal_operations::operation_PC(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_MSIZE: // MSIZE
{
internal_operations::operation_MSIZE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_memory_ptrs[_depth]);
}
break;
case OP_GAS: // GAS
{
internal_operations::operation_GAS(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_JUMPDEST: // JUMPDEST
{
internal_operations::operation_JUMPDEST(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth]);
}
break;
case OP_PUSH0: // PUSH0
{
stack_operations::operation_PUSH0(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth]);
}
break;
case OP_CREATE: // CREATE
{
system_operations::operation_CREATE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_opcode,
*_keccak,
*this,
*_last_return_data_ptrs[_depth]);
}
break;
case OP_CALL: // CALL
{
system_operations::operation_CALL(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_opcode,
*this,
*_last_return_data_ptrs[_depth]);
}
break;
case OP_CALLCODE: // CALLCODE
{
system_operations::operation_CALLCODE(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_opcode,
*this,
*_last_return_data_ptrs[_depth]);
}
break;
case OP_RETURN: // RETURN
{
if (_depth == 0)
{
system_operations::operation_RETURN(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_final_return_data);
}
else
{
system_operations::operation_RETURN(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_last_return_data_ptrs[_depth - 1]);
}
}
break;
case OP_DELEGATECALL: // DELEGATECALL
{
system_operations::operation_DELEGATECALL(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_opcode,
*this,
*_last_return_data_ptrs[_depth]);
}
break;
case OP_CREATE2: // CREATE2
{
system_operations::operation_CREATE2(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_opcode,
*_keccak,
*this,
*_last_return_data_ptrs[_depth]);
}
break;
case OP_STATICCALL: // STATICCALL
{
system_operations::operation_STATICCALL(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_opcode,
*this,
*_last_return_data_ptrs[_depth]);
}
break;
case OP_REVERT: // REVERT
{
if (_depth == 0)
{
system_operations::operation_REVERT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_final_return_data);
}
else
{
system_operations::operation_REVERT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_last_return_data_ptrs[_depth - 1]);
}
}
break;
case OP_INVALID: // INVALID
{
system_operations::operation_INVALID(
error_code);
}
break;
case OP_SELFDESTRUCT: // SELFDESTRUCT
{
if (_depth == 0)
{
system_operations::operation_SELFDESTRUCT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_touch_state_ptrs[_depth],
*_final_return_data,
*this);
}
else
{
system_operations::operation_SELFDESTRUCT(
_arith,
_gas_limit,
_gas_useds[_depth],
error_code,
_pcs[_depth],
*_stack_ptrs[_depth],
*_message_ptrs[_depth],
*_touch_state_ptrs[_depth],
*_last_return_data_ptrs[_depth - 1],
*this);
}
}
break;
default:
{
system_operations::operation_INVALID(
error_code);
}
break;
}
}
// If the operation ended with halting
// can be normal or exceptional
if (error_code != ERR_NONE)
{
// FIRST verify if is a createX operation and success
if (
(error_code == ERR_RETURN) &&
((_message_ptrs[_depth]->get_call_type() == OP_CREATE) ||
(_message_ptrs[_depth]->get_call_type() == OP_CREATE2)))
{
finish_CREATEX(error_code);
}
// if it is the root call
if (_depth == 0)
{
#ifdef TRACER
_tracer->push(
_trace_address,
_trace_pc,
_trace_opcode,
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_gas_useds[_depth],
_gas_limit,
_gas_refunds[_depth],
error_code);
#endif
finish_TRANSACTION(error_code);
free_CALL();
return;
}
else
{
finish_CALL(error_code);
free_CALL();
_depth = _depth - 1;
update_CALL();
#ifdef TRACER
_tracer->push(
_trace_address,
_trace_pc,
_trace_opcode,
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_gas_useds[_depth],
_gas_limit,
_gas_refunds[_depth],
error_code);
#endif
}
}
else
{
#ifdef TRACER
_tracer->push(
_trace_address,
_trace_pc,
_trace_opcode,
*_stack_ptrs[_depth],
*_memory_ptrs[_depth],
*_touch_state_ptrs[_depth],
_gas_useds[_depth],
_gas_limit,
_gas_refunds[_depth],
error_code);
#endif
}
}
}
__host__ __device__ __forceinline__ void finish_CREATEX(
uint32_t &error_code)
{
// compute the gas to deposit the contract
bn_t gas_value;
cgbn_set_ui32(_arith._env, gas_value, GAS_CODE_DEPOSIT);
bn_t code_size;
if (_depth > 0)
{
_arith.cgbn_from_size_t(code_size, _last_return_data_ptrs[_depth - 1]->size());
}
else
{
_arith.cgbn_from_size_t(code_size, _final_return_data->size());
}
cgbn_mul(_arith._env, gas_value, gas_value, code_size);
cgbn_add(_arith._env, _gas_useds[_depth], _gas_useds[_depth], gas_value);
uint32_t tmp_error_code;
tmp_error_code = ERR_NONE;
// if enough gas set the bytecode for the contract
// and the nonce of the new contract
if (_arith.has_gas(_gas_limit, _gas_useds[_depth], tmp_error_code))
{
// compute the address of the contract
bn_t contract_address;
_message_ptrs[_depth]->get_recipient(contract_address);
uint8_t *code;
size_t code_size;
if (_depth > 0)
{
code = _last_return_data_ptrs[_depth - 1]->get_data()->data;
code_size = _last_return_data_ptrs[_depth - 1]->size();
}
else
{
code = _final_return_data->get_data()->data;
code_size = _final_return_data->size();
}
if (code_size <= MAX_CODE_SIZE)
{
if ((code_size > 0) && (code[0] == 0xef)) // EIP-3541
{
error_code = ERROR_CREATE_CODE_FIRST_BYTE_INVALID;
}
else
{
// set the bytecode
_touch_state_ptrs[_depth]->set_account_code(
contract_address,
code,
code_size);
// the balance and the nonce is done at the begining of the call
}
}
else
{
error_code = ERROR_CREATE_CODE_SIZE_EXCEEDED;
}
}
else
{
error_code = tmp_error_code;
}
}
__host__ __device__ __forceinline__ void finish_CALL(
uint32_t &error_code)
{
bn_t child_success;
// set the child call to failure
cgbn_set_ui32(_arith._env, child_success, 0);
// if the child call return from normal halting
// no errors
if ((error_code == ERR_RETURN) || (error_code == ERR_REVERT))
{
// give back the gas left from the child computation
bn_t gas_left;
cgbn_sub(_arith._env, gas_left, _gas_limit, _gas_useds[_depth]);
cgbn_sub(_arith._env, _gas_useds[_depth - 1], _gas_useds[_depth - 1], gas_left);
// if is a succesfull call
if (error_code == ERR_RETURN)
{
// update the parent state with the states of the child
_touch_state_ptrs[_depth - 1]->update_with_child_state(
*_touch_state_ptrs[_depth]);
_log_state_ptrs[_depth - 1]->update_with_child_state(
*_log_state_ptrs[_depth]);
// sum the refund gas
cgbn_add(
_arith._env,
_gas_refunds[_depth - 1],
_gas_refunds[_depth - 1],
_gas_refunds[_depth]);
// for CALL operations set the child success to 1
cgbn_set_ui32(_arith._env, child_success, 1);
// if CREATEX operation, set the address of the contract
if (
(_message_ptrs[_depth]->get_call_type() == OP_CREATE) ||
(_message_ptrs[_depth]->get_call_type() == OP_CREATE2))
{
_message_ptrs[_depth]->get_recipient(child_success);
}
}
}
// reset the gas used and gas refund in the child
cgbn_set_ui32(_arith._env, _gas_useds[_depth], 0);
cgbn_set_ui32(_arith._env, _gas_refunds[_depth], 0);
// get the memory offset and size of the return data
// in the parent memory
bn_t ret_offset, ret_size;
_message_ptrs[_depth]->get_return_data_offset(ret_offset);
_message_ptrs[_depth]->get_return_data_size(ret_size);
// reset the error code for the parent
error_code = ERR_NONE;
// push the result in the parent stack
_stack_ptrs[_depth - 1]->push(child_success, error_code);
// set the parent memory with the return data
bn_t return_data_index;
cgbn_set_ui32(_arith._env, return_data_index, 0);
uint8_t *data;
size_t data_size;
data = _arith.get_data(
*(_last_return_data_ptrs[_depth - 1]->get_data()),
return_data_index,
ret_size,
data_size);
// It writes on memory even if the call was reverted
_memory_ptrs[_depth - 1]->set(
data,
ret_offset,
ret_size,
data_size,
error_code);
}
__host__ __device__ __forceinline__ void free_CALL()
{
delete _stack_ptrs[_depth];
_stack_ptrs[_depth] = NULL;
delete _memory_ptrs[_depth];
_memory_ptrs[_depth] = NULL;
delete _last_return_data_ptrs[_depth];
_last_return_data_ptrs[_depth] = NULL;
// delete the touch state
delete _touch_state_ptrs[_depth];
_touch_state_ptrs[_depth] = NULL;
delete _log_state_ptrs[_depth];
_log_state_ptrs[_depth] = NULL;
// delete the message
delete _message_ptrs[_depth];
_message_ptrs[_depth] = NULL;
}
__host__ __device__ __forceinline__ void finish_TRANSACTION(
uint32_t &error_code)
{
// sent the gas value to the block beneficiary
bn_t gas_value;
bn_t beneficiary;
_block->get_coin_base(beneficiary);
if (error_code == ERR_RETURN)
{
bn_t gas_left;
// \f$T_{g} - g\f$
cgbn_sub(_arith._env, gas_left, _gas_limit, _gas_useds[_depth]);
bn_t capped_refund_gas;
// \f$g/5\f$
cgbn_div_ui32(_arith._env, capped_refund_gas, gas_left, 5);
// min ( \f$g/5\f$, \f$R_{g}\f$)
if (cgbn_compare(_arith._env, capped_refund_gas, _gas_refunds[_depth]) > 0)
{
cgbn_set(_arith._env, capped_refund_gas, _gas_refunds[_depth]);
}
// g^{*} = \f$T_{g} - g + min ( \f$g/5\f$, \f$R_{g}\f$)\f$
cgbn_add(_arith._env, gas_value, gas_left, capped_refund_gas);
// add to sender balance g^{*}
bn_t sender_balance;
bn_t sender_address;
// send back the gas left and gas refund to the sender
_transaction->get_sender(sender_address);
_transaction_touch_state->get_account_balance(sender_address, sender_balance);
cgbn_add(_arith._env, sender_balance, sender_balance, gas_value);
_transaction_touch_state->set_account_balance(sender_address, sender_balance);
// the gas value for the beneficiary is \f$T_{g} - g^{*}\f$
cgbn_sub(_arith._env, gas_value, _gas_limit, gas_value);
// update the transaction state
_transaction_touch_state->update_with_child_state(
*_touch_state_ptrs[_depth]);
_transaction_log_state->update_with_child_state(
*_log_state_ptrs[_depth]);
// set the eror code for a succesfull transaction
_error_code = ERR_NONE;
}
else
{
cgbn_mul(_arith._env, gas_value, _gas_limit, _gas_priority_fee);
// set z to the given error or 1 TODO: 1 in YP
_error_code = error_code;
}
// send the gas value to the beneficiary
bn_t beneficiary_balance;
_transaction_touch_state->get_account_balance(beneficiary, beneficiary_balance);
cgbn_add(_arith._env, beneficiary_balance, beneficiary_balance, gas_value);
_transaction_touch_state->set_account_balance(beneficiary, beneficiary_balance);
// update the final state modification done by the transaction
_transaction_touch_state->to_touch_state_data_t(
*_final_touch_state_data);
_accessed_state->to_accessed_state_data_t(
*_final_accessed_state_data);
*_final_error = _error_code;
delete _jump_destinations;
_jump_destinations = NULL;
}
__host__ __device__ __forceinline__ void child_CALL(
uint32_t &error_code,
message_t &new_message)
{
// increase depth and allocate memory if necessary
_depth = _depth + 1;
if (_depth == _allocated_depth)
{
grow();
}
// setup the new message call and start the execution of the call
_message_ptrs[_depth] = &new_message;
start_CALL(error_code);
}
__host__ static void get_cpu_instances(
evm_instances_t &instances,
const cJSON *test)
{
//setup the arithmetic environment
arith_t arith(cgbn_report_monitor, 0);
// get the world state
world_state_t *cpu_world_state;
cpu_world_state = new world_state_t(arith, test);
instances.world_state_data = cpu_world_state->_content;
delete cpu_world_state;
cpu_world_state = NULL;
// ge the current block
block_t *cpu_block = NULL;
cpu_block = new block_t(arith, test);
instances.block_data = cpu_block->_content;
delete cpu_block;
cpu_block = NULL;
// setup the keccak paramameters
keccak_t *keccak;
keccak = new keccak_t();
instances.sha3_parameters = keccak->_parameters;
delete keccak;
keccak = NULL;
// get the transactions
transaction_t::get_transactions(instances.transactions_data, test, instances.count);
// allocated the memory for accessed states
instances.accessed_states_data = accessed_state_t::get_cpu_instances(instances.count);
// allocated the memory for touch states
instances.touch_states_data = touch_state_t::get_cpu_instances(instances.count);
// allocated the memory for logs
instances.logs_data = log_state_t::get_cpu_instances(instances.count);
#ifdef TRACER
// allocated the memory for tracers
instances.tracers_data = tracer_t::get_cpu_instances(instances.count);
#endif
// alocate the memory for the result of the transactions
#ifndef ONLY_CPU
CUDA_CHECK(cudaMallocManaged(
(void **)&(instances.errors),
sizeof(uint32_t) * instances.count));
#else
instances.errors = new uint32_t[instances.count];
#endif
memset(instances.errors, ERR_NONE, sizeof(uint32_t) * instances.count);
}
__host__ static void get_gpu_instances(
evm_instances_t &gpu_instances,
evm_instances_t &cpu_instances)
{
gpu_instances.count = cpu_instances.count;
gpu_instances.world_state_data = cpu_instances.world_state_data;
gpu_instances.block_data = cpu_instances.block_data;
gpu_instances.sha3_parameters = cpu_instances.sha3_parameters;
gpu_instances.transactions_data = cpu_instances.transactions_data;
gpu_instances.accessed_states_data = accessed_state_t::get_gpu_instances_from_cpu_instances(cpu_instances.accessed_states_data, cpu_instances.count);
gpu_instances.touch_states_data = touch_state_t::get_gpu_instances_from_cpu_instances(cpu_instances.touch_states_data, cpu_instances.count);
gpu_instances.logs_data = log_state_t::get_gpu_instances_from_cpu_instances(cpu_instances.logs_data, cpu_instances.count);
#ifdef TRACER
gpu_instances.tracers_data = tracer_t::get_gpu_instances_from_cpu_instances(cpu_instances.tracers_data, cpu_instances.count);
#endif
gpu_instances.errors = cpu_instances.errors;
}
__host__ static void get_cpu_instances_from_gpu_instances(
evm_instances_t &cpu_instances,
evm_instances_t &gpu_instances)
{
cpu_instances.count = gpu_instances.count;
cpu_instances.world_state_data = gpu_instances.world_state_data;
cpu_instances.block_data = gpu_instances.block_data;
cpu_instances.sha3_parameters = gpu_instances.sha3_parameters;
cpu_instances.transactions_data = gpu_instances.transactions_data;
accessed_state_t::free_cpu_instances(cpu_instances.accessed_states_data, cpu_instances.count);
cpu_instances.accessed_states_data = accessed_state_t::get_cpu_instances_from_gpu_instances(gpu_instances.accessed_states_data, gpu_instances.count);
touch_state_t::free_cpu_instances(cpu_instances.touch_states_data, cpu_instances.count);
cpu_instances.touch_states_data = touch_state_t::get_cpu_instances_from_gpu_instances(gpu_instances.touch_states_data, gpu_instances.count);
log_state_t::free_cpu_instances(cpu_instances.logs_data, cpu_instances.count);
cpu_instances.logs_data = log_state_t::get_cpu_instances_from_gpu_instances(gpu_instances.logs_data, gpu_instances.count);
#ifdef TRACER
tracer_t::free_cpu_instances(cpu_instances.tracers_data, cpu_instances.count);
cpu_instances.tracers_data = tracer_t::get_cpu_instances_from_gpu_instances(gpu_instances.tracers_data, gpu_instances.count);
#endif
cpu_instances.errors = gpu_instances.errors;
}
__host__ static void free_instances(
evm_instances_t &cpu_instances)
{
arith_t arith(cgbn_report_monitor, 0);
world_state_t *cpu_world_state;
cpu_world_state = new world_state_t(arith, cpu_instances.world_state_data);
cpu_world_state->free_content();
delete cpu_world_state;
cpu_world_state = NULL;
block_t *cpu_block = NULL;
cpu_block = new block_t(arith, cpu_instances.block_data);
cpu_block->free_content();
delete cpu_block;
cpu_block = NULL;
keccak_t *keccak;
keccak = new keccak_t(cpu_instances.sha3_parameters);
keccak->free_parameters();
delete keccak;
keccak = NULL;
transaction_t::free_instances(cpu_instances.transactions_data, cpu_instances.count);
cpu_instances.transactions_data = NULL;
accessed_state_t::free_cpu_instances(cpu_instances.accessed_states_data, cpu_instances.count);
cpu_instances.accessed_states_data = NULL;
touch_state_t::free_cpu_instances(cpu_instances.touch_states_data, cpu_instances.count);
cpu_instances.touch_states_data = NULL;
log_state_t::free_cpu_instances(cpu_instances.logs_data, cpu_instances.count);
cpu_instances.logs_data = NULL;
#ifdef TRACER
tracer_t::free_cpu_instances(cpu_instances.tracers_data, cpu_instances.count);
cpu_instances.tracers_data = NULL;
#endif
#ifndef ONLY_CPU
CUDA_CHECK(cudaFree(cpu_instances.errors));
#else
delete[] cpu_instances.errors;
#endif
cpu_instances.errors = NULL;
}
__host__ static void print_evm_instances_t(
arith_t &arith,
evm_instances_t instances)
{
world_state_t *cpu_world_state;
cpu_world_state = new world_state_t(arith, instances.world_state_data);
printf("World state:\n");
cpu_world_state->print();
delete cpu_world_state;
cpu_world_state = NULL;
block_t *cpu_block = NULL;
cpu_block = new block_t(arith, instances.block_data);
printf("Block:\n");
cpu_block->print();
delete cpu_block;
cpu_block = NULL;
printf("Instances:\n");
for (size_t idx = 0; idx < instances.count; idx++)
{
printf("Instance %lu\n", idx);
transaction_t::print_transaction_data_t(arith, instances.transactions_data[idx]);
accessed_state_t::print_accessed_state_data_t(arith, instances.accessed_states_data[idx]);
touch_state_t::print_touch_state_data_t(arith, instances.touch_states_data[idx]);
log_state_t::print_log_state_data_t(arith, instances.logs_data[idx]);
#ifdef TRACER
tracer_t::print_tracer_data_t(arith, instances.tracers_data[idx]);
#endif
printf("Error: %u\n", instances.errors[idx]);
}
}
__host__ static cJSON *json_from_evm_instances_t(
arith_t &arith,
evm_instances_t instances)
{
cJSON *root = cJSON_CreateObject();
world_state_t *cpu_world_state;
cpu_world_state = new world_state_t(arith, instances.world_state_data);
cJSON *world_state_json = cpu_world_state->json();
cJSON_AddItemToObject(root, "pre", world_state_json);
delete cpu_world_state;
cpu_world_state = NULL;
block_t *cpu_block = NULL;
cpu_block = new block_t(arith, instances.block_data);
cJSON *block_json = cpu_block->json();
cJSON_AddItemToObject(root, "env", block_json);
delete cpu_block;
cpu_block = NULL;
cJSON *instances_json = cJSON_CreateArray();
cJSON_AddItemToObject(root, "post", instances_json);
transaction_t *transaction;
for (uint32_t idx = 0; idx < instances.count; idx++)
{
cJSON *instance_json = cJSON_CreateObject();
cJSON_AddItemToArray(instances_json, instance_json);
transaction = new transaction_t(arith, &(instances.transactions_data[idx]));
cJSON *transaction_json = transaction->json();
cJSON_AddItemToObject(instance_json, "msg", transaction_json);
delete transaction;
transaction = NULL;
cJSON *accessed_state_json = accessed_state_t::json_from_accessed_state_data_t(arith, instances.accessed_states_data[idx]);
cJSON_AddItemToObject(instance_json, "access_state", accessed_state_json);
cJSON *touch_state_json = touch_state_t::json_from_touch_state_data_t(arith, instances.touch_states_data[idx]);
cJSON_AddItemToObject(instance_json, "touch_state", touch_state_json);
cJSON *log_state_json = log_state_t::json_from_log_state_data_t(arith, instances.logs_data[idx]);
cJSON_AddItemToObject(instance_json, "log_state", log_state_json);
#ifdef TRACER
cJSON *tracer_json = tracer_t::json_from_tracer_data_t(arith, instances.tracers_data[idx]);
cJSON_AddItemToObject(instance_json, "traces", tracer_json);
#endif
cJSON_AddItemToObject(instance_json, "error", cJSON_CreateNumber(instances.errors[idx]));
cJSON_AddItemToObject(instance_json, "success", cJSON_CreateBool((instances.errors[idx] == ERR_NONE) || (instances.errors[idx] == ERR_RETURN) || (instances.errors[idx] == ERR_SUCCESS)));
}
return root;
}
};
template <class params>
__global__ void kernel_evm(
cgbn_error_report_t *report,
typename evm_t<params>::evm_instances_t *instances)
{
uint32_t instance = (blockIdx.x * blockDim.x + threadIdx.x) / params::TPI;
typedef transaction_t<params> transaction_t;
if (instance >= instances->count)
return;
typedef arith_env_t<params> arith_t;
typedef typename arith_t::bn_t bn_t;
typedef evm_t<params> evm_t;
// setup arith
arith_t arith(
cgbn_report_monitor,
report,
instance);
// setup evm
evm_t *evm = NULL;
evm = new evm_t(
arith,
instances->world_state_data,
instances->block_data,
instances->sha3_parameters,
&(instances->transactions_data[instance]),
&(instances->accessed_states_data[instance]),
&(instances->touch_states_data[instance]),
&(instances->logs_data[instance]),
#ifdef TRACER
&(instances->tracers_data[instance]),
#endif
instance,
&(instances->errors[instance]));
uint32_t tmp_error_code;
tmp_error_code = ERR_NONE;
// run the evm
evm->run(tmp_error_code);
// free the evm
delete evm;
evm = NULL;
}
#endif