diff --git a/bindings/go/evmc/host.go b/bindings/go/evmc/host.go index 0a97aa8..8e6faca 100644 --- a/bindings/go/evmc/host.go +++ b/bindings/go/evmc/host.go @@ -71,8 +71,8 @@ func goByteSlice(data *C.uint8_t, size C.size_t) []byte { type HostContext interface { AccountExists(addr common.Address) bool - GetStorage(addr common.Address, key common.Hash) common.Hash - SetStorage(addr common.Address, key common.Hash, value common.Hash) StorageStatus + GetStorage(addr common.Address, key common.Hash) (common.Hash, error) + SetStorage(addr common.Address, key common.Hash, value common.Hash) (StorageStatus, error) GetBalance(addr common.Address) (common.Hash, error) GetCodeSize(addr common.Address) (int, error) GetCodeHash(addr common.Address) (common.Hash, error) @@ -95,18 +95,26 @@ func accountExists(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) C.bool { } //export getStorage -func getStorage(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.struct_evmc_uint256be) { +func getStorage(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.struct_evmc_uint256be) C.bool { idx := int((*C.struct_extended_context)(pCtx).index) ctx := getHostContext(idx) - value := ctx.GetStorage(goAddress(*pAddr), goHash(*pKey)) + value, err := ctx.GetStorage(goAddress(*pAddr), goHash(*pKey)) + if err != nil { + return false + } *pResult = evmcUint256be(value) + return true } //export setStorage func setStorage(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.struct_evmc_uint256be, pVal *C.struct_evmc_uint256be) C.enum_evmc_storage_status { idx := int((*C.struct_extended_context)(pCtx).index) ctx := getHostContext(idx) - return C.enum_evmc_storage_status(ctx.SetStorage(goAddress(*pAddr), goHash(*pKey), goHash(*pVal))) + status, err := ctx.SetStorage(goAddress(*pAddr), goHash(*pKey), goHash(*pVal)) + if err != nil { + return C.EVMC_STORAGE_NON_EXISTING_ACCOUNT + } + return C.enum_evmc_storage_status(status) } //export getBalance diff --git a/examples/example_host.cpp b/examples/example_host.cpp index e675f86..3be2077 100644 --- a/examples/example_host.cpp +++ b/examples/example_host.cpp @@ -24,6 +24,11 @@ bool operator<(const evmc_uint256be& a, const evmc_uint256be& b) return std::memcmp(a.bytes, b.bytes, sizeof(a)) < 0; } +bool operator==(const evmc_uint256be& a, const evmc_uint256be& b) +{ + return std::memcmp(a.bytes, b.bytes, sizeof(a)) == 0; +} + struct account { evmc_uint256be balance = {}; @@ -47,15 +52,19 @@ static bool account_exists(evmc_context* context, const evmc_address* address) return host->accounts.find(*address) != host->accounts.end(); } -static void get_storage(evmc_uint256be* result, +static bool get_storage(evmc_uint256be* result, evmc_context* context, const evmc_address* address, const evmc_uint256be* key) { - (void)result; - (void)context; - (void)address; - (void)key; + example_host_context* host = static_cast(context); + auto it = host->accounts.find(*address); + if (it != host->accounts.end()) + { + *result = it->second.storage[*key]; + return true; + } + return false; } static enum evmc_storage_status set_storage(evmc_context* context, @@ -63,11 +72,26 @@ static enum evmc_storage_status set_storage(evmc_context* context, const evmc_uint256be* key, const evmc_uint256be* value) { - (void)context; - (void)address; - (void)key; - (void)value; - return EVMC_STORAGE_UNCHANGED; + example_host_context* host = static_cast(context); + auto accountIt = host->accounts.find(*address); + if (accountIt == host->accounts.end()) + return EVMC_STORAGE_NON_EXISTING_ACCOUNT; + + auto storageIt = accountIt->second.storage.find(*key); + if (storageIt == accountIt->second.storage.end()) + { + accountIt->second.storage.emplace(std::make_pair(*key, *value)); + return EVMC_STORAGE_ADDED; + } + else if (storageIt->second == *value) + { + return EVMC_STORAGE_UNCHANGED; + } + else + { + storageIt->second = *value; + return EVMC_STORAGE_MODIFIED; + } } static bool get_balance(evmc_uint256be* result, evmc_context* context, const evmc_address* address) diff --git a/include/evmc/evmc.h b/include/evmc/evmc.h index 12e2bef..2a937fa 100644 --- a/include/evmc/evmc.h +++ b/include/evmc/evmc.h @@ -409,15 +409,18 @@ typedef bool (*evmc_account_exists_fn)(struct evmc_context* context, /** * Get storage callback function. * - * This callback function is used by an EVM to query the given contract - * storage entry. - * @param[out] result The returned storage value. - * @param context The pointer to the Host execution context. - * @see ::evmc_context. - * @param address The address of the contract. - * @param key The index of the storage entry. + * This callback function is used by a VM to query the given contract storage entry. + * + * @param[out] result The pointer to the place where to put the result value. + * @param context The pointer to the Host execution context. + * @param address The address of the account. + * @param key The index of the account's storage entry. + * @return If the account exists the value is put at the location + * pointed by @p result and true is returned. + * If the account does not exist false is returned without + * modifying the memory pointed by @p result. */ -typedef void (*evmc_get_storage_fn)(struct evmc_uint256be* result, +typedef bool (*evmc_get_storage_fn)(struct evmc_uint256be* result, struct evmc_context* context, const struct evmc_address* address, const struct evmc_uint256be* key); @@ -431,6 +434,7 @@ typedef void (*evmc_get_storage_fn)(struct evmc_uint256be* result, * - 0 is zero value, * - X != 0 (X is any value other than 0), * - Y != X, Y != 0 (Y is any value other than X and 0), + * - Z != Y (Z is any value other than Y), * - the "->" means the change from one value to another. */ enum evmc_storage_status @@ -458,21 +462,25 @@ enum evmc_storage_status /** * A storage item has been deleted: X -> 0. */ - EVMC_STORAGE_DELETED = 4 + EVMC_STORAGE_DELETED = 4, + + /** + * An attempt to modify storage of an non-existing account. + */ + EVMC_STORAGE_NON_EXISTING_ACCOUNT = 5 }; /** * Set storage callback function. * - * This callback function is used by an EVM to update the given contract - * storage entry. + * This callback function is used by an EVM to update the given contract storage entry. + * * @param context The pointer to the Host execution context. - * @see ::evmc_context. * @param address The address of the contract. * @param key The index of the storage entry. * @param value The value to be stored. - * @return The effect on the storage item, @see ::evmc_storage_status. + * @return The effect on the storage item. @see ::evmc_storage_status. */ typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* context, const struct evmc_address* address,