diff --git a/examples/capi.c b/examples/capi.c index dad8e34..6252a57 100644 --- a/examples/capi.c +++ b/examples/capi.c @@ -24,28 +24,12 @@ static void print_address(const struct evm_uint160be* address) printf("%x", address->bytes[i] & 0xff); } -static void query(union evm_variant* result, - struct evm_env* env, - enum evm_query_key key, - const struct evm_uint160be* address) { - printf("EVM-C: QUERY %d\n", key); - switch (key) { - case EVM_CODE_BY_ADDRESS: - result->data = NULL; - result->data_size = 0; - break; - - case EVM_BALANCE: - result->uint256be = balance(env, address); - break; - - case EVM_ACCOUNT_EXISTS: - result->int64 = 0; - break; - - default: - result->int64 = 0; - } +static int account_exists(struct evm_env* env, + const struct evm_uint160be* address) { + printf("EVM-C: EXISTS @"); + print_address(address); + printf("\n"); + return 0; } static void get_storage(struct evm_uint256be* result, @@ -68,6 +52,26 @@ static void set_storage(struct evm_env* env, printf("\n"); } +static void get_balance(struct evm_uint256be* result, + struct evm_env* env, + const struct evm_uint160be* address) +{ + printf("EVM-C: BALANCE @"); + print_address(address); + printf("\n"); + *result = balance(env, address); +} + +static size_t get_code(const uint8_t** code, + struct evm_env* env, + const struct evm_uint160be* address) +{ + printf("EVM-C: CODE @"); + print_address(address); + printf("\n"); + return 0; +} + static void selfdestruct(struct evm_env* env, const struct evm_uint160be* address, const struct evm_uint160be* beneficiary) @@ -109,9 +113,11 @@ static void evm_log(struct evm_env* env, const struct evm_uint160be* address, } static const struct evm_host example_host = { - query, + account_exists, get_storage, set_storage, + get_balance, + get_code, selfdestruct, call, get_tx_context, diff --git a/include/evm.h b/include/evm.h index 89cbb2b..b80f6ad 100644 --- a/include/evm.h +++ b/include/evm.h @@ -183,73 +183,16 @@ struct evm_result { } reserved; }; -/// The query callback key. -enum evm_query_key { - EVM_CODE_BY_ADDRESS = 10, ///< Code by an address for EXTCODECOPY. - EVM_CODE_SIZE = 11, ///< Code size by an address for EXTCODESIZE. - EVM_BALANCE = 12, ///< Balance of a given address for BALANCE. - EVM_ACCOUNT_EXISTS = 14, ///< Check if an account exists. -}; - - -/// Variant type to represent possible types of values used in EVM. +/// Check account existence callback function /// -/// Type-safety is lost around the code that uses this type. We should have -/// complete set of unit tests covering all possible cases. -/// The size of the type is 64 bytes and should fit in single cache line. -union evm_variant { - /// A host-endian 64-bit integer. - int64_t int64; - - /// A big-endian 256-bit integer or hash. - struct evm_uint256be uint256be; - - /// A memory reference. - struct { - /// Pointer to the data. - uint8_t const* data; - - /// Size of the referenced memory/data. - size_t data_size; - }; -}; - -/// Query callback function. -/// -/// This callback function is used by the EVM to query the host application -/// about additional information about accounts in the state required to -/// execute EVM code. -/// @param[out] result The result of the query. -/// @param env Pointer to execution environment managed by the host -/// application. -/// @param key The kind of the query. See evm_query_key -/// and details below. +/// This callback function is used by the EVM to check if +/// there exists an account at given address. +/// @param env Pointer to execution environment managed by the host +/// application. /// @param address The address of the account the query is about. -/// -/// ## Types of queries -/// -/// - ::EVM_CODE_BY_ADDRESS -/// @result evm_variant::data The appropriate code for the given address or NULL if not found. -/// -/// - ::EVM_CODE_SIZE -/// @result evm_variant::int64 The appropriate code size for the given address or 0 if not found. -/// -/// - ::EVM_BALANCE -/// @result evm_variant::uint256be The appropriate balance for the given address or 0 if not found. -/// -/// - ::EVM_ACCOUNT_EXISTS -/// @result evm_variant::int64 1 if exists, 0 if not. -/// -/// -/// @todo -/// - Consider swapping key and address arguments, -/// e.g. `query(result, env, addr, EVM_SLOAD, k)`. -/// - Consider renaming key argument to something else. Key is confusing -/// especially for SSTORE and SLOAD. Maybe "kind"? -typedef void (*evm_query_state_fn)(union evm_variant* result, - struct evm_env* env, - enum evm_query_key key, - const struct evm_uint160be* address); +/// @return 1 if exists, 0 otherwise. +typedef int (*evm_account_exists_fn)(struct evm_env* env, + const struct evm_uint160be* address); /// Get storage callback function. /// @@ -279,6 +222,32 @@ typedef void (*evm_set_storage_fn)(struct evm_env* env, const struct evm_uint256be* key, const struct evm_uint256be* value); +/// Get balance callback function. +/// +/// This callback function is used by an EVM to query the balance of the given +/// address. +/// @param[out] result The returned balance value. +/// @param env Pointer to execution environment managed by the host +/// application. +/// @param address The address. +typedef void (*evm_get_balance_fn)(struct evm_uint256be* result, + struct evm_env* env, + const struct evm_uint160be* address); + +/// Get code callback function. +/// +/// This callback function is used by an EVM to get the code of a contract of +/// given address. +/// @param[out] result_code The pointer to the contract code. This argument is +/// optional. If NULL is provided, the host MUST only +/// return the code size. +/// @param env Pointer to execution context managed by the Host. +/// @param address The address of the contract. +/// @return The size of the code. +typedef size_t (*evm_get_code_fn)(const uint8_t** result_code, + struct evm_env* env, + const struct evm_uint160be* address); + /// Selfdestruct callback function. /// /// This callback function is used by an EVM to SELFDESTRUCT given contract. @@ -327,10 +296,14 @@ typedef void (*evm_call_fn)( /// realisation of OOP interface (only virtual methods, no data). /// Host implementations SHOULD create constant singletons of this (similar /// to vtables) to lower the maintenance and memory management cost. +/// +/// @todo Merge evm_host with evm_env? struct evm_host { - evm_query_state_fn query; + evm_account_exists_fn account_exists; evm_get_storage_fn get_storage; evm_set_storage_fn set_storage; + evm_get_balance_fn get_balance; + evm_get_code_fn get_code; evm_selfdestruct_fn selfdestruct; evm_call_fn call; evm_get_tx_context_fn get_tx_context;