diff --git a/.gitignore b/.gitignore index 7d98ae5..a5bf609 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,7 @@ dtmp cuevm.out geth.out *.out -*.jsonl \ No newline at end of file +*.jsonl + +# fuzzing +**/__pycache__/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 33637fb..fcbebb8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/sdcioc/CuBigInt.git [submodule "CuEVM/libraries/CGBN"] path = CuEVM/libraries/CGBN - url = https://github.com/sdcioc/CGBN.git + url = https://github.com/sbip-sg/CGBN.git [submodule "CuEVM/libraries/CuCrypto"] path = CuEVM/libraries/CuCrypto url = https://github.com/sdcioc/CuCrypto.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 5737603..6b39a74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,9 @@ option(ENABLE_PAIRING_CODE "Enable ec pairing precompile code" OFF) option(ENABLE_EIP_3155_OPTIONAL "Enable EIP_3155 optional tracer" ON) option(TESTS "Enable tests" ON) option(TESTS_GPU "Enable GPU tests" OFF) +option(BUILD_LIBRARY "Build Python library" OFF) set(EVM_VERSION "SHANGHAI" CACHE STRING "EVM version to use") - +set(CGBN_TPI "32" CACHE STRING "Thread per instance for CGBN") project("cuevm" VERSION 0.1.0 DESCRIPTION "A CUDA EVM Interpreter" @@ -35,8 +36,11 @@ if(DOCS) add_subdirectory("${PROJECT_SOURCE_DIR}/docs") endif() -if (CPU OR GPU OR TESTS) +if (CPU OR GPU OR TESTS OR BUILD_LIBRARY) add_subdirectory("${PROJECT_SOURCE_DIR}/CuEVM") + if(BUILD_LIBRARY) + target_compile_definitions(CuEVM PRIVATE BUILD_LIBRARY) + endif() if(ENABLE_EIP_3155) target_compile_definitions(CuEVM PRIVATE EIP_3155) endif() @@ -58,20 +62,20 @@ if(CPU) $ $ ) - + set_target_properties(${CPU_INTERPRETER} PROPERTIES CUDA_SEPARABLE_COMPILATION ON CUDA_RESOLVE_DEVICE_SYMBOLS ON POSITION_INDEPENDENT_CODE ON ) - + # Link the library to its dependencies # our own libraries first target_link_libraries(${CPU_INTERPRETER} PRIVATE CGBN CuCrypto CuBigInt CuEVM) # then the external ones target_link_libraries(${CPU_INTERPRETER} PUBLIC gmp cjson ${CUDA_LIBRARIES}) - + target_compile_options(${CPU_INTERPRETER} PRIVATE $<$:-lineinfo --std=c++20 -rdc=true --expt-relaxed-constexpr>) if(ENABLE_EIP_3155) target_compile_definitions(${CPU_INTERPRETER} PRIVATE EIP_3155) @@ -80,43 +84,99 @@ if(CPU) target_compile_definitions(${CPU_INTERPRETER} PRIVATE EIP_3155_OPTIONAL) endif() target_compile_definitions(${CPU_INTERPRETER} PRIVATE EVM_VERSION=${EVM_VERSION}) + + target_compile_definitions(${CPU_INTERPRETER} PRIVATE CGBN_TPI=${CGBN_TPI}) endif() if(GPU) - set(GPU_INTERPRETER ${PROJECT_NAME}_GPU) - # GPU - add_executable(${GPU_INTERPRETER} - "${PROJECT_SOURCE_DIR}/interpreter/interpreter.cu" - $ - $ - $ - $ - ) - - set_target_properties(${GPU_INTERPRETER} + if(BUILD_LIBRARY) + # Find Python libraries + find_package(PythonLibs REQUIRED) + include_directories(${PYTHON_INCLUDE_DIRS}) + # Build as a shared library + add_library(${PROJECT_NAME} SHARED + "${PROJECT_SOURCE_DIR}/interpreter/libcuevm.cu" + "${PROJECT_SOURCE_DIR}/interpreter/interpreter.cu" + "${PROJECT_SOURCE_DIR}/interpreter/python_utils.cu" + $ + $ + $ + $ + ) + + # Apply flags for library + target_compile_options(${PROJECT_NAME} PRIVATE $<$:--shared -Xcompiler '-fPIC'>) + if(CMAKE_BUILD_TYPE MATCHES Debug) + target_compile_options(${PROJECT_NAME} PRIVATE $<$:-g>) + endif() + # set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "cuevm") + set_target_properties(${PROJECT_NAME} PROPERTIES + OUTPUT_NAME "cuevm" CUDA_SEPARABLE_COMPILATION ON CUDA_RESOLVE_DEVICE_SYMBOLS ON - POSITION_INDEPENDENT_CODE ON - ) - - # Link the library to its dependencies - # our own libraries first - target_link_libraries(${GPU_INTERPRETER} PRIVATE CGBN CuCrypto CuBigInt CuEVM) - # then the external ones - target_link_libraries(${GPU_INTERPRETER} PUBLIC gmp cjson ${CUDA_LIBRARIES}) - - target_compile_options(${GPU_INTERPRETER} PRIVATE $<$:-lineinfo --std=c++20 -rdc=true --expt-relaxed-constexpr>) - if(ENABLE_EIP_3155) - target_compile_definitions(${GPU_INTERPRETER} PRIVATE EIP_3155) - endif() - if(ENABLE_EIP_3155_OPTIONAL) - target_compile_definitions(${GPU_INTERPRETER} PRIVATE EIP_3155_OPTIONAL) - endif() - target_compile_definitions(${GPU_INTERPRETER} PRIVATE EVM_VERSION=${EVM_VERSION}) + CUDA_RUNTIME_LIBRARY Shared # Ensure CUDA runtime library is shared + ) + + # Link the library to its dependencies + # our own libraries first + target_link_libraries(${PROJECT_NAME} PRIVATE CGBN CuCrypto CuBigInt CuEVM) + # then the external ones + target_link_libraries(${PROJECT_NAME} PUBLIC gmp cjson ${PYTHON_LIBRARIES} ${CUDA_LIBRARIES}) + + target_compile_options(${PROJECT_NAME} PRIVATE $<$:-lineinfo --std=c++20 -rdc=true --expt-relaxed-constexpr>) + if(ENABLE_EIP_3155) + target_compile_definitions(${PROJECT_NAME} PRIVATE EIP_3155) + endif() + if(ENABLE_EIP_3155_OPTIONAL) + target_compile_definitions(${PROJECT_NAME} PRIVATE EIP_3155_OPTIONAL) + endif() + target_compile_definitions(${PROJECT_NAME} PRIVATE EVM_VERSION=${EVM_VERSION}) + + target_compile_definitions(${PROJECT_NAME} PRIVATE GPU) + + target_compile_definitions(${PROJECT_NAME} PRIVATE CGBN_TPI=${CGBN_TPI}) + + else() + + set(GPU_INTERPRETER ${PROJECT_NAME}_GPU) + # GPU + add_executable(${GPU_INTERPRETER} + "${PROJECT_SOURCE_DIR}/interpreter/interpreter.cu" + $ + $ + $ + $ + ) + + set_target_properties(${GPU_INTERPRETER} + PROPERTIES + CUDA_SEPARABLE_COMPILATION ON + CUDA_RESOLVE_DEVICE_SYMBOLS ON + POSITION_INDEPENDENT_CODE ON + ) + + # Link the library to its dependencies + # our own libraries first + target_link_libraries(${GPU_INTERPRETER} PRIVATE CGBN CuCrypto CuBigInt CuEVM) + # then the external ones + target_link_libraries(${GPU_INTERPRETER} PUBLIC gmp cjson ${CUDA_LIBRARIES}) + + target_compile_options(${GPU_INTERPRETER} PRIVATE $<$:-lineinfo --std=c++20 -rdc=true --expt-relaxed-constexpr>) + if(ENABLE_EIP_3155) + target_compile_definitions(${GPU_INTERPRETER} PRIVATE EIP_3155) + endif() + if(ENABLE_EIP_3155_OPTIONAL) + target_compile_definitions(${GPU_INTERPRETER} PRIVATE EIP_3155_OPTIONAL) + endif() + target_compile_definitions(${GPU_INTERPRETER} PRIVATE EVM_VERSION=${EVM_VERSION}) + + target_compile_definitions(${GPU_INTERPRETER} PRIVATE GPU) + + target_compile_definitions(${GPU_INTERPRETER} PRIVATE CGBN_TPI=${CGBN_TPI}) + endif() - target_compile_definitions(${GPU_INTERPRETER} PRIVATE GPU) endif() if(TESTS) diff --git a/CuEVM/CMakeLists.txt b/CuEVM/CMakeLists.txt index 471ef9b..7910197 100644 --- a/CuEVM/CMakeLists.txt +++ b/CuEVM/CMakeLists.txt @@ -29,7 +29,7 @@ if (NOT CMAKE_CUDA_ARCHITECTURES) set(CMAKE_CUDA_ARCHITECTURES ${CUDA_COMPUTE_CAPABILITY}) endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) - +set(CGBN_TPI "32" CACHE STRING "Thread per instance for CGBN") find_package(GMP REQUIRED) find_package(cJSON REQUIRED) # Assuming cJSON is available as a find package @@ -74,5 +74,5 @@ target_link_libraries(${PROJECT_NAME} PUBLIC gmp cjson ${CUDA_LIBRARIES}) # Add specific NVCC flags using target_compile_options (if necessary) target_compile_options(${PROJECT_NAME} PRIVATE $<$:-lineinfo --std=c++20 -rdc=true --expt-relaxed-constexpr>) - +target_compile_definitions(${PROJECT_NAME} PRIVATE CGBN_TPI=${CGBN_TPI}) diff --git a/CuEVM/include/CuEVM/core/byte_array.cuh b/CuEVM/include/CuEVM/core/byte_array.cuh index 5b85721..0cad63f 100644 --- a/CuEVM/include/CuEVM/core/byte_array.cuh +++ b/CuEVM/include/CuEVM/core/byte_array.cuh @@ -11,6 +11,7 @@ #include #include +#include namespace CuEVM { enum PaddingDirection { NO_PADDING = 0, LEFT_PADDING = 1, RIGHT_PADDING = 2 }; @@ -200,8 +201,13 @@ struct byte_array_t { */ __host__ __device__ static void reset_return_data(byte_array_t *&return_data_ptr) { - if (return_data_ptr != nullptr) delete return_data_ptr; - return_data_ptr = new byte_array_t(); + return_data_ptr->free(); + // printf("reset return data thread %d", THREADIDX); + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // if (return_data_ptr->data != nullptr) delete[] return_data_ptr->data; + // return_data_ptr->data = nullptr; + // __ONE_GPU_THREAD_WOSYNC_END__ + // return_data_ptr->size = 0; } private: diff --git a/CuEVM/include/CuEVM/core/evm_word.cuh b/CuEVM/include/CuEVM/core/evm_word.cuh index 715601d..08a7a2c 100644 --- a/CuEVM/include/CuEVM/core/evm_word.cuh +++ b/CuEVM/include/CuEVM/core/evm_word.cuh @@ -4,7 +4,6 @@ // SPDX-License-Identifier: MIT #pragma once -#include #include #include @@ -30,6 +29,7 @@ struct evm_word_t : cgbn_mem_t { */ __host__ __device__ evm_word_t(uint32_t value); + __host__ __device__ void set_zero(); /** * The assignment operator. * @param[in] src The source evm_word_t @@ -54,6 +54,7 @@ struct evm_word_t : cgbn_mem_t { * @return 1 for equal, 0 otherwise */ __host__ __device__ int32_t operator==(const uint32_t &value) const; + __host__ __device__ int32_t operator<(const uint32_t &value) const; /** * Set the evm_word_t from a hex string. * The hex string is in Big Endian format. @@ -62,13 +63,21 @@ struct evm_word_t : cgbn_mem_t { */ __host__ int32_t from_hex(const char *hex_string); /** - * Set the evm_word_t from a byte array. + * Set the evm_word_t from a byte array, optimized for parallel threads. * The byte array is in Big Endian format. * @param[in] byte_array The source byte array * @param[in] endian The endian format * @return 0 for success, 1 otherwise */ __host__ __device__ int32_t from_byte_array_t(byte_array_t &byte_array, int32_t endian = LITTLE_ENDIAN); + /** + * Set the evm_word_t from a byte array. Compatible with CPU version. + * The byte array is in Big Endian format. + * @param[in] byte_array The source byte array + * @param[in] endian The endian format + * @return 0 for success, 1 otherwise + */ + __host__ int32_t from_byte_array_t_loop(byte_array_t &byte_array, int32_t endian = LITTLE_ENDIAN); /** * Set the evm_word_t from a size_t. * @param[in] value The source size_t @@ -115,6 +124,7 @@ struct evm_word_t : cgbn_mem_t { __host__ __device__ char *to_hex(char *hex_string = nullptr, int32_t pretty = 0, uint32_t count = CuEVM::cgbn_limbs) const; + __host__ __device__ char *address_to_hex(char *hex_string = nullptr, uint32_t count = CuEVM::cgbn_limbs) const; __host__ __device__ void print_as_compact_hex() const; /** diff --git a/CuEVM/include/CuEVM/core/jump_destinations.cuh b/CuEVM/include/CuEVM/core/jump_destinations.cuh index 11f1e45..6c06a75 100644 --- a/CuEVM/include/CuEVM/core/jump_destinations.cuh +++ b/CuEVM/include/CuEVM/core/jump_destinations.cuh @@ -19,15 +19,15 @@ namespace CuEVM { */ struct jump_destinations_t { private: - byte_array_t - destinations; /**< The array of valid JUMPDESTs pc \f$D(c)\f$ */ - + uint16_t* destinations; /**< The array of valid JUMPDESTs pc \f$D(c)\f$ */ + uint32_t capacity; + uint32_t size; /**< The size of the jump dest, smaller than capacity*/ public: /** * Cosntructor from the given code * @param[in] byte_code The code */ - __host__ __device__ jump_destinations_t(CuEVM::byte_array_t &byte_code); + __host__ __device__ jump_destinations_t(CuEVM::byte_array_t& byte_code); /** * Destructor of the class @@ -35,6 +35,8 @@ struct jump_destinations_t { */ __host__ __device__ ~jump_destinations_t(); + __host__ __device__ void set_bytecode(CuEVM::byte_array_t& byte_code); + /** * Find out if a given pc is a valid JUMPDEST * @param[in] pc The pc to check @@ -42,6 +44,8 @@ struct jump_destinations_t { */ __host__ __device__ uint32_t has(uint32_t pc); + __host__ __device__ int32_t grow_capacity(uint32_t new_capacity); + /** * Print the destinations */ diff --git a/CuEVM/include/CuEVM/core/message.cuh b/CuEVM/include/CuEVM/core/message.cuh index ba58393..a4f6840 100644 --- a/CuEVM/include/CuEVM/core/message.cuh +++ b/CuEVM/include/CuEVM/core/message.cuh @@ -8,35 +8,65 @@ #define _CUEVM_MESSAGE_H_ #include -#include #include #include #include +#include + +namespace CuEVM { +struct evm_message_call_t_shadow { + // store in global mem to load back + /* + evm_word_t *sender; + evm_word_t *recipient; + evm_word_t *contract_address; + evm_word_t *gas_limit; + evm_word_t *value; + evm_word_t *storage_address; + evm_word_t *return_data_offset; + evm_word_t *return_data_size; + */ + evm_word_t *params_data; // store 8 evm_word_t elements + CuEVM::byte_array_t *data; /**< The data YP: \f$d\f$ */ + CuEVM::byte_array_t *byte_code; /**< The byte code YP: \f$b\f$ or \f$I_{b}\f$*/ -namespace CuEVM { - /** - * The message call struct. - * YP: \f$M\f$ - */ - struct evm_message_call_t { - evm_word_t sender; /**< The sender address YP: \f$s\f$ */ - evm_word_t recipient; /**< The recipient address YP: \f$r\f$ also \f$I_{a}\f$ */ - evm_word_t contract_address; /**< The contract address YP: \f$c\f$ */ - evm_word_t gas_limit; /**< The gas limit YP: \f$g\f$ */ - evm_word_t value; /**< The value YP: \f$v\f$ or \f$v^{'}\f$ for DelegateCALL */ - uint32_t depth; /**< The depth YP: \f$e\f$ */ - uint32_t call_type; /**< The call type internal has the opcode */ - evm_word_t storage_address; /**< The storage address YP: \f$a\f$ */ - CuEVM::byte_array_t data; /**< The data YP: \f$d\f$ */ - CuEVM::byte_array_t byte_code; /**< The byte code YP: \f$b\f$ or \f$I_{b}\f$*/ + uint32_t static_env; /**< The static flag (STATICCALL) YP: \f$w\f$ */ + uint32_t depth; /**< The depth YP: \f$e\f$ */ + uint32_t call_type; /**< The call type internal has the opcode */ + + CuEVM::jump_destinations_t *jump_destinations; /**< The jump destinations */ + __host__ __device__ evm_message_call_t_shadow(ArithEnv &arith, const evm_word_t *sender, + const evm_word_t *recipient, const evm_word_t *contract_address, + const evm_word_t *gas_limit, const evm_word_t *value, + const uint32_t depth, const uint32_t call_type, + const evm_word_t *storage_address, const CuEVM::byte_array_t &data, + const CuEVM::byte_array_t &byte_code, const bn_t &return_data_offset, + const bn_t &return_data_size, const uint32_t static_env); +}; + +/** + * The message call struct resides in shared memory + * YP: \f$M\f$ + */ +struct evm_message_call_t { + evm_word_t sender; /**< The sender address YP: \f$s\f$ */ + evm_word_t recipient; /**< The recipient address YP: \f$r\f$ also \f$I_{a}\f$ */ + evm_word_t contract_address; /**< The contract address YP: \f$c\f$ */ + evm_word_t gas_limit; /**< The gas limit YP: \f$g\f$ */ + evm_word_t value; /**< The value YP: \f$v\f$ or \f$v^{'}\f$ for DelegateCALL */ + evm_word_t storage_address; /**< The storage address YP: \f$a\f$ */ evm_word_t return_data_offset; /**< The return data offset in memory */ evm_word_t return_data_size; /**< The return data size in memory */ - uint32_t static_env; /**< The static flag (STATICCALL) YP: \f$w\f$ */ + // important store them adjacent in shared memory + uint32_t depth; /**< The depth YP: \f$e\f$ */ + uint32_t call_type; /**< The call type internal has the opcode */ + CuEVM::byte_array_t *data; /**< The data YP: \f$d\f$ */ + CuEVM::byte_array_t *byte_code; /**< The byte code YP: \f$b\f$ or \f$I_{b}\f$*/ + uint32_t static_env; /**< The static flag (STATICCALL) YP: \f$w\f$ */ CuEVM::jump_destinations_t *jump_destinations; /**< The jump destinations */ - /** * The constructor. * @param[in] arith The arithmetical environment. @@ -54,23 +84,23 @@ namespace CuEVM { * @param[in] return_data_size The return data size in memory. * @param[in] static_env The static flag (STATICCALL) YP: \f$w\f$. */ - __host__ __device__ evm_message_call_t( - ArithEnv &arith, - const bn_t &sender, - const bn_t &recipient, - const bn_t &contract_address, - const bn_t &gas_limit, - const bn_t &value, - const uint32_t depth, - const uint32_t call_type, - const bn_t &storage_address, - const CuEVM::byte_array_t &data, - const CuEVM::byte_array_t &byte_code, - const bn_t &return_data_offset, - const bn_t &return_data_size, - const uint32_t static_env = 0 - ); - + // __host__ __device__ evm_message_call_t(ArithEnv &arith, const bn_t &sender, const bn_t &recipient, + // const bn_t &contract_address, const bn_t &gas_limit, const bn_t &value, + // const uint32_t depth, const uint32_t call_type, const bn_t + // &storage_address, const CuEVM::byte_array_t &data, const + // CuEVM::byte_array_t &byte_code, const bn_t &return_data_offset, const bn_t + // &return_data_size, const uint32_t static_env = 0); + // __host__ __device__ evm_message_call_t(ArithEnv &arith, const evm_word_t *sender, const evm_word_t *recipient, + // const evm_word_t *contract_address, const evm_word_t *gas_limit, + // const evm_word_t *value, const uint32_t depth, const uint32_t call_type, + // const evm_word_t *storage_address, const CuEVM::byte_array_t &data, + // const CuEVM::byte_array_t &byte_code, const bn_t &return_data_offset, + // const bn_t &return_data_size, const uint32_t static_env); + // Default constructor + __host__ __device__ evm_message_call_t() {} + + // Copy function + __host__ __device__ void copy_from(const evm_message_call_t_shadow *other); /** * The destructor. */ @@ -80,66 +110,54 @@ namespace CuEVM { * Get the sender address. * @param[in] arith The arithmetical environment. * @param[out] sender The sender address YP: \f$s\f$. - */ - __host__ __device__ void get_sender( - ArithEnv &arith, - bn_t &sender) const; + */ + __host__ __device__ void get_sender(ArithEnv &arith, bn_t &sender) const; /** * Get the recipient address. * @param[in] arith The arithmetical environment. * @param[out] recipient The recipient address YP: \f$r\f$. - */ - __host__ __device__ void get_recipient( - ArithEnv &arith, - bn_t &recipient) const; + */ + __host__ __device__ void get_recipient(ArithEnv &arith, bn_t &recipient) const; /** * Get the contract address. * @param[in] arith The arithmetical environment. * @param[out] contract_address The contract address YP: \f$c\f$. - */ - __host__ __device__ void get_contract_address( - ArithEnv &arith, - bn_t &contract_address) const; + */ + __host__ __device__ void get_contract_address(ArithEnv &arith, bn_t &contract_address) const; /** * Get the gas limit. * @param[in] arith The arithmetical environment. * @param[out] gas_limit The gas limit YP: \f$g\f$. - */ - __host__ __device__ void get_gas_limit( - ArithEnv &arith, - bn_t &gas_limit) const; + */ + __host__ __device__ void get_gas_limit(ArithEnv &arith, bn_t &gas_limit) const; /** * Get the value. * @param[in] arith The arithmetical environment. * @param[out] value The value YP: \f$v\f$ or \f$v^{'}\f$ for DelegateCALL. */ - __host__ __device__ void get_value( - ArithEnv &arith, - bn_t &value) const; + __host__ __device__ void get_value(ArithEnv &arith, bn_t &value) const; /** * Get the depth. * @return The depth YP: \f$e\f$. - */ + */ __host__ __device__ uint32_t get_depth() const; /** * Get the call type. * @return The call type internal has the opcode YP: \f$w\f$. - */ + */ __host__ __device__ uint32_t get_call_type() const; /** * Get the storage address. * @param[in] arith The arithmetical environment. * @param[out] storage_address The storage address YP: \f$a\f$. - */ - __host__ __device__ void get_storage_address( - ArithEnv &arith, - bn_t &storage_address) const; + */ + __host__ __device__ void get_storage_address(ArithEnv &arith, bn_t &storage_address) const; /** * Get the call/init data. @@ -158,17 +176,13 @@ namespace CuEVM { * @param[in] arith The arithmetical environment. * @param[out] return_data_offset The return data offset in memory. */ - __host__ __device__ void get_return_data_offset( - ArithEnv &arith, - bn_t &return_data_offset) const; + __host__ __device__ void get_return_data_offset(ArithEnv &arith, bn_t &return_data_offset) const; /** * Get the return data size. * @param[in] arith The arithmetical environment. * @param[out] return_data_size The return data size in memory. */ - __host__ __device__ void get_return_data_size( - ArithEnv &arith, - bn_t &return_data_size) const; + __host__ __device__ void get_return_data_size(ArithEnv &arith, bn_t &return_data_size) const; /** * Get the static flag. * @return The static flag (STATICCALL) YP: \f$w\f$. @@ -179,52 +193,44 @@ namespace CuEVM { * @param[in] arith The arithmetical environment. * @param[in] gas_limit The gas limit YP: \f$g\f$. */ - __host__ __device__ void set_gas_limit( - ArithEnv &arith, - bn_t &gas_limit); + __host__ __device__ void set_gas_limit(ArithEnv &arith, bn_t &gas_limit); /** * Set the call data. * @param[in] data The data YP: \f$d\f$. */ - __host__ __device__ void set_data( - CuEVM::byte_array_t &data); + __host__ __device__ void set_data(CuEVM::byte_array_t &data); /** * Set the byte code. * @param[in] byte_code The byte code YP: \f$b\f$. */ - __host__ __device__ void set_byte_code( - CuEVM::byte_array_t &byte_code); + __host__ __device__ void set_byte_code(CuEVM::byte_array_t &byte_code); /** * Set the return data offset. * @param[in] arith The arithmetical environment. * @param[in] return_data_offset The return data offset in memory. */ - __host__ __device__ void set_return_data_offset( - ArithEnv &arith, - bn_t &return_data_offset); + __host__ __device__ void set_return_data_offset(ArithEnv &arith, bn_t &return_data_offset); /** * Set the return data size. * @param[in] arith The arithmetical environment. * @param[in] return_data_size The return data size in memory. */ - __host__ __device__ void set_return_data_size( - ArithEnv &arith, - bn_t &return_data_size); + __host__ __device__ void set_return_data_size(ArithEnv &arith, bn_t &return_data_size); /** * Get the jump destinations. * @return The jump destinations. */ - __host__ __device__ CuEVM::jump_destinations_t* get_jump_destinations() const; + // __host__ __device__ CuEVM::jump_destinations_t *get_jump_destinations() const; /** * Print the message. */ __host__ __device__ void print() const; - }; +}; -} +} // namespace CuEVM #endif diff --git a/CuEVM/include/CuEVM/core/stack.cuh b/CuEVM/include/CuEVM/core/stack.cuh index 4a8c37b..8c178ef 100644 --- a/CuEVM/include/CuEVM/core/stack.cuh +++ b/CuEVM/include/CuEVM/core/stack.cuh @@ -13,23 +13,25 @@ namespace CuEVM { namespace stack { -constexpr CONSTANT uint32_t max_size = - CuEVM::max_stack_size; /**< The maximum stack size*/ +constexpr CONSTANT uint32_t max_size = CuEVM::max_stack_size; /**< The maximum stack size*/ // constexpr CONSTANT uint32_t alligment = // sizeof(evm_word_t); /**< The alligment of the stack*/ -constexpr CONSTANT uint32_t initial_capacity = - 16U; /**< The initial capacity of the stack can be change for performence - reasons*/ +// constexpr CONSTANT uint32_t initial_capacity = 16U; /**< The initial capacity of the stack can be change for +// performence +// reasons*/ struct evm_stack_t { - evm_word_t *stack_base; /**< The stack YP: (YP: \f$\mu_{s}\f$)*/ - uint32_t stack_offset; /**< The stack offset (YP: \f$|\mu_{s}|\f$)*/ - uint32_t capacity; /**< The capacity of the stack*/ + evm_word_t *global_stack_base; /**< The stack YP: (YP: \f$\mu_{s}\f$)*/ // global memory store from X+1 element + evm_word_t *shared_stack_base; // shared memory for X elements from the top + uint32_t stack_base_offset; // offset of the stack base in shared memory or global memory + uint16_t stack_offset; // offset of the current stack (its size) from it's base offset in shared memory + // uint16_t capacity; /**< The capacity of the stack on global memory /** * The default constructor + * Stack base offset of the child stack = parent stack offset + 1 */ - __host__ __device__ evm_stack_t(); + __host__ __device__ evm_stack_t(evm_word_t *shared_stack_base = nullptr, uint32_t stack_base_offset = 0); /** * The destructor @@ -40,7 +42,7 @@ struct evm_stack_t { * The copy constructor * @param[in] other The other stack */ - __host__ __device__ evm_stack_t(const evm_stack_t &other); + // __host__ __device__ evm_stack_t(const evm_stack_t &other); /** * Free the memory @@ -52,18 +54,24 @@ struct evm_stack_t { */ __host__ __device__ void clear(); - /** - * The assignment operator - * @param[in] other The other stack - * @return The reference to the stack - */ - __host__ __device__ evm_stack_t &operator=(const evm_stack_t &other); + // /** + // * The assignment operator + // * @param[in] other The other stack + // * @return The reference to the stack + // */ + // __host__ __device__ evm_stack_t &operator=(const evm_stack_t &other); + + // /** + // * Duplicate the stack + // * @param[in] other The other stack + // */ + // __host__ __device__ void duplicate(const evm_stack_t &other); /** - * Duplicate the stack + * Extract the stack data for tracing * @param[in] other The other stack */ - __host__ __device__ void duplicate(const evm_stack_t &other); + __host__ __device__ void extract_data(evm_word_t *other) const; /** * Grow the stack @@ -90,7 +98,7 @@ struct evm_stack_t { * @return 0 if the value is pushed, error code otherwise */ __host__ __device__ int32_t push(ArithEnv &arith, const bn_t &value); - + __host__ __device__ int32_t push_evm_word_t(ArithEnv &arith, const evm_word_t *value); /** * Pop a value from the stack * @param[in] arith The arithmetical environment @@ -98,7 +106,7 @@ struct evm_stack_t { * @return 0 if the value is popped, error code otherwise */ __host__ __device__ int32_t pop(ArithEnv &arith, bn_t &y); - + __host__ __device__ int32_t pop_evm_word(ArithEnv &arith, evm_word_t *&y); /** * Push a value to the stack from a byte array * @param[in] arith The arithmetical environment @@ -107,9 +115,7 @@ struct evm_stack_t { * @param[in] src_byte_size The size of the source byte data * @return 0 if the value is pushed, error code otherwise */ - __host__ __device__ int32_t pushx(ArithEnv &arith, uint8_t x, - uint8_t *src_byte_data, - uint8_t src_byte_size); + __host__ __device__ int32_t pushx(ArithEnv &arith, uint8_t x, uint8_t *src_byte_data, uint8_t src_byte_size); /** * Get the value from the stack at the given index @@ -118,9 +124,9 @@ struct evm_stack_t { * @param[out] y The value at the given index * @return 0 if the value is popped, error code otherwise */ - __host__ __device__ int32_t get_index(ArithEnv &arith, uint32_t index, - bn_t &y); + __host__ __device__ int32_t get_index(ArithEnv &arith, uint32_t index, bn_t &y); + __host__ __device__ evm_word_t *get_address_at_index(uint32_t index) const; /** * Duplicvate the value at the given index and push * it at the top of the stack. @@ -170,8 +176,7 @@ struct evm_stack_t { * @param[in] count The number of instances * @return The stack gpu instances */ - __host__ static evm_stack_t *gpu_from_cpu(evm_stack_t *cpu_instances, - uint32_t count); + __host__ static evm_stack_t *gpu_from_cpu(evm_stack_t *cpu_instances, uint32_t count); /** * Free the stack gpu instances @@ -186,8 +191,7 @@ struct evm_stack_t { * @param[in] count The number of instances * @return The stack cpu instances */ - __host__ static evm_stack_t *cpu_from_gpu(evm_stack_t *gpu_instances, - uint32_t count); + __host__ static evm_stack_t *cpu_from_gpu(evm_stack_t *gpu_instances, uint32_t count); }; /** @@ -196,8 +200,7 @@ struct evm_stack_t { * @param[in] src The source stack * @param[in] count The number of instances */ -__global__ void transfer_kernel_evm_stack_t(evm_stack_t *dst, evm_stack_t *src, - uint32_t count); +__global__ void transfer_kernel_evm_stack_t(evm_stack_t *dst, evm_stack_t *src, uint32_t count); } // namespace stack // Type alias for accessing evm_stack_t directly under the CuEVM namespace diff --git a/CuEVM/include/CuEVM/core/transaction.cuh b/CuEVM/include/CuEVM/core/transaction.cuh index f7b0003..7dcdaa1 100644 --- a/CuEVM/include/CuEVM/core/transaction.cuh +++ b/CuEVM/include/CuEVM/core/transaction.cuh @@ -3,9 +3,7 @@ // Author: Stefan-Dan Ciocirlan // Data: 2024-07-12 // SPDX-License-Identifier: MIT -#ifndef _CUEVM_TRANSACTION_H_ -#define _CUEVM_TRANSACTION_H_ - +#pragma once #include #include @@ -207,7 +205,7 @@ struct evm_transaction_t { * @param[in] touch_state the touch state. * @return 0 for success, error code for failure. */ - __host__ __device__ int32_t access_list_warm_up(ArithEnv &arith, CuEVM::TouchState &touch_state) const; + __host__ __device__ int32_t access_list_warm_up(ArithEnv &arith, CuEVM::TouchState *touch_state_ptr) const; /** * validate the transaction @@ -219,7 +217,7 @@ struct evm_transaction_t { * @param[out] gas_priority_fee the gas priority fee YP: \f$f\f$. * @return 0 for success, error code for failure. */ - __host__ __device__ int32_t validate(ArithEnv &arith, CuEVM::TouchState &touch_state, + __host__ __device__ int32_t validate(ArithEnv &arith, CuEVM::TouchState *touch_state_ptr, CuEVM::block_info_t &block_info, bn_t &gas_used, bn_t &gas_price, bn_t &gas_priority_fee) const; @@ -230,8 +228,8 @@ struct evm_transaction_t { * @param[out] evm_message_call_ptr the message call. * @return 0 for success, error code for failure. */ - __host__ __device__ int32_t get_message_call(ArithEnv &arith, CuEVM::TouchState &touch_state, - CuEVM::evm_message_call_t *&evm_message_call_ptr) const; + __host__ __device__ int32_t get_message_call(ArithEnv &arith, CuEVM::TouchState *touch_state_ptr, + CuEVM::evm_message_call_t_shadow *&evm_message_call_ptr) const; __host__ __device__ void print(); @@ -273,5 +271,3 @@ __host__ int32_t free_instaces(evm_transaction_t *transactions_ptr, uint32_t tra // alias fro transaction using evm_transaction_t = transaction::evm_transaction_t; } // namespace CuEVM - -#endif \ No newline at end of file diff --git a/CuEVM/include/CuEVM/evm.cuh b/CuEVM/include/CuEVM/evm.cuh index 7d7959d..7bb52f6 100644 --- a/CuEVM/include/CuEVM/evm.cuh +++ b/CuEVM/include/CuEVM/evm.cuh @@ -22,20 +22,27 @@ struct evm_instance_t { #ifdef EIP_3155 CuEVM::utils::tracer_t* tracer_ptr; /**< The tracer pointer*/ #endif + + CuEVM::serialized_worldstate_data* serialized_worldstate_data_ptr; /**< The serialized worldstate data */ + CuEVM::utils::simplified_trace_data* simplified_trace_data_ptr; /**< The simplified trace data pointer */ }; struct evm_t { CuEVM::WorldState world_state; /**< The world state */ const CuEVM::block_info_t* block_info_ptr; /**< The block info pointer */ const CuEVM::evm_transaction_t* transaction_ptr; /**< The transaction pointer */ - CuEVM::evm_call_state_t* call_state_ptr; /**< The call state pointer */ - CuEVM::EccConstants* ecc_constants_ptr; /**< The ecc constants pointer*/ - bn_t gas_price; /**< The gas price */ - bn_t gas_priority_fee; /**< The gas priority fee */ - uint32_t status; /**< The status */ + CuEVM::evm_call_state_t* call_state_ptr; /**< The call state pointer store in global mem*/ + // CuEVM::cached_evm_call_state + // cached_call_state; /**< The state pointer store in local mem (constant register usage)*/ + // CuEVM::evm_call_state_t call_state_local; /**< The state pointer store in local mem (constant register usage)*/ + CuEVM::EccConstants* ecc_constants_ptr; /**< The ecc constants pointer*/ + bn_t gas_price; /**< The gas price */ + bn_t gas_priority_fee; /**< The gas priority fee */ + uint32_t status; /**< The status */ #ifdef EIP_3155 CuEVM::utils::tracer_t* tracer_ptr; /**< The tracer pointer */ #endif - + CuEVM::serialized_worldstate_data* serialized_worldstate_data_ptr; /**< The serialized worldstate data */ + CuEVM::utils::simplified_trace_data* simplified_trace_data_ptr; /**< The simplified trace data pointer */ /** * @brief Construct a new evm_t object * Construct a new evm_t object @@ -51,12 +58,16 @@ struct evm_t { __host__ __device__ evm_t(ArithEnv& arith, CuEVM::state_t* world_state_data_ptr, CuEVM::block_info_t* block_info_ptr, CuEVM::evm_transaction_t* transaction_ptr, CuEVM::state_access_t* touch_state_data_ptr, CuEVM::log_state_data_t* log_state_ptr, - CuEVM::evm_return_data_t* return_data_ptr, CuEVM::EccConstants* ecc_constants_ptr + CuEVM::evm_return_data_t* return_data_ptr, CuEVM::EccConstants* ecc_constants_ptr, + CuEVM::evm_message_call_t* shared_message_call_ptr, CuEVM::evm_word_t* shared_stack_ptr #ifdef EIP_3155 , CuEVM::utils::tracer_t* tracer_ptr #endif - ); + + , + CuEVM::serialized_worldstate_data* serialized_worldstate_data_ptr, + CuEVM::utils::simplified_trace_data* simplified_trace_data_ptr); /** * @brief Construct a new evm_t object @@ -64,7 +75,9 @@ struct evm_t { * @param[in] arith The arithmetic environment * @param[in] evm_instance The evm instance */ - __host__ __device__ evm_t(ArithEnv& arith, CuEVM::evm_instance_t& evm_instance); + __host__ __device__ evm_t(ArithEnv& arith, CuEVM::evm_instance_t& evm_instance, + CuEVM::evm_message_call_t* shared_message_call_ptr = nullptr, + CuEVM::evm_word_t* shared_stack_ptr = nullptr); /** * @brief Destroy the evm_t object @@ -79,7 +92,7 @@ struct evm_t { * @param[in] arith The arithmetic environment * @return int32_t The error code, or 0 if successful */ - __host__ __device__ int32_t start_CALL(ArithEnv& arith); + __host__ __device__ int32_t start_CALL(ArithEnv& arith, cached_evm_call_state& cache_call_state); /** * @brief Finish a call operation @@ -99,7 +112,7 @@ struct evm_t { * @param[in] arith The arithmetic environment * @return int32_t The error code, or 0 if successful */ - __host__ __device__ int32_t finish_CREATE(ArithEnv& arith); + __host__ __device__ int32_t finish_CREATE(ArithEnv& arith, cached_evm_call_state& cache_call_state); /** * @brief Finish a transaction operation. @@ -118,6 +131,7 @@ struct evm_t { * Run the EVM for the given transaction * @param[in] arith The arithmetic environment */ + __host__ __device__ void run(ArithEnv& arith, cached_evm_call_state& cache_call_state); __host__ __device__ void run(ArithEnv& arith); }; @@ -145,6 +159,9 @@ __host__ int32_t get_evm_instances(ArithEnv& arith, evm_instance_t*& evm_instanc */ __host__ void free_evm_instances(evm_instance_t*& evm_instances, uint32_t num_instances, int32_t managed = 0); +__global__ void kernel_evm_multiple_instances(cgbn_error_report_t* report, CuEVM::evm_instance_t* instances, + uint32_t count); + } // namespace CuEVM #endif \ No newline at end of file diff --git a/CuEVM/include/CuEVM/evm_call_state.cuh b/CuEVM/include/CuEVM/evm_call_state.cuh index aacae4f..39c15e8 100644 --- a/CuEVM/include/CuEVM/evm_call_state.cuh +++ b/CuEVM/include/CuEVM/evm_call_state.cuh @@ -11,20 +11,21 @@ #include namespace CuEVM { + struct evm_call_state_t { - CuEVM::evm_call_state_t* parent; /**< The parent state */ - uint32_t depth; /**< The depth of the state */ - uint32_t pc; /**< The program counter */ - bn_t gas_used; /**< The gas */ - bn_t gas_refund; /**< The gas refund */ - CuEVM::evm_message_call_t* - message_ptr; /**< The message that started the execution */ - bn_t gas_limit; /**< The gas limit */ - CuEVM::evm_stack_t* stack_ptr; /**< The stack */ - CuEVM::evm_memory_t* memory_ptr; /**< The memory */ - CuEVM::log_state_data_t* log_state_ptr; /**< The logs state */ - CuEVM::TouchState touch_state; /**< The touch state */ - CuEVM::evm_return_data_t* last_return_data_ptr; /**< The return data */ + CuEVM::evm_call_state_t* parent; /**< The parent state */ + uint32_t depth; /**< The depth of the state */ + uint32_t pc; /**< The program counter */ + bn_t gas_used; /**< The gas */ + bn_t gas_refund; /**< The gas refund */ + bn_t gas_limit; /**< The gas limit */ + CuEVM::evm_message_call_t* message_ptr; /**< The message that started the execution in shared memory*/ + CuEVM::evm_message_call_t_shadow* message_ptr_copy; /**< The copy of the message stored in global memory*/ + CuEVM::evm_stack_t* stack_ptr; /**< The stack */ + CuEVM::evm_memory_t* memory_ptr; /**< The memory */ + CuEVM::log_state_data_t* log_state_ptr; /**< The logs state */ + CuEVM::TouchState* touch_state_ptr; /**< The touch state */ + CuEVM::evm_return_data_t* last_return_data_ptr; /**< The return data */ #ifdef EIP_3155 uint32_t trace_idx; /**< The index in the trace */ #endif @@ -32,37 +33,59 @@ struct evm_call_state_t { /** * The complete constructor of the evm_state_t */ - __host__ __device__ evm_call_state_t( - ArithEnv& arith, CuEVM::evm_call_state_t* parent, uint32_t depth, - uint32_t pc, bn_t gas_used, bn_t gas_refund, - CuEVM::evm_message_call_t* message_ptr, CuEVM::evm_stack_t* stack_ptr, - CuEVM::evm_memory_t* memory_ptr, CuEVM::log_state_data_t* log_state_ptr, - CuEVM::TouchState touch_state, - CuEVM::evm_return_data_t* last_return_data_ptr); + __host__ __device__ evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* parent, uint32_t depth, uint32_t pc, + bn_t gas_used, bn_t gas_refund, CuEVM::evm_message_call_t* message_ptr, + CuEVM::evm_stack_t* stack_ptr, CuEVM::evm_memory_t* memory_ptr, + CuEVM::log_state_data_t* log_state_ptr, CuEVM::TouchState* touch_state_ptr, + CuEVM::evm_return_data_t* last_return_data_ptr); + // /** + // * The constructor with the parent state and message call + // */ + // __host__ __device__ evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* parent, + // CuEVM::evm_message_call_t* shared_message_ptr); /** * The constructor with the parent state and message call */ - __host__ __device__ - evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* parent, - CuEVM::evm_message_call_t* message_ptr); + __host__ __device__ evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* parent, + CuEVM::evm_message_call_t* shared_message_ptr, + CuEVM::evm_message_call_t_shadow* shadow_message_ptr = nullptr, + CuEVM::evm_word_t* shared_stack_ptr = nullptr); + + __host__ __device__ evm_call_state_t() {} + __host__ __device__ evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* other); /** * The constructor with no parent state and message call */ - __host__ __device__ evm_call_state_t( - ArithEnv& arith, CuEVM::WorldState* word_state_ptr, - CuEVM::evm_stack_t* stack_ptr, CuEVM::evm_memory_t* memory_ptr, - CuEVM::log_state_data_t* log_state_ptr, - CuEVM::state_access_t* state_access_ptr, - CuEVM::evm_return_data_t* last_return_data_ptr); + __host__ __device__ evm_call_state_t(ArithEnv& arith, CuEVM::WorldState* word_state_ptr, + CuEVM::evm_stack_t* stack_ptr, CuEVM::evm_memory_t* memory_ptr, + CuEVM::log_state_data_t* log_state_ptr, + CuEVM::state_access_t* state_access_ptr, + CuEVM::evm_return_data_t* last_return_data_ptr); /** * The destructor of the evm_call_state_t */ __host__ __device__ ~evm_call_state_t(); - __host__ __device__ int32_t update(ArithEnv& arith, - evm_call_state_t& other); + __host__ __device__ void print(ArithEnv& arith) const; + + __host__ __device__ int32_t update(ArithEnv& arith, evm_call_state_t& other); +}; +// pc, gas_used, gas_limit, stack_ptr, bytecode should be in local or shared memory +struct cached_evm_call_state { + uint32_t pc; /**< The program counter */ + bn_t gas_used; /**< The gas */ + bn_t gas_limit; /**< The gas limit */ + CuEVM::evm_stack_t* stack_ptr; /**< The stack */ + uint32_t byte_code_size; /**< The size of the byte code */ + uint8_t* byte_code_data; /**< The byte code */ + + __host__ __device__ cached_evm_call_state(ArithEnv& arith, evm_call_state_t* state); // copy from state to cache + __host__ __device__ cached_evm_call_state() {}; + __host__ __device__ void set_byte_code(const byte_array_t* byte_code); + __host__ __device__ void write_cache_to_state(ArithEnv& arith, + evm_call_state_t* state); // copy from cache to state }; } // namespace CuEVM diff --git a/CuEVM/include/CuEVM/gas_cost.cuh b/CuEVM/include/CuEVM/gas_cost.cuh index 9abfc77..f3d1018 100644 --- a/CuEVM/include/CuEVM/gas_cost.cuh +++ b/CuEVM/include/CuEVM/gas_cost.cuh @@ -23,12 +23,11 @@ #define GAS_COLD_SLOAD 2100 #define GAS_STORAGE_SET 20000 #define GAS_STORAGE_RESET 2900 -#define GAS_STORAGE_CLEAR_REFUND \ - 4800 // can be defined as GAS_SRESET + GAS_ACCESS_LIST_STORAGE +#define GAS_STORAGE_CLEAR_REFUND 4800 // can be defined as GAS_SRESET + GAS_ACCESS_LIST_STORAGE #define GAS_SSTORE_RESET 5000 - GAS_COLD_SLOAD // change eip-2929 from eip-2020 #define GAS_SSTORE_CLEARS_SCHEDULE \ - 4800 // EIP-3529 SSTORE_RESET - COLD_SLOAD_COST + ACCESS_LIST_STORAGE_KEY = - // 5000 - 2100 + 1900 = 4800 + 4800 // EIP-3529 SSTORE_RESET - COLD_SLOAD_COST + ACCESS_LIST_STORAGE_KEY = + // 5000 - 2100 + 1900 = 4800 #define GAS_WARM_SSOTRE_RESET 1900 // SSTORE_RESET - COLD_SLOAD_COST #define GAS_SELFDESTRUCT 5000 #define GAS_CREATE 32000 @@ -81,8 +80,7 @@ namespace gas_cost { * @param[in] gas_used The gas used * @return 0 for enough gas, 1 for not enough gas or error */ -__host__ __device__ int32_t has_gas(ArithEnv &arith, const bn_t &gas_limit, - const bn_t &gas_used); +__host__ __device__ int32_t has_gas(ArithEnv &arith, const bn_t &gas_limit, const bn_t &gas_used); /** * Compute the max gas call. * @param[in] arith The arithmetic environment @@ -90,9 +88,7 @@ __host__ __device__ int32_t has_gas(ArithEnv &arith, const bn_t &gas_limit, * @param[in] gas_limit The gas limit * @param[in] gas_used The gas used */ -__host__ __device__ void max_gas_call(ArithEnv &arith, bn_t &gas_capped, - const bn_t &gas_limit, - const bn_t &gas_used); +__host__ __device__ void max_gas_call(ArithEnv &arith, bn_t &gas_capped, const bn_t &gas_limit, const bn_t &gas_used); /** * Add the gas cost for the given length of bytes, but considering * evm words. @@ -101,8 +97,7 @@ __host__ __device__ void max_gas_call(ArithEnv &arith, bn_t &gas_capped, * @param[in] length The length of the bytes * @param[in] gas_per_word The gas per evm word */ -__host__ __device__ void evm_words_gas_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &length, +__host__ __device__ void evm_words_gas_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &length, const uint32_t gas_per_word); /** * Add the gas cost for the given length of bytes. @@ -111,8 +106,7 @@ __host__ __device__ void evm_words_gas_cost(ArithEnv &arith, bn_t &gas_used, * @param[in] length The length of the bytes * @param[in] gas_per_byte The gas per byte */ -__host__ __device__ void evm_bytes_gas_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &length, +__host__ __device__ void evm_bytes_gas_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &length, const uint32_t gas_per_byte); /** @@ -122,8 +116,7 @@ __host__ __device__ void evm_bytes_gas_cost(ArithEnv &arith, bn_t &gas_used, * @param[in] exponent The exponent * @return the most significant non-zero bit position */ -__host__ __device__ int32_t exp_bytes_gas_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &exponent); +__host__ __device__ int32_t exp_bytes_gas_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &exponent); /** * Add the cost for initiliasation code. * EIP-3860: https://eips.ethereum.org/EIPS/eip-3860 @@ -131,8 +124,7 @@ __host__ __device__ int32_t exp_bytes_gas_cost(ArithEnv &arith, bn_t &gas_used, * @param[inout] gas_used The gas used * @param[in] initcode_length The length of the initcode */ -__host__ __device__ void initcode_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &initcode_length); +__host__ __device__ void initcode_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &initcode_length); /** * Add the cost for code storage. @@ -140,56 +132,49 @@ __host__ __device__ void initcode_cost(ArithEnv &arith, bn_t &gas_used, * @param[inout] gas_used The gas used * @param[in] code_length The length of the code */ -__host__ __device__ void code_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &code_length); +__host__ __device__ void code_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &code_length); /** * Add the cost for keccak hashing. * @param[in] arith The arithmetic environment * @param[inout] gas_used The gas used * @param[in] length The length of the data in bytes */ -__host__ __device__ void keccak_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &length); +__host__ __device__ void keccak_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &length); /** * Add the cost for memory operation on call data/return data. * @param[in] arith The arithmetic environment * @param[inout] gas_used The gas used * @param[in] length The length of the data in bytes */ -__host__ __device__ void memory_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &length); +__host__ __device__ void memory_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &length); /** * Add the cost for log operation on record data. * @param[in] arith The arithmetic environment * @param[inout] gas_used The gas used * @param[in] length The length of the record in bytes */ -__host__ __device__ void log_record_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &length); +__host__ __device__ void log_record_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &length); /** * Add the cost for log operation on topic. * @param[in] arith The arithmetic environment * @param[inout] gas_used The gas used * @param[in] no_topics The number of topics */ -__host__ __device__ void log_topics_cost(ArithEnv &arith, bn_t &gas_used, - const uint32_t &no_topics); +__host__ __device__ void log_topics_cost(ArithEnv &arith, bn_t &gas_used, const uint32_t &no_topics); /** * Add the cost for sha256 hashing. * @param[in] arith The arithmetic environment * @param[inout] gas_used The gas used * @param[in] length The length of the data in bytes */ -__host__ __device__ void sha256_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &length); +__host__ __device__ void sha256_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &length); /** * Add the dynamic cost for ripemd160 hashing. * @param[in] arith The arithmetic environment * @param[inout] gas_used The gas used * @param[in] length The length of the data in bytes */ -__host__ __device__ void ripemd160_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &length); +__host__ __device__ void ripemd160_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &length); /** * Add the dynamics cost for blake2 hashing. @@ -197,13 +182,10 @@ __host__ __device__ void ripemd160_cost(ArithEnv &arith, bn_t &gas_used, * @param[inout] gas_used The gas used * @param[in] rounds Number of rounds (big-endian unsigned integer) */ -__host__ __device__ void blake2_cost(ArithEnv &arith, bn_t &gas_used, - const uint32_t rounds); +__host__ __device__ void blake2_cost(ArithEnv &arith, bn_t &gas_used, const uint32_t rounds); -__host__ __device__ int32_t modexp_cost(ArithEnv &arith, bn_t &gas_used, - const bn_t &exponent_size, - const bn_t &exponent_bit_length_bn, - const bn_t &multiplication_complexity); +__host__ __device__ int32_t modexp_cost(ArithEnv &arith, bn_t &gas_used, const bn_t &exponent_size, + const bn_t &exponent_bit_length_bn, const bn_t &multiplication_complexity); /** * Add the pairing cost to the gas used. @@ -211,8 +193,7 @@ __host__ __device__ int32_t modexp_cost(ArithEnv &arith, bn_t &gas_used, * @param[inout] gas_used The gas used * @param[in] data_size The size of the data in bytes */ -__host__ __device__ void ecpairing_cost(ArithEnv &arith, bn_t &gas_used, - uint32_t data_size); +__host__ __device__ void ecpairing_cost(ArithEnv &arith, bn_t &gas_used, uint32_t data_size); /** * Add the cost for accessing account information @@ -222,9 +203,8 @@ __host__ __device__ void ecpairing_cost(ArithEnv &arith, bn_t &gas_used, * @param[in] address The address of the account * @return 0 for success, 1 for failure */ -__host__ __device__ int32_t access_account_cost(ArithEnv &arith, bn_t &gas_used, - CuEVM::TouchState &touch_state, - const bn_t &address); +__host__ __device__ int32_t access_account_cost(ArithEnv &arith, bn_t &gas_used, CuEVM::TouchState &touch_state, + const evm_word_t *address); /** * Add the cost for the SLOAD operation. @@ -234,9 +214,8 @@ __host__ __device__ int32_t access_account_cost(ArithEnv &arith, bn_t &gas_used, * @param[in] key The key of the storage * @return 0 for success, 1 for failure */ -__host__ __device__ int32_t sload_cost(ArithEnv &arith, bn_t &gas_used, - const CuEVM::TouchState &touch_state, - const bn_t &address, const bn_t &key); +__host__ __device__ int32_t sload_cost(ArithEnv &arith, bn_t &gas_used, const CuEVM::TouchState &touch_state, + const evm_word_t *address, const bn_t &key); /** * Add the cost and refund for the SSTORE operation. @@ -249,11 +228,9 @@ __host__ __device__ int32_t sload_cost(ArithEnv &arith, bn_t &gas_used, * @param[in] value The value of the storage * @return 0 for success, 1 for failure */ -__host__ __device__ int32_t sstore_cost(ArithEnv &arith, bn_t &gas_used, - bn_t &gas_refund, - const CuEVM::TouchState &touch_state, - const bn_t &address, const bn_t &key, - const bn_t &value); +__host__ __device__ int32_t sstore_cost(ArithEnv &arith, bn_t &gas_used, bn_t &gas_refund, + const CuEVM::TouchState &touch_state, const evm_word_t *address, + const bn_t &key, const bn_t &value); /** * Get the transaction intrinsic gas. @@ -262,9 +239,8 @@ __host__ __device__ int32_t sstore_cost(ArithEnv &arith, bn_t &gas_used, * @param[out] gas_intrinsic The intrinsic gas * @return 0 for success, 1 for failure */ -__host__ __device__ int32_t transaction_intrinsic_gas( - ArithEnv &arith, const CuEVM::evm_transaction_t &transaction, - bn_t &gas_intrinsic); +__host__ __device__ int32_t transaction_intrinsic_gas(ArithEnv &arith, const CuEVM::evm_transaction_t &transaction, + bn_t &gas_intrinsic); /** * Get the memory grow cost. @@ -276,9 +252,8 @@ __host__ __device__ int32_t transaction_intrinsic_gas( * @param[out] gas_used The gas used * @return 0 for success, 1 for failure */ -__host__ __device__ int32_t memory_grow_cost( - ArithEnv &arith, const CuEVM::evm_memory_t &memory, const bn_t &index, - const bn_t &length, bn_t &memory_expansion_cost, bn_t &gas_used); +__host__ __device__ int32_t memory_grow_cost(ArithEnv &arith, const CuEVM::evm_memory_t &memory, const bn_t &index, + const bn_t &length, bn_t &memory_expansion_cost, bn_t &gas_used); } // namespace gas_cost } // namespace CuEVM diff --git a/CuEVM/include/CuEVM/operations/flow.cuh b/CuEVM/include/CuEVM/operations/flow.cuh index 83b9131..5a7e718 100644 --- a/CuEVM/include/CuEVM/operations/flow.cuh +++ b/CuEVM/include/CuEVM/operations/flow.cuh @@ -7,12 +7,11 @@ #ifndef _CUEVM_FLOW_OP_H_ #define _CUEVM_FLOW_OP_H_ - -#include -#include -#include #include - +#include +#include +#include +#include /** * 50s: Flow Operations: @@ -23,91 +22,75 @@ * - JUMPDEST */ namespace CuEVM::operations { - /** - * The JUMP operation implementation. - * Takes the destination from the stack and sets the program counter - * to the destination if it is a valid jump destination. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit. - * @param[inout] gas_used The gas used. - * @param[inout] pc The program counter. - * @param[in] stack The stack. - * @param[in] message The message. - * @return 0 if the operation was successful, an error code otherwise. - */ - __host__ __device__ int32_t JUMP( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - uint32_t &pc, - CuEVM::evm_stack_t &stack, - const CuEVM::evm_message_call_t &message); - /** - * The JUMPI operation implementation. - * Takes the destination and the condition from the stack and sets the program counter - * to the destination if it is a valid jump destination and the condition is not 0. - * If the condition is 0 the program counter is incremented by 1. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit. - * @param[inout] gas_used The gas used. - * @param[inout] pc The program counter. - * @param[in] stack The stack. - * @param[in] message The message. - * @return 0 if the operation was successful, an error code otherwise. - */ - __host__ __device__ int32_t JUMPI( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - uint32_t &pc, - CuEVM::evm_stack_t &stack, - const CuEVM::evm_message_call_t &message); +/** + * The JUMP operation implementation. + * Takes the destination from the stack and sets the program counter + * to the destination if it is a valid jump destination. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit. + * @param[inout] gas_used The gas used. + * @param[inout] pc The program counter. + * @param[in] stack The stack. + * @param[in] message The message. + * @return 0 if the operation was successful, an error code otherwise. + */ +__host__ __device__ int32_t JUMP(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, uint32_t &pc, + CuEVM::evm_stack_t &stack, const CuEVM::evm_message_call_t &message); +/** + * The JUMPI operation implementation. + * Takes the destination and the condition from the stack and sets the program counter + * to the destination if it is a valid jump destination and the condition is not 0. + * If the condition is 0 the program counter is incremented by 1. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit. + * @param[inout] gas_used The gas used. + * @param[inout] pc The program counter. + * @param[in] stack The stack. + * @param[in] message The message. + * @return 0 if the operation was successful, an error code otherwise. + */ +__host__ __device__ int32_t JUMPI(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, uint32_t &pc, + CuEVM::evm_stack_t &stack, const CuEVM::evm_message_call_t &message +#ifdef BUILD_LIBRARY + , + CuEVM::utils::simplified_trace_data *simplified_trace_data_ptr +#endif +); - /** - * The PC operation implementation. - * Pushes the program counter to the stack. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit. - * @param[inout] gas_used The gas used. - * @param[in] pc The program counter. - * @param[out] stack The stack. - * @return 0 if the operation was successful, an error code otherwise. - */ - __host__ __device__ int32_t PC( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - const uint32_t &pc, - CuEVM::evm_stack_t &stack); +/** + * The PC operation implementation. + * Pushes the program counter to the stack. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit. + * @param[inout] gas_used The gas used. + * @param[in] pc The program counter. + * @param[out] stack The stack. + * @return 0 if the operation was successful, an error code otherwise. + */ +__host__ __device__ int32_t PC(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, const uint32_t &pc, + CuEVM::evm_stack_t &stack); - /** - * The GAS operation implementation. - * Pushes the gas left to the stack after this operation. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit. - * @param[inout] gas_used The gas used. - * @param[out] stack The stack. - * @return 0 if the operation was successful, an error code otherwise. - */ - __host__ __device__ int32_t GAS( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack); +/** + * The GAS operation implementation. + * Pushes the gas left to the stack after this operation. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit. + * @param[inout] gas_used The gas used. + * @param[out] stack The stack. + * @return 0 if the operation was successful, an error code otherwise. + */ +__host__ __device__ int32_t GAS(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_stack_t &stack); - /** - * The JUMPDEST operation implementation. - * It increments the program counter by 1. - * It is used as a valid jump destination. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit. - * @param[inout] gas_used The gas used. - * @return 0 if the operation was successful, an error code otherwise. - */ - __host__ __device__ int32_t JUMPDEST( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used); -} +/** + * The JUMPDEST operation implementation. + * It increments the program counter by 1. + * It is used as a valid jump destination. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit. + * @param[inout] gas_used The gas used. + * @return 0 if the operation was successful, an error code otherwise. + */ +__host__ __device__ int32_t JUMPDEST(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used); +} // namespace CuEVM::operations #endif \ No newline at end of file diff --git a/CuEVM/include/CuEVM/operations/system.cuh b/CuEVM/include/CuEVM/operations/system.cuh index a1d1afd..87e105b 100644 --- a/CuEVM/include/CuEVM/operations/system.cuh +++ b/CuEVM/include/CuEVM/operations/system.cuh @@ -1,13 +1,12 @@ #ifndef _CUEVM_SYSTEMS_OP_H_ #define _CUEVM_SYSTEMS_OP_H_ - -#include -#include #include #include -#include +#include #include +#include +#include /** * The system operations class. @@ -26,147 +25,122 @@ * - INVALID * - SELFDESTRUCT */ -namespace CuEVM::operations -{ - /** - * The STOP operation. - * @param[out] return_data The return data. - * @return return error code. - */ - __host__ __device__ int32_t STOP( - CuEVM::evm_return_data_t &return_data); +namespace CuEVM::operations { +/** + * The STOP operation. + * @param[out] return_data The return data. + * @return return error code. + */ +__host__ __device__ int32_t STOP(CuEVM::evm_return_data_t &return_data); - /** - * The CREATE operation. gives the new evm call state - * @param[in] arith The arithmetical environment. - * @param[in] current_state The current state. - * @param[out] new_state_ptr The new state pointer. - * @return 0 if the operation is successful, otherwise the error code. - */ - __host__ __device__ int32_t CREATE( - ArithEnv &arith, - CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t* &new_state_ptr); +/** + * The CREATE operation. gives the new evm call state + * @param[in] arith The arithmetical environment. + * @param[in] current_state The current state. + * @param[out] new_state_ptr The new state pointer. + * @return 0 if the operation is successful, otherwise the error code. + */ +__host__ __device__ int32_t CREATE(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, + CuEVM::evm_call_state_t *&new_state_ptr, CuEVM::cached_evm_call_state &cached_state); - /** - * The CALL operation. gives the new evm call state - * @param[in] arith The arithmetical environment. - * @param[in] current_state The current state. - * @param[out] new_state_ptr The new state pointer. - * @return 0 if the operation is successful, otherwise the error code. - */ - __host__ __device__ int32_t CALL( - ArithEnv &arith, - CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t* &new_state_ptr); +/** + * The CALL operation. gives the new evm call state + * @param[in] arith The arithmetical environment. + * @param[in] current_state The current state. + * @param[out] new_state_ptr The new state pointer. + * @return 0 if the operation is successful, otherwise the error code. + */ +__host__ __device__ int32_t CALL(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, + CuEVM::evm_call_state_t *&new_state_ptr, CuEVM::cached_evm_call_state &cached_state); - /** - * The CALLCODE operation. gives the new evm call state - * @param[in] arith The arithmetical environment. - * @param[in] current_state The current state. - * @param[out] new_state_ptr The new state pointer. - * @return 0 if the operation is successful, otherwise the error code. - */ - __host__ __device__ int32_t CALLCODE( - ArithEnv &arith, - CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t* &new_state_ptr); +/** + * The CALLCODE operation. gives the new evm call state + * @param[in] arith The arithmetical environment. + * @param[in] current_state The current state. + * @param[out] new_state_ptr The new state pointer. + * @return 0 if the operation is successful, otherwise the error code. + */ +__host__ __device__ int32_t CALLCODE(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, + CuEVM::evm_call_state_t *&new_state_ptr, + CuEVM::cached_evm_call_state &cached_state); - /** - * The RETURN operation. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit. - * @param[inout] gas_used The gas used. - * @param[in] stack The stack. - * @param[in] memory The memory. - * @param[out] return_data The return data. - * @return 0 if the operation is successful, otherwise the error code. - */ - __host__ __device__ int32_t RETURN( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack, - CuEVM::evm_memory_t &memory, - CuEVM::evm_return_data_t &return_data); - /** - * The DELEGATECALL operation. gives the new evm call state - * @param[in] arith The arithmetical environment. - * @param[in] current_state The current state. - * @param[out] new_state_ptr The new state pointer. - * @return 0 if the operation is successful, otherwise the error code. - */ - __host__ __device__ int32_t DELEGATECALL( - ArithEnv &arith, - CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t* &new_state_ptr); +/** + * The RETURN operation. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit. + * @param[inout] gas_used The gas used. + * @param[in] stack The stack. + * @param[in] memory The memory. + * @param[out] return_data The return data. + * @return 0 if the operation is successful, otherwise the error code. + */ +__host__ __device__ int32_t RETURN(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_stack_t &stack, + CuEVM::evm_memory_t &memory, CuEVM::evm_return_data_t &return_data); +/** + * The DELEGATECALL operation. gives the new evm call state + * @param[in] arith The arithmetical environment. + * @param[in] current_state The current state. + * @param[out] new_state_ptr The new state pointer. + * @return 0 if the operation is successful, otherwise the error code. + */ +__host__ __device__ int32_t DELEGATECALL(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, + CuEVM::evm_call_state_t *&new_state_ptr, + CuEVM::cached_evm_call_state &cached_state); - /** - * The CREATE2 operation. gives the new evm call state - * @param[in] arith The arithmetical environment. - * @param[in] current_state The current state. - * @param[out] new_state_ptr The new state pointer. - * @return 0 if the operation is successful, otherwise the error code. - */ - __host__ __device__ int32_t CREATE2( - ArithEnv &arith, - CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t* &new_state_ptr); +/** + * The CREATE2 operation. gives the new evm call state + * @param[in] arith The arithmetical environment. + * @param[in] current_state The current state. + * @param[out] new_state_ptr The new state pointer. + * @return 0 if the operation is successful, otherwise the error code. + */ +__host__ __device__ int32_t CREATE2(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, + CuEVM::evm_call_state_t *&new_state_ptr, + CuEVM::cached_evm_call_state &cached_state); - /** - * The STATICCALL operation. gives the new evm call state - * @param[in] arith The arithmetical environment. - * @param[in] current_state The current state. - * @param[out] new_state_ptr The new state pointer. - * @return 0 if the operation is successful, otherwise the error code. - */ - __host__ __device__ int32_t STATICCALL( - ArithEnv &arith, - CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t* &new_state_ptr); +/** + * The STATICCALL operation. gives the new evm call state + * @param[in] arith The arithmetical environment. + * @param[in] current_state The current state. + * @param[out] new_state_ptr The new state pointer. + * @return 0 if the operation is successful, otherwise the error code. + */ +__host__ __device__ int32_t STATICCALL(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, + CuEVM::evm_call_state_t *&new_state_ptr, + CuEVM::cached_evm_call_state &cached_state); - /** - * The REVERT operation. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit. - * @param[inout] gas_used The gas used. - * @param[in] stack The stack. - * @param[in] memory The memory. - * @param[out] return_data The return data. - */ - __host__ __device__ int32_t REVERT( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack, - CuEVM::evm_memory_t &memory, - CuEVM::evm_return_data_t &return_data); +/** + * The REVERT operation. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit. + * @param[inout] gas_used The gas used. + * @param[in] stack The stack. + * @param[in] memory The memory. + * @param[out] return_data The return data. + */ +__host__ __device__ int32_t REVERT(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_stack_t &stack, + CuEVM::evm_memory_t &memory, CuEVM::evm_return_data_t &return_data); - /** - * The INVALID operation. - * @return The error code. - */ - __host__ __device__ int32_t INVALID(); +/** + * The INVALID operation. + * @return The error code. + */ +__host__ __device__ int32_t INVALID(); - /** - * The SELFDESTRUCT operation. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit. - * @param[inout] gas_used The gas used. - * @param[inout] stack The stack. - * @param[in] message The current context message call. - * @param[inout] touch_state The touch state. - * @param[out] return_data The return data. - * @return 0 if the operation is successful, otherwise the error code. - */ - __host__ __device__ int32_t SELFDESTRUCT( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack, - CuEVM::evm_message_call_t &message, - CuEVM::TouchState &touch_state, - CuEVM::evm_return_data_t &return_data); -} // namespace CuEVM::operation +/** + * The SELFDESTRUCT operation. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit. + * @param[inout] gas_used The gas used. + * @param[inout] stack The stack. + * @param[in] message The current context message call. + * @param[inout] touch_state The touch state. + * @param[out] return_data The return data. + * @return 0 if the operation is successful, otherwise the error code. + */ +__host__ __device__ int32_t SELFDESTRUCT(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, + CuEVM::evm_stack_t &stack, CuEVM::evm_message_call_t &message, + CuEVM::TouchState &touch_state, CuEVM::evm_return_data_t &return_data); +} // namespace CuEVM::operations #endif \ No newline at end of file diff --git a/CuEVM/include/CuEVM/state/account.cuh b/CuEVM/include/CuEVM/state/account.cuh index 22fc6d4..c568f47 100644 --- a/CuEVM/include/CuEVM/state/account.cuh +++ b/CuEVM/include/CuEVM/state/account.cuh @@ -52,6 +52,7 @@ struct account_t { * @param[in] address The address of the account */ __host__ __device__ account_t(ArithEnv &arith, const bn_t &address); + __host__ __device__ account_t(ArithEnv &arith, evm_word_t *address); /** * The destructor for the account data structure. @@ -129,7 +130,7 @@ struct account_t { * @param[in] arith The arithmetical environment * @param[in] address The address of the account */ - __host__ __device__ void set_address(ArithEnv &arith, const bn_t &address); + __host__ __device__ void set_address(ArithEnv &arith, const evm_word_t *address); /** * Set the balance of the account. @@ -157,7 +158,7 @@ struct account_t { * @param[in] address The address * @return If found 1, otherwise 0 */ - __host__ __device__ int32_t has_address(ArithEnv &arith, const bn_t &address); + __host__ __device__ int32_t has_address(ArithEnv &arith, const evm_word_t *address); /** * Verify if the account has the the given address. @@ -165,7 +166,7 @@ struct account_t { * @param[in] address The address as evm word * @return If found 1, otherwise 0 */ - __host__ __device__ int32_t has_address(ArithEnv &arith, const evm_word_t &address); + // __host__ __device__ int32_t has_address(ArithEnv &arith, const evm_word_t &address); /** * Update the current account with the information diff --git a/CuEVM/include/CuEVM/state/logs.cuh b/CuEVM/include/CuEVM/state/logs.cuh index c62305e..eea21d8 100644 --- a/CuEVM/include/CuEVM/state/logs.cuh +++ b/CuEVM/include/CuEVM/state/logs.cuh @@ -43,9 +43,9 @@ struct log_state_data_t { */ __host__ __device__ ~log_state_data_t() { if (logs != nullptr && capacity > 0) { - __ONE_GPU_THREAD_BEGIN__ + __ONE_GPU_THREAD_WOSYNC_BEGIN__ delete[] logs; - __ONE_GPU_THREAD_END__ + __ONE_GPU_THREAD_WOSYNC_END__ } logs = nullptr; capacity = 0; diff --git a/CuEVM/include/CuEVM/state/state.cuh b/CuEVM/include/CuEVM/state/state.cuh index b38639f..bd0fe8b 100644 --- a/CuEVM/include/CuEVM/state/state.cuh +++ b/CuEVM/include/CuEVM/state/state.cuh @@ -9,8 +9,8 @@ #include #include +#include #include - namespace CuEVM { /** * The state struct. @@ -72,7 +72,7 @@ struct state_t { * @param[out] index The index. * @return If found 0. otherwise error. */ - __host__ __device__ int32_t get_account_index(ArithEnv &arith, const bn_t &address, uint32_t &index); + __host__ __device__ int32_t get_account_index(ArithEnv &arith, const evm_word_t *address, uint32_t &index); /** * The get account function. @@ -81,7 +81,7 @@ struct state_t { * @param[out] account The account. * @return If found 0. otherwise error. */ - __host__ __device__ int32_t get_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t &account); + __host__ __device__ int32_t get_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t &account); /** * The get account function. @@ -90,7 +90,7 @@ struct state_t { * @param[out] account_ptr The account pointer. * @return If found 0. otherwise error. */ - __host__ __device__ int32_t get_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t *&account_ptr); + __host__ __device__ int32_t get_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr); /** * The add account function. @@ -107,22 +107,17 @@ struct state_t { */ __host__ __device__ int32_t set_account(ArithEnv &arith, const CuEVM::account_t &account); - /** - * The has account function. - * @param[in] arith The arithmetic environment. - * @param[in] address The address. - * @return If has ERROR_SUCCESS. otherwise ERROR_STATE_ADDRESS_NOT_FOUND. - */ - __host__ __device__ int32_t has_account(ArithEnv &arith, const bn_t &address); - /** * The update account function. * @param[in] arith The arithmetic environment. * @param[in] account The account. * @return If updated 0. otherwise error. */ - __host__ __device__ int32_t update_account(ArithEnv &arith, const CuEVM::account_t &account); + __host__ __device__ int32_t update_account(ArithEnv &arith, const CuEVM::account_t &account, + const CuEVM::account_flags_t flag = CuEVM::ACCOUNT_ALL_FLAG); + __host__ __device__ int32_t update(ArithEnv &arith, const CuEVM::account_t *accounts, + const CuEVM::account_flags_t *flags, uint32_t account_count); // /** // * If an account is empty. // * @param[in] arith The arithmetic environment. diff --git a/CuEVM/include/CuEVM/state/state_access.cuh b/CuEVM/include/CuEVM/state/state_access.cuh index 863ffd5..f3af469 100644 --- a/CuEVM/include/CuEVM/state/state_access.cuh +++ b/CuEVM/include/CuEVM/state/state_access.cuh @@ -70,7 +70,7 @@ struct state_access_t : state_t { * @param[in] flag The flag access. * @return If found 0. otherwise error. */ - __host__ __device__ int32_t get_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t &account, + __host__ __device__ int32_t get_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t &account, const CuEVM::account_flags_t flag = CuEVM::ACCOUNT_NONE_FLAG); /** @@ -81,7 +81,7 @@ struct state_access_t : state_t { * @param[in] flag The flag access. * @return If found 0. otherwise error. */ - __host__ __device__ int32_t get_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t *&account_ptr, + __host__ __device__ int32_t get_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, const CuEVM::account_flags_t flag = CuEVM::ACCOUNT_NONE_FLAG); /** @@ -120,7 +120,8 @@ struct state_access_t : state_t { * @param[in] flag The flag access. * @return If added 0. otherwise error. */ - __host__ __device__ int32_t add_new_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t *&account_ptr, + __host__ __device__ int32_t add_new_account(ArithEnv &arith, const evm_word_t *address, + CuEVM::account_t *&account_ptr, const CuEVM::account_flags_t flag = CuEVM::ACCOUNT_NONE_FLAG); /** diff --git a/CuEVM/include/CuEVM/state/touch_state.cuh b/CuEVM/include/CuEVM/state/touch_state.cuh index 9adb58c..3cf7f9c 100644 --- a/CuEVM/include/CuEVM/state/touch_state.cuh +++ b/CuEVM/include/CuEVM/state/touch_state.cuh @@ -29,7 +29,7 @@ class TouchState { * @param[in] acces_state_flag The account access flags. * @return 1 if the account is added successfully, 0 otherwise. */ - __host__ __device__ int32_t add_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t *&account_ptr, + __host__ __device__ int32_t add_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, const CuEVM::account_flags_t acces_state_flag); public: @@ -84,6 +84,8 @@ class TouchState { return *this; } + __host__ __device__ state_access_t *get_state() const { return _state; } + /** * The getter for the account given by an address. * @param[in] arith The arithmetic environment. @@ -94,17 +96,17 @@ class TouchState { * Set to true when getting the account to update it. * @return 0 if the account is found, error otherwise. */ - __host__ __device__ int32_t get_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t *&account_ptr, + __host__ __device__ int32_t get_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, const CuEVM::account_flags_t acces_state_flag, bool add_to_state = false); - __host__ __device__ int32_t get_account_index(ArithEnv &arith, const bn_t &address, uint32_t &index) const; + __host__ __device__ int32_t get_account_index(ArithEnv &arith, const evm_word_t *address, uint32_t &index) const; /** * If the account given by address is empty * @param[in] arith The arithmetic environment. * @param[in] address The address of the account. * @return true if the account is empty, false otherwise. */ - __host__ __device__ bool is_empty_account(ArithEnv &arith, const bn_t &address); + __host__ __device__ bool is_empty_account(ArithEnv &arith, const evm_word_t *address); /** * @brief Determine if an account is empty and can be created @@ -113,7 +115,7 @@ class TouchState { * @param address * @return __host__ */ - __host__ __device__ bool is_empty_account_create(ArithEnv &arith, const bn_t &address); + __host__ __device__ bool is_empty_account_create(ArithEnv &arith, const evm_word_t *address); /** * If the account given by address is deleted @@ -121,7 +123,7 @@ class TouchState { * @param[in] address The address of the account. * @return 1 if the account is deleted, 0 otherwise. */ - __host__ __device__ int32_t is_deleted_account(ArithEnv &arith, const bn_t &address); + __host__ __device__ int32_t is_deleted_account(ArithEnv &arith, const evm_word_t *address); /** * The getter for the balance given by an address. @@ -130,7 +132,7 @@ class TouchState { * @param[out] balance The balance of the account. * @return error_code, 0 if success */ - __host__ __device__ int32_t get_balance(ArithEnv &arith, const bn_t &address, bn_t &balance); + __host__ __device__ int32_t get_balance(ArithEnv &arith, const evm_word_t *address, bn_t &balance); /** * The getter for the nonce given by an address. @@ -139,7 +141,7 @@ class TouchState { * @param[out] nonce The nonce of the account. * @return error_code, 0 if success */ - __host__ __device__ int32_t get_nonce(ArithEnv &arith, const bn_t &address, bn_t &nonce); + __host__ __device__ int32_t get_nonce(ArithEnv &arith, const evm_word_t *address, bn_t &nonce); /** * The getter for the code given by an address. @@ -148,7 +150,7 @@ class TouchState { * @param[out] byte_code The byte code of the account. * @return error_code, 0 if success */ - __host__ __device__ int32_t get_code(ArithEnv &arith, const bn_t &address, byte_array_t &byte_code); + __host__ __device__ int32_t get_code(ArithEnv &arith, const evm_word_t *address, byte_array_t &byte_code); /** * The getter for the value given by an address and a key. @@ -158,7 +160,7 @@ class TouchState { * @param[out] value The value of the storage. * @return 0 if the value is found, error otherwise. */ - __host__ __device__ int32_t get_value(ArithEnv &arith, const bn_t &address, const bn_t &key, bn_t &value); + __host__ __device__ int32_t get_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, bn_t &value); /** * The getter for the value of a storage element without modifing the state. @@ -168,9 +170,10 @@ class TouchState { * @param[out] value The value of the storage. * @return 0 if the value is found, error otherwise. */ - __host__ __device__ int32_t poke_value(ArithEnv &arith, const bn_t &address, const bn_t &key, bn_t &value) const; + __host__ __device__ int32_t poke_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, + bn_t &value) const; - __host__ __device__ int32_t poke_original_value(ArithEnv &arith, const bn_t &address, const bn_t &key, + __host__ __device__ int32_t poke_original_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, bn_t &value) const; /** @@ -180,7 +183,7 @@ class TouchState { * @param[in] balance The balance of the account. * @return 0 if the balance is set, error otherwise. */ - __host__ __device__ int32_t set_balance(ArithEnv &arith, const bn_t &address, const bn_t &balance); + __host__ __device__ int32_t set_balance(ArithEnv &arith, const evm_word_t *address, const bn_t &balance); /** * The getter for the balance given by an address without modifing the @@ -190,7 +193,7 @@ class TouchState { * @param[in] balance The balance of the account. * @return 0 if the balance is set, error otherwise. */ - __host__ __device__ int32_t poke_balance(ArithEnv &arith, const bn_t &address, bn_t &balance) const; + __host__ __device__ int32_t poke_balance(ArithEnv &arith, const evm_word_t *address, bn_t &balance) const; /** * Get the account object without settng it warm * @@ -200,7 +203,7 @@ class TouchState { * @param include_world_state If the world state should be included * @return 0 if the account is found, error otherwise. */ - __host__ __device__ int32_t poke_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t *&account_ptr, + __host__ __device__ int32_t poke_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, bool include_world_state = false) const; /** @@ -210,7 +213,7 @@ class TouchState { * @param address The address of the account. * @return true if the account is in the warm set, false otherwise. */ - __host__ __device__ bool is_warm_account(ArithEnv &arith, const bn_t &address) const; + __host__ __device__ bool is_warm_account(ArithEnv &arith, const evm_word_t *address) const; /** * Check if a key is in the warm set @@ -220,14 +223,14 @@ class TouchState { * @param key The key of the storage. * @return true if the key is in the warm set, false otherwise. */ - __host__ __device__ bool is_warm_key(ArithEnv &arith, const bn_t &address, const bn_t &key) const; + __host__ __device__ bool is_warm_key(ArithEnv &arith, const evm_word_t *address, const bn_t &key) const; /** * Set an account to be warm * @param arith The arithmetic environment. * @param address The address of the account. */ - __host__ __device__ bool set_warm_account(ArithEnv &arith, const bn_t &address); + __host__ __device__ bool set_warm_account(ArithEnv &arith, const evm_word_t *address); /** * Set a key to be warm @@ -236,7 +239,8 @@ class TouchState { * @param key The key of the storage. * @param value The value of the storage. */ - __host__ __device__ bool set_warm_key(ArithEnv &arith, const bn_t &address, const bn_t &key, const bn_t &value); + __host__ __device__ bool set_warm_key(ArithEnv &arith, const evm_word_t *address, const bn_t &key, + const bn_t &value); /** * The setter for the nonce given by an address. * @param[in] arith The arithmetic environment. @@ -244,7 +248,7 @@ class TouchState { * @param[in] nonce The nonce of the account. * @return 0 if the nonce is set, error otherwise. */ - __host__ __device__ int32_t set_nonce(ArithEnv &arith, const bn_t &address, const bn_t &nonce); + __host__ __device__ int32_t set_nonce(ArithEnv &arith, const evm_word_t *address, const bn_t &nonce); /** * The setter for the code given by an address. @@ -253,7 +257,7 @@ class TouchState { * @param[in] byte_code The byte code of the account. * @return 0 if the code is set, error otherwise. */ - __host__ __device__ int32_t set_code(ArithEnv &arith, const bn_t &address, const byte_array_t &byte_code); + __host__ __device__ int32_t set_code(ArithEnv &arith, const evm_word_t *address, const byte_array_t &byte_code); /** * The setter for the storage value given by an address, a key, and a @@ -264,7 +268,7 @@ class TouchState { * @param[in] value The value of the storage. * @return 0 if the storage value is set, error otherwise. */ - __host__ __device__ int32_t set_storage_value(ArithEnv &arith, const bn_t &address, const bn_t &key, + __host__ __device__ int32_t set_storage_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, const bn_t &value); /** @@ -273,7 +277,7 @@ class TouchState { * @param[in] address The address of the account. * @return 0 if the account is deleted, error otherwise. */ - __host__ __device__ int32_t delete_account(ArithEnv &arith, const bn_t &address); + __host__ __device__ int32_t delete_account(ArithEnv &arith, const evm_word_t *address); /** * Mark an account for deletion at the end of the transaction @@ -281,7 +285,7 @@ class TouchState { * @param[in] address The address of the account. * @return 0 if success, error otherwise. */ - __host__ __device__ int32_t mark_for_deletion(ArithEnv &arith, const bn_t &address); + __host__ __device__ int32_t mark_for_deletion(ArithEnv &arith, const evm_word_t *address); /** * Update the touch state. @@ -291,6 +295,9 @@ class TouchState { */ __host__ __device__ int32_t update(ArithEnv &arith, TouchState *other); + // update the final state with the world state and combine storage + __host__ __device__ int32_t update_world_state(ArithEnv &arith); + /** * Transfer the given value from one account to another. * @param[in] arith The arithmetic environment. @@ -299,7 +306,8 @@ class TouchState { * @param[in] value The value to transfer. * @return 0 if the transfer is successful, error otherwise. */ - __host__ __device__ int32_t transfer(ArithEnv &arith, const bn_t &from, const bn_t &to, const bn_t &value); + __host__ __device__ int32_t transfer(ArithEnv &arith, const evm_word_t *from, const evm_word_t *to, + const bn_t &value); __host__ __device__ CuEVM::contract_storage_t get_entire_storage(ArithEnv &arith, const uint32_t account_index) const; diff --git a/CuEVM/include/CuEVM/state/world_state.cuh b/CuEVM/include/CuEVM/state/world_state.cuh index c60bcb8..75f6ed1 100644 --- a/CuEVM/include/CuEVM/state/world_state.cuh +++ b/CuEVM/include/CuEVM/state/world_state.cuh @@ -6,10 +6,31 @@ #pragma once #include +#include #include +#include #include - namespace CuEVM { +// for convenient data transfer between host and device. set a fixed maximum size for the number of addresses to be +// transferred +// todo : optimize this later +constexpr uint32_t worldstate_addresses_size = 32; +constexpr uint32_t worldstate_storage_values_size = 1024; +// heuristic size for the bytecode hex string to keep everything within 1MB +constexpr uint32_t byte_code_hex_size = 32 * max_code_size; +struct serialized_worldstate_data { + uint32_t no_accounts; + uint32_t no_storage_elements; + char addresses[worldstate_addresses_size][43]; // 0x + ... + \0 + char balance[worldstate_addresses_size][67]; // 0x + ... + \0 + uint32_t nonce[worldstate_addresses_size]; + uint16_t storage_indexes[worldstate_storage_values_size]; + char storage_keys[worldstate_storage_values_size][67]; // 0x + ... + \0 + char storage_values[worldstate_storage_values_size][67]; // 0x + ... + \0 + // currently dont support copy back the bytecode hex string + // TODO: use 1 large preallocated buffer for bytecode + void print(); +}; /** * The world state classs */ @@ -38,9 +59,8 @@ class WorldState { * @param[out] account_ptr The pointer to the account * @return if found 0, otherwise error. */ - __host__ __device__ int32_t get_account(ArithEnv &arith, - const bn_t &address, - CuEVM::account_t *&account_ptr); + __host__ __device__ int32_t get_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr); + __host__ __device__ int32_t update(ArithEnv &arith, const CuEVM::state_access_t *state_access_ptr); /** * Get the value of a storage element @@ -55,7 +75,8 @@ class WorldState { * if the account or the key within the account's storage could not be found * and the value is set to 0. */ - __host__ __device__ int32_t get_value(ArithEnv &arith, const bn_t &address, - const bn_t &key, bn_t &value); + __host__ __device__ int32_t get_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, bn_t &value); + __host__ __device__ void serialize_data(ArithEnv &arith, serialized_worldstate_data *data); }; + } // namespace CuEVM diff --git a/CuEVM/include/CuEVM/tracer.cuh b/CuEVM/include/CuEVM/tracer.cuh index d05f135..6bac0cb 100644 --- a/CuEVM/include/CuEVM/tracer.cuh +++ b/CuEVM/include/CuEVM/tracer.cuh @@ -12,10 +12,73 @@ #include #include #include +#include #include #include - namespace CuEVM::utils { +// PyObject* branches = PyList_New(0); +// PyObject* bugs = PyList_New(0); +// PyObject* calls = PyList_New(0); +// PyObject* storage_write = PyList_New(0); + +// PyObject* tracer_json = PyList_New(0); +// PyObject* item = NULL; +// PyObject* stack_json = NULL; +// add sub mul div mod exp +// sstore +#define MAX_TRACE_EVENTS 1024 +#define MAX_ADDRESSES_TRACING 32 +#define MAX_CALLS_TRACING 32 +#define MAX_BRANCHES_TRACING 32 // only track the latest 32 branches +struct simple_event_trace { + // pc // op // operand 1, operand 2, res + uint32_t pc; + uint8_t op; + // uint8_t address_idx; + // evm_word_t address; // temporarily disabled + evm_word_t operand_1; + evm_word_t operand_2; + evm_word_t res; // blank in some cases +}; +struct call_trace { + uint32_t pc; + uint8_t op; + // uint8_t address_idx; + evm_word_t sender; + evm_word_t receiver; + evm_word_t value; + uint8_t success = UINT8_MAX; // 0 or 1 + // todo add more depth + result etc +}; +struct branch_trace { + uint32_t pc_src; + uint32_t pc_dst; + uint32_t pc_missed; + evm_word_t distance; // distance between pc_src and pc_dst + + // todo: use evm_word_t for distance +}; + +struct simplified_trace_data { + simple_event_trace events[MAX_TRACE_EVENTS]; + // evm_word_t addresses[MAX_ADDRESSES_TRACING]; + call_trace calls[MAX_CALLS_TRACING]; + branch_trace branches[MAX_BRANCHES_TRACING]; // pc_src jump to pc_dest + uint32_t no_addresses = 0; + // uint32_t current_address_idx = 0; + uint32_t no_events = 0; + uint32_t no_calls = 0; + uint32_t no_branches = 0; + evm_word_t last_distance; // use to track branch distance by comparison opcodes + + __host__ __device__ void start_operation(const uint32_t pc, const uint8_t op, const CuEVM::evm_stack_t &stack_ptr); + __host__ __device__ void finish_operation(const CuEVM::evm_stack_t &stack_ptr, uint32_t error_code); + __host__ __device__ void start_call(uint32_t pc, evm_message_call_t *message_call_ptr); + __host__ __device__ void finish_call(uint8_t success); + __host__ __device__ void record_branch(uint32_t pc_src, uint32_t pc_dst, uint32_t pc_missed); + __host__ __device__ void record_distance(ArithEnv &arith, uint8_t op, const CuEVM::evm_stack_t &stack_ptr); + __host__ __device__ void print(); +}; struct trace_data_t { uint32_t pc; /**< The program counter */ uint8_t op; /**< The opcode */ @@ -73,7 +136,7 @@ struct tracer_t { __host__ __device__ void print_err(); - __device__ void print_device_err(); + __device__ void print_device_err(); __host__ cJSON *to_json(); }; diff --git a/CuEVM/include/CuEVM/utils/arith.cuh b/CuEVM/include/CuEVM/utils/arith.cuh index 9d72fa3..b8d0566 100644 --- a/CuEVM/include/CuEVM/utils/arith.cuh +++ b/CuEVM/include/CuEVM/utils/arith.cuh @@ -5,7 +5,6 @@ #pragma once -#include #include #include @@ -36,8 +35,7 @@ class ArithEnv { * @param[in] report The error report for the CGBN library * @param[in] instance The instance number for the CGBN library */ - __device__ ArithEnv(cgbn_monitor_t monitor, cgbn_error_report_t *report, - uint32_t instance); + __device__ ArithEnv(cgbn_monitor_t monitor, cgbn_error_report_t *report, uint32_t instance); /** * The constructor. This takes a monitor for the CGBN library. @@ -70,36 +68,30 @@ class ArithEnv { * @param[in] src The memory byte array * @param[in] size The size of the memory byte array */ -__host__ __device__ void cgbn_set_memory(env_t env, bn_t &dst, - const uint8_t *src, - const uint32_t size = 32); +__host__ __device__ void cgbn_set_memory(env_t env, bn_t &dst, const uint8_t *src, const uint32_t size = 32); /** * Get a CGBN type from a size_t. * @param[out] dst The destination CGBN * @param[in] src The size_t */ -__host__ __device__ void cgbn_set_size_t(env_t env, bn_t &dst, - const size_t src); +__host__ __device__ void cgbn_set_size_t(env_t env, bn_t &dst, const size_t src); /** * Get a size_t from a CGBN type. * @param[out] dst The destination size_t * @param[in] src The source CGBN * @return 1 for overflow, 0 otherwiese */ -__host__ __device__ int32_t cgbn_get_size_t(env_t env, size_t &dst, - const bn_t &src); +__host__ __device__ int32_t cgbn_get_size_t(env_t env, size_t &dst, const bn_t &src); /** * Get a uint64_t from a CGBN type. * @param[out] dst The destination uint64_t * @param[in] src The source CGBN * @return 1 for overflow, 0 otherwiese */ -__host__ __device__ int32_t cgbn_get_uint64_t(env_t env, uint64_t &dst, - const bn_t &src); +__host__ __device__ int32_t cgbn_get_uint64_t(env_t env, uint64_t &dst, const bn_t &src); -__host__ __device__ int32_t cgbn_get_uint32_t(env_t env, uint32_t &dst, - const bn_t &src); +__host__ __device__ int32_t cgbn_get_uint32_t(env_t env, uint32_t &dst, const bn_t &src); /** * Get the cgbn number from the byte array. @@ -107,8 +99,7 @@ __host__ __device__ int32_t cgbn_get_uint32_t(env_t env, uint32_t &dst, * @param[out] out The cgbn number. * @return The Error code. 0 for success, 1 for failure. */ -__host__ __device__ int32_t -cgbn_set_byte_array_t(env_t env, bn_t &out, const byte_array_t &byte_array); +__host__ __device__ int32_t cgbn_set_byte_array_t(env_t env, bn_t &out, const byte_array_t &byte_array); /** * Get the sub byte array from the byte array. @@ -118,12 +109,8 @@ cgbn_set_byte_array_t(env_t env, bn_t &out, const byte_array_t &byte_array); * @param[out] out The sub byte array. * @return The Error code. 0 for success, 1 for failure. */ -__host__ __device__ int32_t get_sub_byte_array_t(ArithEnv &arith, - const byte_array_t &byte_array, - const bn_t &index, - const bn_t &length, - byte_array_t &out); - +__host__ __device__ int32_t get_sub_byte_array_t(ArithEnv &arith, const byte_array_t &byte_array, const bn_t &index, + const bn_t &length, byte_array_t &out); /** * Get an array of maximum 256 bytes, each having value 1 or 0 indicating bit @@ -133,9 +120,7 @@ __host__ __device__ int32_t get_sub_byte_array_t(ArithEnv &arith, * @param[in] src_cgbn_mem * @param limb_count */ -__host__ __device__ void get_bit_array(uint8_t *dst_array, - uint32_t &array_length, - evm_word_t &src_cgbn_mem, +__host__ __device__ void get_bit_array(uint8_t *dst_array, uint32_t &array_length, evm_word_t &src_cgbn_mem, uint32_t limb_count = 8); /** @@ -146,9 +131,7 @@ __host__ __device__ void get_bit_array(uint8_t *dst_array, * @param[in] src_cgbn_mem * @param limb_count */ -__host__ __device__ void byte_array_from_cgbn_memory(uint8_t *dst_array, - size_t &array_length, - evm_word_t &src_cgbn_mem, +__host__ __device__ void byte_array_from_cgbn_memory(uint8_t *dst_array, size_t &array_length, evm_word_t &src_cgbn_mem, size_t limb_count = 8); /** @@ -158,8 +141,7 @@ __host__ __device__ void byte_array_from_cgbn_memory(uint8_t *dst_array, * @param[out] dst The memory byte array * @param[in] src The source CGBN */ -__host__ __device__ void memory_from_cgbn(ArithEnv &arith, uint8_t *dst, - bn_t &src); +__host__ __device__ void memory_from_cgbn(ArithEnv &arith, uint8_t *dst, bn_t &src); /** * Convert and evm word to and address format diff --git a/CuEVM/include/CuEVM/utils/cuda_utils.cuh b/CuEVM/include/CuEVM/utils/cuda_utils.cuh index 5b331c7..b5d320e 100644 --- a/CuEVM/include/CuEVM/utils/cuda_utils.cuh +++ b/CuEVM/include/CuEVM/utils/cuda_utils.cuh @@ -5,6 +5,15 @@ #pragma once + +// CGBN parameters +#ifndef CGBN_TPI +#define CGBN_TPI 32 +#endif + +#define CGBN_IBP 2 +#define SHARED_STACK_SIZE 128 + #include #include @@ -12,22 +21,23 @@ #ifndef MULTIPLE_THREADS_PER_INSTANCE #define MULTIPLE_THREADS_PER_INSTANCE #endif +#define THREADIDX threadIdx.x +#else +#define THREADIDX 0 #endif #ifdef MULTIPLE_THREADS_PER_INSTANCE -#define __ONE_THREAD_PER_INSTANCE(X) \ - if (threadIdx.x == 0) { \ - X \ - } +#define __ONE_THREAD_PER_INSTANCE(X) \ + if (threadIdx.x % CGBN_TPI == 0) { \ + X \ + } #define __ONE_GPU_THREAD_BEGIN__ \ __syncthreads(); \ - if (threadIdx.x == 0) { + if (threadIdx.x % CGBN_TPI == 0) { #define __ONE_GPU_THREAD_END__ \ } \ __syncthreads(); -#define __ONE_GPU_THREAD_WOSYNC_BEGIN__ \ - if (threadIdx.x == 0) { -#define __ONE_GPU_THREAD_WOSYNC_END__ \ - } +#define __ONE_GPU_THREAD_WOSYNC_BEGIN__ if (threadIdx.x % CGBN_TPI == 0) { +#define __ONE_GPU_THREAD_WOSYNC_END__ } #define __SYNC_THREADS__ __syncthreads(); #define __SHARED_MEMORY__ __shared__ #else @@ -41,9 +51,7 @@ #endif #ifdef DEBUG -#define DEBUG_PRINT(fmt, args...) \ - fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, \ - ##args) +#define DEBUG_PRINT(fmt, args...) fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args) #else #define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */ #endif @@ -57,7 +65,17 @@ #define CUDA_CHECK(action) cuda_check(action, #action, __FILE__, __LINE__) #define CGBN_CHECK(report) cgbn_check(report, __FILE__, __LINE__) -void cuda_check(cudaError_t status, const char *action = NULL, - const char *file = NULL, int32_t line = 0); -void cgbn_check(cgbn_error_report_t *report, const char *file = NULL, - int32_t line = 0); +#ifdef __CUDA_ARCH__ +#define INSTANCE_BLK_IDX threadIdx.x / CGBN_TPI +#define INSTANCE_GLOBAL_IDX (threadIdx.x + blockIdx.x * blockDim.x) / CGBN_TPI +#define THREAD_IDX_PER_INSTANCE threadIdx.x % CGBN_TPI +#define INSTANCE_IDX_PER_BLOCK threadIdx.x / CGBN_TPI +#else +#define INSTANCE_BLK_IDX 0 +#define INSTANCE_GLOBAL_IDX 0 +#define THREAD_IDX_PER_INSTANCE 0 +#define INSTANCE_IDX_PER_BLOCK 0 +#endif + +void cuda_check(cudaError_t status, const char *action = NULL, const char *file = NULL, int32_t line = 0); +void cgbn_check(cgbn_error_report_t *report, const char *file = NULL, int32_t line = 0); diff --git a/CuEVM/include/CuEVM/utils/ecc_constants.cuh b/CuEVM/include/CuEVM/utils/ecc_constants.cuh index 40bcf1a..ff49d55 100644 --- a/CuEVM/include/CuEVM/utils/ecc_constants.cuh +++ b/CuEVM/include/CuEVM/utils/ecc_constants.cuh @@ -94,7 +94,7 @@ struct EccConstants { for (int i = 0; i < 11; i++) { final_exp[i].from_hex(final_exp_const[i]); } - printf("EccConstants initialized\n"); + // printf("EccConstants initialized\n"); } }; } // namespace CuEVM \ No newline at end of file diff --git a/CuEVM/include/CuEVM/utils/evm_defines.cuh b/CuEVM/include/CuEVM/utils/evm_defines.cuh index 8e25b58..c2e77a4 100644 --- a/CuEVM/include/CuEVM/utils/evm_defines.cuh +++ b/CuEVM/include/CuEVM/utils/evm_defines.cuh @@ -73,6 +73,7 @@ #define EIP_4895 #define EIP_6049 #define PARIS + #endif #ifdef PARIS @@ -80,6 +81,7 @@ #define EIP_4399 #define EIP_5133 #define LONDON + #endif #ifdef LONDON @@ -109,6 +111,7 @@ #define EIP_2718 #define EIP_2929 #define EIP_2930 +#define EVM_PRECOMPILED_CONTRACTS 9 // 9 precompiled contracts #endif #ifdef EIP_2070 @@ -223,8 +226,8 @@ constexpr CONSTANT uint32_t max_initcode_size = std::numeric_limits::m constexpr CONSTANT uint32_t no_precompile_contracts = 10; -// CGBN parameters -constexpr CONSTANT uint32_t cgbn_tpi = 8; +constexpr CONSTANT uint32_t cgbn_tpi = CGBN_TPI; +constexpr CONSTANT uint32_t cgbn_IBP = CGBN_IBP; // CUEVM parameters constexpr CONSTANT uint32_t max_transactions_count = 10000; @@ -234,6 +237,8 @@ constexpr CONSTANT uint32_t cgbn_limbs = ((CuEVM::word_bits + 31) / 32); // specific implementation constants constexpr CONSTANT uint32_t initial_storage_capacity = 4; +constexpr CONSTANT uint32_t shared_stack_size = SHARED_STACK_SIZE; + /** * The CGBN context type. This is a template type that takes * the number of threads per instance and the diff --git a/CuEVM/include/CuEVM/utils/evm_utils.cuh b/CuEVM/include/CuEVM/utils/evm_utils.cuh index 1f17941..882d325 100644 --- a/CuEVM/include/CuEVM/utils/evm_utils.cuh +++ b/CuEVM/include/CuEVM/utils/evm_utils.cuh @@ -21,10 +21,19 @@ namespace CuEVM::utils { * @param[in] sender_address The sender address * @param[in] sender_nonce The sender nonce */ -__host__ __device__ int32_t get_contract_address_create( - ArithEnv &arith, bn_t &contract_address, const bn_t &sender_address, - const bn_t &sender_nonce); +__host__ __device__ int32_t get_contract_address_create(ArithEnv &arith, bn_t &contract_address, + const bn_t &sender_address, const bn_t &sender_nonce); +/** + * Get the contract address from the sender address and the sender nonce. + * For the simple CREATE operation. + * @param[in] arith The arithmetic environment + * @param[out] contract_address The contract address + * @param[in] sender_address The sender address + * @param[in] sender_nonce The sender nonce + */ +__host__ __device__ int32_t get_contract_address_create_word(ArithEnv &arith, evm_word_t *contract_address, + evm_word_t *sender_address, evm_word_t *sender_nonce); /** * Get the contract address from the sender address, the salt, and the init * code. For the CREATE2 operation. @@ -34,9 +43,9 @@ __host__ __device__ int32_t get_contract_address_create( * @param[in] salt The salt * @param[in] init_code The init code */ -__host__ __device__ int32_t get_contract_address_create2( - ArithEnv &arith, bn_t &contract_address, const bn_t &sender_address, - const bn_t &salt, const CuEVM::byte_array_t &init_code); +__host__ __device__ int32_t get_contract_address_create2(ArithEnv &arith, bn_t &contract_address, + const bn_t &sender_address, const bn_t &salt, + const CuEVM::byte_array_t &init_code); /** * If it is a hex character. @@ -67,8 +76,7 @@ __host__ __device__ int32_t is_hex(const char hex); * @param[in] high The high nibble. * @param[in] low The low nibble. */ -__host__ __device__ uint8_t byte_from_nibbles(const uint8_t high, - const uint8_t low); +__host__ __device__ uint8_t byte_from_nibbles(const uint8_t high, const uint8_t low); /** * Get the hex string from a byte. * @param[in] byte The byte. @@ -81,8 +89,7 @@ __host__ __device__ void hex_from_byte(char *dst, const uint8_t byte); * @param[in] low The low hex character. * @return The byte. */ -__host__ __device__ uint8_t byte_from_two_hex_char(const char high, - const char low); +__host__ __device__ uint8_t byte_from_two_hex_char(const char high, const char low); /** * Get the number of bytes oh a string * @param[in] hex_string diff --git a/CuEVM/include/CuEVM/utils/python_utils.h b/CuEVM/include/CuEVM/utils/python_utils.h new file mode 100644 index 0000000..a58846e --- /dev/null +++ b/CuEVM/include/CuEVM/utils/python_utils.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +#include +#include +#include + +#define GET_STR_FROM_DICT_WITH_DEFAULT(dict, key, default_value) \ + (PyDict_GetItemString(dict, key) ? PyUnicode_AsUTF8(PyDict_GetItemString(dict, key)) : default_value) +namespace DefaultBlock { +constexpr char BaseFee[] = "0x0a"; +constexpr char CoinBase[] = "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"; +constexpr char Difficulty[] = "0x020000"; +constexpr char BlockNumber[] = "0x01"; +constexpr char GasLimit[] = "0x05f5e100"; +constexpr char TimeStamp[] = "0x03e8"; +constexpr char PreviousHash[] = "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"; +} // namespace DefaultBlock + +void copy_dict_recursive(PyObject* read_root, PyObject* write_root); +static PyObject* print_dict(PyObject* self, PyObject* args); + +namespace python_utils { + +CuEVM::block_info_t* getBlockDataFromPyObject(PyObject* data); + +void print_dict_recursive(PyObject* dict, int indent_level); + +CuEVM::evm_transaction_t* getTransactionDataFromListofPyObject(PyObject* read_roots); + +CuEVM::state_t* getStateDataFromPyObject(PyObject* data); +void get_evm_instances_from_PyObject(CuEVM::evm_instance_t*& evm_instances, PyObject* read_roots, + uint32_t& num_instances); + +std::unordered_set const bug_opcodes = {OP_ADD, OP_MUL, OP_SUB, OP_MOD, OP_EXP, OP_SELFDESTRUCT, OP_ORIGIN}; +std::unordered_set const call_opcodes = {OP_CALL, OP_CALLCODE, OP_DELEGATECALL}; // ignore static call for now +std::unordered_set const comparison_opcodes = {OP_LT, OP_GT, OP_SLT, OP_SGT, OP_EQ}; +std::unordered_set const revert_opcodes = {OP_REVERT, OP_INVALID}; +// OP_SSTORE +// OP_JUMPI +// OP_SELFDESTRUCT + +PyObject* pyobject_from_serialized_state(CuEVM::serialized_worldstate_data* serialized_worldstate_instance); + +/** + * Get the pyobject from the evm instances after the transaction execution. + * @param[in] instances evm instances + * @return pyobject + */ +PyObject* pyobject_from_evm_instances(CuEVM::evm_instance_t* instances, uint32_t num_instances); +} // namespace python_utils diff --git a/CuEVM/libraries/CGBN b/CuEVM/libraries/CGBN index 04c0f68..825502c 160000 --- a/CuEVM/libraries/CGBN +++ b/CuEVM/libraries/CGBN @@ -1 +1 @@ -Subproject commit 04c0f68c04fe598c0ef74493bbd37dfb070fe4ee +Subproject commit 825502cea2b9435d007e499f13066086cedf0ba1 diff --git a/CuEVM/src/core/byte_array.cu b/CuEVM/src/core/byte_array.cu index f84f0b2..0143bdc 100644 --- a/CuEVM/src/core/byte_array.cu +++ b/CuEVM/src/core/byte_array.cu @@ -9,42 +9,71 @@ namespace CuEVM { __host__ __device__ byte_array_t::byte_array_t(const uint32_t size) : size(size) { - __SHARED_MEMORY__ uint8_t *tmp_data; - __ONE_GPU_THREAD_BEGIN__ + __SHARED_MEMORY__ uint8_t *tmp_data[CGBN_IBP]; + // printf("byte_array_t::byte_array_t construction %d %d instance id %d\n", THREADIDX, THREAD_IDX_PER_INSTANCE, + // INSTANCE_IDX_PER_BLOCK); if (size > 0) { - tmp_data = new uint8_t[size]; - memset(tmp_data, 0, size * sizeof(uint8_t)); + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + tmp_data[INSTANCE_IDX_PER_BLOCK] = new uint8_t[size]; + __ONE_GPU_THREAD_END__ + // memset(tmp_data, 0, size * sizeof(uint8_t)); + // parallel_copy + // printf("instance id %d , instance data %p\n", INSTANCE_IDX_PER_BLOCK, tmp_data[INSTANCE_IDX_PER_BLOCK]); + uint32_t my_idx = THREAD_IDX_PER_INSTANCE; + for (; my_idx < size; my_idx += CuEVM::cgbn_tpi) { + tmp_data[INSTANCE_IDX_PER_BLOCK][my_idx] = 0; + } } else - tmp_data = nullptr; - __ONE_GPU_THREAD_END__ - data = tmp_data; + tmp_data[INSTANCE_IDX_PER_BLOCK] = nullptr; + __SYNC_THREADS__ + data = tmp_data[INSTANCE_IDX_PER_BLOCK]; } -__host__ __device__ byte_array_t::byte_array_t(uint8_t *data, uint32_t size) : size(size) { - __SHARED_MEMORY__ uint8_t *tmp_data; - __ONE_GPU_THREAD_BEGIN__ +__device__ byte_array_t::byte_array_t(uint8_t *data, uint32_t size) : size(size) { + __SHARED_MEMORY__ uint8_t *tmp_data[CGBN_IBP]; + if (size > 0) { - tmp_data = new uint8_t[size]; - memcpy(tmp_data, data, size * sizeof(uint8_t)); + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + tmp_data[INSTANCE_IDX_PER_BLOCK] = new uint8_t[size]; + __ONE_GPU_THREAD_END__ + // memcpy(tmp_data, data, size * sizeof(uint8_t)); + // parallel_copy + uint32_t my_idx = THREAD_IDX_PER_INSTANCE; + for (; my_idx < size; my_idx += CuEVM::cgbn_tpi) { + tmp_data[INSTANCE_IDX_PER_BLOCK][my_idx] = data[my_idx]; + } } else - tmp_data = nullptr; - __ONE_GPU_THREAD_END__ - this->data = tmp_data; + tmp_data[INSTANCE_IDX_PER_BLOCK] = nullptr; + + this->data = tmp_data[INSTANCE_IDX_PER_BLOCK]; } __host__ __device__ byte_array_t::byte_array_t(const byte_array_t &src_byte_array, uint32_t offset, uint32_t size) : size(size) { - __SHARED_MEMORY__ uint8_t *tmp_data; - __ONE_GPU_THREAD_BEGIN__ + __SHARED_MEMORY__ uint8_t *tmp_data[CGBN_IBP]; + // printf("byte_array_t::byte_array_t %d %d %d %d\n", THREADIDX, THREAD_IDX_PER_INSTANCE, offset, size); if (size > 0) { - tmp_data = new uint8_t[size]; - memset(tmp_data, 0, size * sizeof(uint8_t)); + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + tmp_data[INSTANCE_IDX_PER_BLOCK] = new uint8_t[size]; + __ONE_GPU_THREAD_END__ + // memset(tmp_data, 0, size * sizeof(uint8_t)); + // parallel_copy + uint32_t my_idx = THREAD_IDX_PER_INSTANCE; + for (uint32_t idx = my_idx; idx < size; idx += CuEVM::cgbn_tpi) { + tmp_data[INSTANCE_IDX_PER_BLOCK][idx] = 0; + } + // parallel_copy if (offset < src_byte_array.size) - memcpy(tmp_data, src_byte_array.data + offset, min(size, src_byte_array.size - offset) * sizeof(uint8_t)); + for (uint32_t idx = my_idx; idx < min(size, src_byte_array.size - offset); idx += CuEVM::cgbn_tpi) { + tmp_data[INSTANCE_IDX_PER_BLOCK][idx] = src_byte_array.data[offset + idx]; + } + // if (offset < src_byte_array.size) + // memcpy(tmp_data, src_byte_array.data + offset, min(size, src_byte_array.size - offset) * + // sizeof(uint8_t)); } else - tmp_data = nullptr; - __ONE_GPU_THREAD_END__ - this->data = tmp_data; + tmp_data[INSTANCE_IDX_PER_BLOCK] = nullptr; + // __ONE_GPU_THREAD_END__ + this->data = tmp_data[INSTANCE_IDX_PER_BLOCK]; } __host__ byte_array_t::byte_array_t(const char *hex_string, int32_t endian, PaddingDirection padding) @@ -79,19 +108,19 @@ __host__ __device__ void byte_array_t::clear() { } __host__ __device__ byte_array_t::byte_array_t(const byte_array_t &other) : size(other.size) { - __SHARED_MEMORY__ uint8_t *tmp_data; + __SHARED_MEMORY__ uint8_t *tmp_data[CGBN_IBP]; __ONE_GPU_THREAD_BEGIN__ if (size > 0) { - tmp_data = new uint8_t[size]; - memcpy(tmp_data, other.data, size * sizeof(uint8_t)); + tmp_data[INSTANCE_IDX_PER_BLOCK] = new uint8_t[size]; + memcpy(tmp_data[INSTANCE_IDX_PER_BLOCK], other.data, size * sizeof(uint8_t)); } else - tmp_data = nullptr; + tmp_data[INSTANCE_IDX_PER_BLOCK] = nullptr; __ONE_GPU_THREAD_END__ - data = tmp_data; + data = tmp_data[INSTANCE_IDX_PER_BLOCK]; } __host__ __device__ byte_array_t &byte_array_t::operator=(const byte_array_t &other) { - __SHARED_MEMORY__ uint8_t *tmp_data; + __SHARED_MEMORY__ uint8_t *tmp_data[CGBN_IBP]; // #ifdef __CUDA_ARCH__ // printf("byte_array_t::operator= %d this %p other %p\n", threadIdx.x, this, &other); // printf("byte_array_t::operator= %d this size %d other size %d\n", threadIdx.x, size, other.size); @@ -109,15 +138,23 @@ __host__ __device__ byte_array_t &byte_array_t::operator=(const byte_array_t &ot // tmp_data = data; // cannot assign like this as data will be freed by others // } free(); // can do outside, all thread set to null - __ONE_GPU_THREAD_WOSYNC_BEGIN__ + if (other.size > 0) { // printf("other size !=0 %p \n", tmp_data); - tmp_data = new uint8_t[other.size]; - memcpy(tmp_data, other.data, other.size * sizeof(uint8_t)); + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + tmp_data[INSTANCE_IDX_PER_BLOCK] = new uint8_t[other.size]; + __ONE_GPU_THREAD_END__ + + // memcpy(tmp_data, other.data, other.size * sizeof(uint8_t)); + // parallel_copy + uint32_t my_idx = THREAD_IDX_PER_INSTANCE; + for (; my_idx < other.size; my_idx += CuEVM::cgbn_tpi) { + tmp_data[INSTANCE_IDX_PER_BLOCK][my_idx] = other.data[my_idx]; + } } else - tmp_data = nullptr; - __ONE_GPU_THREAD_END__ - data = tmp_data; + tmp_data[INSTANCE_IDX_PER_BLOCK] = nullptr; + + data = tmp_data[INSTANCE_IDX_PER_BLOCK]; size = other.size; } // __SYNC_THREADS__ @@ -128,42 +165,61 @@ __host__ __device__ byte_array_t &byte_array_t::operator=(const byte_array_t &ot } __host__ __device__ int32_t byte_array_t::grow(uint32_t new_size, int32_t zero_padding) { + // printf("byte_array_t::grow %d %d size %d zero_padding %d, new_size %d, data %p\n", THREADIDX, + // THREAD_IDX_PER_INSTANCE, size, zero_padding, new_size, data); if (new_size == size) return ERROR_SUCCESS; - __SHARED_MEMORY__ uint8_t *new_data; - __ONE_GPU_THREAD_BEGIN__ - new_data = new uint8_t[new_size]; - if (zero_padding) memset(new_data, 0, new_size * sizeof(uint8_t)); + __SHARED_MEMORY__ uint8_t *new_data[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + new_data[INSTANCE_IDX_PER_BLOCK] = new uint8_t[new_size]; + __ONE_GPU_THREAD_END__ + // printf("byte_array_t::grow %d %d %d %d new_data_pointer %p\n", THREADIDX, THREAD_IDX_PER_INSTANCE, new_size, + // zero_padding, new_data[INSTANCE_IDX_PER_BLOCK]); + if (zero_padding) { + // parallel_copy + uint32_t my_idx = THREAD_IDX_PER_INSTANCE; + for (; my_idx < new_size; my_idx += CuEVM::cgbn_tpi) { + new_data[INSTANCE_IDX_PER_BLOCK][my_idx] = 0; + } + } + // memset(new_data, 0, new_size * sizeof(uint8_t)); if (size > 0) { // if (new_size > size) { - memcpy(new_data, data, min(new_size, size) * sizeof(uint8_t)); + // memcpy(new_data, data, min(new_size, size) * sizeof(uint8_t)); + // parallel_copy + uint32_t my_idx = THREAD_IDX_PER_INSTANCE; + for (; my_idx < min(new_size, size); my_idx += CuEVM::cgbn_tpi) { + new_data[INSTANCE_IDX_PER_BLOCK][my_idx] = data[my_idx]; + } // if (zero_padding) // memset(new_data + size, 0, new_size - size); // } else { // memcpy(new_data, data, new_size * sizeof(uint8_t)); // } + __ONE_GPU_THREAD_WOSYNC_BEGIN__ delete[] data; + __ONE_GPU_THREAD_WOSYNC_END__ } - __ONE_GPU_THREAD_END__ - data = new_data; + + data = new_data[INSTANCE_IDX_PER_BLOCK]; size = new_size; return ERROR_SUCCESS; } __host__ __device__ uint32_t byte_array_t::has_value(uint8_t value) const { - __SHARED_MEMORY__ uint32_t error_code; + __SHARED_MEMORY__ uint32_t error_code[CGBN_IBP]; uint32_t index; - error_code = ERROR_VALUE_NOT_FOUND; + error_code[INSTANCE_IDX_PER_BLOCK] = ERROR_VALUE_NOT_FOUND; __SYNC_THREADS__ #ifdef __CUDA_ARCH__ uint32_t slot_size = size / CuEVM::cgbn_tpi; for (index = 0; index < slot_size; index++) { if (data[slot_size * threadIdx.x + index] == value) { - error_code = ERROR_SUCCESS; + error_code[INSTANCE_IDX_PER_BLOCK] = ERROR_SUCCESS; } } for (index = slot_size * CuEVM::cgbn_tpi; index < size; index++) { if (data[index] == value) { - error_code = ERROR_SUCCESS; + error_code[INSTANCE_IDX_PER_BLOCK] = ERROR_SUCCESS; } } __SYNC_THREADS__ @@ -174,7 +230,7 @@ __host__ __device__ uint32_t byte_array_t::has_value(uint8_t value) const { } } #endif - return error_code; + return error_code[INSTANCE_IDX_PER_BLOCK]; } __host__ __device__ void byte_array_t::print() const { diff --git a/CuEVM/src/core/evm_word.cu b/CuEVM/src/core/evm_word.cu index 39d99ca..696aa0e 100644 --- a/CuEVM/src/core/evm_word.cu +++ b/CuEVM/src/core/evm_word.cu @@ -22,9 +22,12 @@ __host__ __device__ evm_word_t &evm_word_t::operator=(const evm_word_t &src) { _limbs[index] = src._limbs[index]; } return *this;*/ - __ONE_GPU_THREAD_WOSYNC_BEGIN__ - memcpy(_limbs, src._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); - __ONE_GPU_THREAD_END__ + // __ONE_GPU_THREAD_BEGIN__ + // memcpy(_limbs, src._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // __ONE_GPU_THREAD_END__ + if (THREAD_IDX_PER_INSTANCE < CuEVM::cgbn_limbs) { + _limbs[THREAD_IDX_PER_INSTANCE] = src._limbs[THREAD_IDX_PER_INSTANCE]; + } return *this; } @@ -34,9 +37,32 @@ __host__ __device__ evm_word_t &evm_word_t::operator=(uint32_t value) { } __host__ __device__ int32_t evm_word_t::operator==(const evm_word_t &other) const { + // #pragma unroll + // for (int32_t index = 0; index < CuEVM::cgbn_limbs; index++) { + // if (_limbs[index] != other._limbs[index]) { + // return 0; + // } + // } + // return 1; + __SHARED_MEMORY__ int32_t res[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + res[INSTANCE_IDX_PER_BLOCK] = 1; + __ONE_GPU_THREAD_END__ + if (THREAD_IDX_PER_INSTANCE < CuEVM::cgbn_limbs && + (_limbs[THREAD_IDX_PER_INSTANCE] != other._limbs[THREAD_IDX_PER_INSTANCE])) { + res[INSTANCE_IDX_PER_BLOCK] = 0; + } + __SYNC_THREADS__ + return res[INSTANCE_IDX_PER_BLOCK]; +} +// todo optimize +__host__ __device__ int32_t evm_word_t::operator<(const uint32_t &value) const { + if (_limbs[0] >= value) { + return 0; + } #pragma unroll - for (int32_t index = 0; index < CuEVM::cgbn_limbs; index++) { - if (_limbs[index] != other._limbs[index]) { + for (int32_t index = 1; index < CuEVM::cgbn_limbs; index++) { + if (_limbs[index] != 0) { return 0; } } @@ -58,36 +84,84 @@ __host__ __device__ int32_t evm_word_t::operator==(const uint32_t &value) const __host__ __device__ int32_t evm_word_t::from_hex(const char *hex_string) { #ifdef __CUDA_ARCH__ - // todo: make host function + // todo: make device function #else CuEVM::byte_array_t byte_array(hex_string, CuEVM::word_size, BIG_ENDIAN, CuEVM::PaddingDirection::LEFT_PADDING); return from_byte_array_t(byte_array); #endif } -__host__ __device__ int32_t evm_word_t::from_byte_array_t(byte_array_t &byte_array, int32_t endian) { +__device__ int32_t evm_word_t::from_byte_array_t(byte_array_t &byte_array, int32_t endian) { if (byte_array.size != CuEVM::word_size) { return ERROR_BYTE_ARRAY_INVALID_SIZE; } uint8_t *bytes = nullptr; + if (endian == LITTLE_ENDIAN) { - bytes = byte_array.data; + bytes = byte_array.data; //+ my_idx * 4; + // printf("my_idx: %d, bytes: %p\n", my_idx, bytes); #pragma unroll + // _limbs[my_idx] = (*(bytes++) | *(bytes++) << 8 | *(bytes++) << 16 | *(bytes++) << 24); for (uint32_t idx = 0; idx < CuEVM::cgbn_limbs; idx++) { _limbs[idx] = (*(bytes++) | *(bytes++) << 8 | *(bytes++) << 16 | *(bytes++) << 24); } } else if (endian == BIG_ENDIAN) { - bytes = byte_array.data + CuEVM::word_size - 1; + uint8_t my_idx = THREAD_IDX_PER_INSTANCE; + // printf("my_idx: %d, bytes: %p offset %d\n", my_idx, bytes, CuEVM::word_size - 1 - my_idx * 4); + if (my_idx < CuEVM::cgbn_limbs) { + // printf("my_idx: %d, bytes: %p offset %d\n", my_idx, bytes, CuEVM::word_size - 1 - my_idx * 4); + bytes = byte_array.data + CuEVM::word_size - 1 - my_idx * 4; + _limbs[my_idx] = (*(bytes--) | *(bytes--) << 8 | *(bytes--) << 16 | *(bytes--) << 24); + } + + } else { + return ERROR_NOT_IMPLEMENTED; + } + return ERROR_SUCCESS; +} + +__host__ int32_t evm_word_t::from_byte_array_t_loop(byte_array_t &byte_array, int32_t endian) { + if (byte_array.size != CuEVM::word_size) { + return ERROR_BYTE_ARRAY_INVALID_SIZE; + } + uint8_t *bytes = nullptr; + + if (endian == LITTLE_ENDIAN) { + bytes = byte_array.data; //+ my_idx * 4; + // printf("my_idx: %d, bytes: %p\n", my_idx, bytes); #pragma unroll + // _limbs[my_idx] = (*(bytes++) | *(bytes++) << 8 | *(bytes++) << 16 | *(bytes++) << 24); + for (uint32_t idx = 0; idx < CuEVM::cgbn_limbs; idx++) { + _limbs[idx] = (*(bytes++) | *(bytes++) << 8 | *(bytes++) << 16 | *(bytes++) << 24); + } + } else if (endian == BIG_ENDIAN) { + // printf("my_idx: %d, bytes: %p offset %d\n", my_idx, bytes, CuEVM::word_size - 1 - my_idx * 4); for (uint32_t idx = 0; idx < CuEVM::cgbn_limbs; idx++) { + bytes = byte_array.data + CuEVM::word_size - 1 - idx * 4; _limbs[idx] = (*(bytes--) | *(bytes--) << 8 | *(bytes--) << 16 | *(bytes--) << 24); } + } else { return ERROR_NOT_IMPLEMENTED; } return ERROR_SUCCESS; } +// __device__ __host__ __device__ int32_t evm_word_t::address_from_byte_array_t(byte_array_t &byte_array) { +// if (byte_array.size != CuEVM::word_size) { +// return ERROR_BYTE_ARRAY_INVALID_SIZE; +// } +// uint8_t *bytes = nullptr; + +// uint8_t my_idx = THREAD_IDX_PER_INSTANCE; +// if (my_idx < CuEVM::cgbn_limbs) { +// bytes = byte_array.data + CuEVM::word_size - 1 - my_idx * 4; +// _limbs[my_idx] = (*(bytes--) | *(bytes--) << 8 | *(bytes--) << 16 | *(bytes--) << 24); +// } + +// return ERROR_SUCCESS; +// } + __host__ __device__ int32_t evm_word_t::from_size_t(size_t value) { if (sizeof(size_t) == sizeof(uint64_t)) { return from_uint64_t(value); @@ -97,6 +171,15 @@ __host__ __device__ int32_t evm_word_t::from_size_t(size_t value) { return ERROR_NOT_IMPLEMENTED; } } +__host__ __device__ void evm_word_t::set_zero() { + uint8_t my_idx = THREAD_IDX_PER_INSTANCE; + // printf("my_idx: %d, bytes: %p offset %d\n", my_idx, bytes, CuEVM::word_size - 1 - my_idx * 4); + if (my_idx < CuEVM::cgbn_limbs) { + for (uint32_t idx = my_idx; idx < CuEVM::cgbn_limbs; idx = idx + CuEVM::cgbn_tpi) { + _limbs[idx] = 0; + } + } +} __host__ __device__ int32_t evm_word_t::from_uint64_t(uint64_t value) { #pragma unroll @@ -180,9 +263,29 @@ __host__ __device__ char *evm_word_t::to_hex(char *hex_string, int32_t pretty, u return hex_string; } +__host__ __device__ char *evm_word_t::address_to_hex(char *hex_string, uint32_t count) const { + if (hex_string == nullptr) { + hex_string = new char[count * 5 + 3]; + } + hex_string[0] = '0'; + hex_string[1] = 'x'; + for (uint32_t idx = 3; idx < count; idx++) { + CuEVM::utils::hex_from_byte(hex_string + 2 + (idx - 3) * 8, (_limbs[count - 1 - idx] >> 24) & 0xFF); + CuEVM::utils::hex_from_byte(hex_string + 2 + (idx - 3) * 8 + 2, (_limbs[count - 1 - idx] >> 16) & 0xFF); + CuEVM::utils::hex_from_byte(hex_string + 2 + (idx - 3) * 8 + 4, (_limbs[count - 1 - idx] >> 8) & 0xFF); + CuEVM::utils::hex_from_byte(hex_string + 2 + (idx - 3) * 8 + 6, _limbs[count - 1 - idx] & 0xFF); + } + hex_string[43] = '\0'; + + return hex_string; +} + __host__ __device__ int32_t evm_word_t::to_byte_array_t(byte_array_t &byte_array, int32_t endian) const { byte_array.grow(CuEVM::word_size, 1); uint8_t *bytes = nullptr; + // printf("evm_word_t::to_byte_array_t %d %d endian %d byte_array.data %p\n", THREADIDX, + // THREAD_IDX_PER_INSTANCE, + // endian, byte_array.data); if (endian == BIG_ENDIAN) { __ONE_GPU_THREAD_WOSYNC_BEGIN__ bytes = byte_array.data + CuEVM::word_size - 1; diff --git a/CuEVM/src/core/jump_destinations.cu b/CuEVM/src/core/jump_destinations.cu index 2907959..2246d29 100644 --- a/CuEVM/src/core/jump_destinations.cu +++ b/CuEVM/src/core/jump_destinations.cu @@ -10,13 +10,16 @@ #include namespace CuEVM { -__host__ __device__ -jump_destinations_t::jump_destinations_t(CuEVM::byte_array_t &byte_code) - : destinations(0U) { - uint32_t size = 0; +__host__ __device__ jump_destinations_t::jump_destinations_t(CuEVM::byte_array_t &byte_code) { + return; // temporarily disabled + size = 0; + capacity = 0; uint8_t opcode; uint8_t push_size; - uint32_t pc; + uint16_t pc; + uint16_t current_capacity = 16; + grow_capacity(current_capacity); + for (pc = 0; pc < byte_code.size; pc++) { opcode = byte_code.data[pc]; // if a push x @@ -25,35 +28,137 @@ jump_destinations_t::jump_destinations_t(CuEVM::byte_array_t &byte_code) pc = pc + push_size; } if (opcode == OP_JUMPDEST) { - size = size + 1; + size++; + if (size > current_capacity) { + current_capacity = current_capacity + 16; + grow_capacity(current_capacity); + } + destinations[size - 1] = pc; } } - if (size > 0) { - destinations.grow(size, 1); - uint32_t index = 0; - for (pc = 0; pc < byte_code.size; pc++) { - opcode = byte_code.data[pc]; - // if a push x - if (((opcode & 0xF0) == 0x60) || ((opcode & 0xF0) == 0x70)) { - push_size = (opcode & 0x1F) + 1; - pc = pc + push_size; - } - if (opcode == OP_JUMPDEST) { - destinations[index] = pc; - index++; + + // #ifdef __CUDA_ARCH__ + // printf("jump destination initialized size %d capapcity %d\n", size, capacity, threadIdx.x); + // #endif + // if (size > 0) { + // destinations.grow(size, 1); + // uint32_t index = 0; + // for (pc = 0; pc < byte_code.size; pc++) { + // opcode = byte_code.data[pc]; + // // if a push x + // if (((opcode & 0xF0) == 0x60) || ((opcode & 0xF0) == 0x70)) { + // push_size = (opcode & 0x1F) + 1; + // pc = pc + push_size; + // } + // if (opcode == OP_JUMPDEST) { + // destinations[index] = pc; + // index++; + // } + // } + // } +} +__host__ __device__ void jump_destinations_t::set_bytecode(CuEVM::byte_array_t &byte_code) { + return; // temporarily disabled + size = 0; + uint8_t opcode; + uint8_t push_size; + uint16_t pc; + uint16_t current_capacity = capacity; + if (current_capacity == 0) { + current_capacity = 16; + grow_capacity(current_capacity); + } + + // grow_capacity(current_capacity); + + for (pc = 0; pc < byte_code.size; pc++) { + opcode = byte_code.data[pc]; + // if a push x + if (((opcode & 0xF0) == 0x60) || ((opcode & 0xF0) == 0x70)) { + push_size = (opcode & 0x1F) + 1; + pc = pc + push_size; + } + if (opcode == OP_JUMPDEST) { + size++; + if (size > current_capacity) { + current_capacity = current_capacity + 16; + grow_capacity(current_capacity); } + destinations[size - 1] = pc; } } + // #ifdef __CUDA_ARCH__ + // printf("jump destination copied set_bytecode size %d capapcity %d\n", size, capacity, threadIdx.x); + // #endif +} +__host__ __device__ jump_destinations_t::~jump_destinations_t() { + if (capacity > 0) { + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + delete[] destinations; + __ONE_GPU_THREAD_WOSYNC_END__ + } } - -__host__ __device__ jump_destinations_t::~jump_destinations_t() {} __host__ __device__ uint32_t jump_destinations_t::has(uint32_t pc) { - return destinations.has_value(pc) == ERROR_SUCCESS - ? ERROR_SUCCESS - : ERROR_INVALID_JUMP_DESTINATION; + return ERROR_SUCCESS; // Temporarily disabled + // return destinations.has_value(pc) == ERROR_SUCCESS ? ERROR_SUCCESS : ERROR_INVALID_JUMP_DESTINATION; + + __SHARED_MEMORY__ uint32_t error_code[CGBN_IBP]; + uint32_t index; + error_code[INSTANCE_IDX_PER_BLOCK] = ERROR_INVALID_JUMP_DESTINATION; + __SYNC_THREADS__ +#ifdef __CUDA_ARCH__ + uint32_t slot_size = (size + CuEVM::cgbn_tpi) / CuEVM::cgbn_tpi; + for (index = 0; index < slot_size; index++) { + if (slot_size * threadIdx.x + index >= size) { + break; + } + if (destinations[slot_size * threadIdx.x + index] > pc) { + break; + } + if (destinations[slot_size * threadIdx.x + index] == pc) { + error_code[INSTANCE_IDX_PER_BLOCK] = ERROR_SUCCESS; + break; + } + } + __SYNC_THREADS__ +#else + for (index = 0; index < size; index++) { + if (destinations[index] == pc) { + error_code[INSTANCE_IDX_PER_BLOCK] = ERROR_SUCCESS; + break; + } + } +#endif + return error_code[INSTANCE_IDX_PER_BLOCK]; +} + +__host__ __device__ int32_t jump_destinations_t::grow_capacity(uint32_t new_capacity) { + if (new_capacity == capacity) return ERROR_SUCCESS; + __SHARED_MEMORY__ uint16_t *new_data[CGBN_IBP]; + __ONE_GPU_THREAD_BEGIN__ + new_data[INSTANCE_IDX_PER_BLOCK] = new uint16_t[new_capacity]; + if (capacity > 0) { + // printf("Copying destinations\n"); + // printf("New capacity: %d\n", new_capacity); + // printf("Old capacity: %d\n", capacity); + // printf("destination ptr: %p\n", destinations); + // if (new_size > size) { + memcpy(new_data[INSTANCE_IDX_PER_BLOCK], destinations, min(new_capacity, capacity) * sizeof(uint16_t)); + + delete[] destinations; + } + __ONE_GPU_THREAD_END__ + destinations = new_data[INSTANCE_IDX_PER_BLOCK]; + capacity = new_capacity; + return ERROR_SUCCESS; } -__host__ __device__ void jump_destinations_t::print() { destinations.print(); } +__host__ __device__ void jump_destinations_t::print() { + // // Temporarily disabled + // for (uint32_t i = 0; i < real_size; i++) { + // printf("Jump destination %d: %d\n", i, destinations[i]); + // } +} } // namespace CuEVM \ No newline at end of file diff --git a/CuEVM/src/core/message.cu b/CuEVM/src/core/message.cu index 8bcee8b..d21bdac 100644 --- a/CuEVM/src/core/message.cu +++ b/CuEVM/src/core/message.cu @@ -6,272 +6,295 @@ #include - namespace CuEVM { - __host__ __device__ evm_message_call_t::evm_message_call_t( - ArithEnv &arith, - const bn_t &sender, - const bn_t &recipient, - const bn_t &contract_address, - const bn_t &gas_limit, - const bn_t &value, - const uint32_t depth, - const uint32_t call_type, - const bn_t &storage_address, - const CuEVM::byte_array_t &data, - const CuEVM::byte_array_t &byte_code, - const bn_t &return_data_offset, - const bn_t &return_data_size, - const uint32_t static_env - ) { - cgbn_store(arith.env, &this->sender, sender); - cgbn_store(arith.env, &this->recipient, recipient); - cgbn_store(arith.env, &this->contract_address, contract_address); - cgbn_store(arith.env, &this->gas_limit, gas_limit); - cgbn_store(arith.env, &this->value, value); - this->depth = depth; - this->call_type = call_type; - cgbn_store(arith.env, &this->storage_address, storage_address); - this->data = data; - this->byte_code = byte_code; - cgbn_store(arith.env, &this->return_data_offset, return_data_offset); - cgbn_store(arith.env, &this->return_data_size, return_data_size); - this->static_env = static_env; - // create the jump destinations - this->jump_destinations = new CuEVM::jump_destinations_t( - this->byte_code); - } - __host__ __device__ evm_message_call_t::~evm_message_call_t() { - // todo maybe to delete the inside vectors who knows - delete jump_destinations; - jump_destinations = nullptr; - } +__host__ __device__ evm_message_call_t_shadow::evm_message_call_t_shadow( + ArithEnv &arith, const evm_word_t *sender, const evm_word_t *recipient, const evm_word_t *contract_address, + const evm_word_t *gas_limit, const evm_word_t *value, const uint32_t depth, const uint32_t call_type, + const evm_word_t *storage_address, const CuEVM::byte_array_t &data, const CuEVM::byte_array_t &byte_code, + const bn_t &return_data_offset, const bn_t &return_data_size, const uint32_t static_env) { + __SHARED_MEMORY__ evm_word_t *new_params_data[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + new_params_data[INSTANCE_IDX_PER_BLOCK] = new evm_word_t[8]; + __ONE_GPU_THREAD_END__ + this->params_data = new_params_data[INSTANCE_IDX_PER_BLOCK]; + /* + evm_word_t *sender; + evm_word_t *recipient; + evm_word_t *contract_address; + evm_word_t *gas_limit; + evm_word_t *value; + evm_word_t *storage_address; + evm_word_t *return_data_offset; + evm_word_t *return_data_size; +*/ + this->params_data[0] = *sender; + this->params_data[1] = *recipient; + this->params_data[2] = *contract_address; + this->params_data[3] = *gas_limit; + this->params_data[4] = *value; + this->params_data[5] = *storage_address; + // this->params_data[6] = *return_data_offset; + // this->params_data[7] = *return_data_size; + cgbn_store(arith.env, &this->params_data[6], return_data_offset); + cgbn_store(arith.env, &this->params_data[7], return_data_size); + // this->params_data[2].print(); + this->depth = depth; + this->call_type = call_type; - /** - * Get the sender address. - * @param[in] arith The arithmetical environment. - * @param[out] sender The sender address YP: \f$s\f$. - */ - __host__ __device__ void evm_message_call_t::get_sender( - ArithEnv &arith, - bn_t &sender) const { - cgbn_load(arith.env, sender, (cgbn_evm_word_t_ptr) &this->sender); - } + this->data = new byte_array_t(data); + this->byte_code = new byte_array_t(byte_code); + // printf("evm message call constructor return data offset: "); + // print_bnt(arith, return_data_offset); + // this->params_data[6].print(); + // printf("evm message call constructor return data size: "); + // print_bnt(arith, return_data_size); + // this->params_data[7].print(); - /** - * Get the recipient address. - * @param[in] arith The arithmetical environment. - * @param[out] recipient The recipient address YP: \f$r\f$. - */ - __host__ __device__ void evm_message_call_t::get_recipient( - ArithEnv &arith, - bn_t &recipient) const { - cgbn_load(arith.env, recipient, (cgbn_evm_word_t_ptr) &this->recipient); - } + this->static_env = static_env; + // create the jump destinations + // printf("evm create jump destinations %p\n", this->jump_destinations); + this->jump_destinations = new CuEVM::jump_destinations_t(*this->byte_code); +} +// Copy function , only words global -> shared mem +__host__ __device__ void evm_message_call_t::copy_from(const evm_message_call_t_shadow *other) { + // printf("evm_message_call_t copy_from other\n "); - /** - * Get the contract address. - * @param[in] arith The arithmetical environment. - * @param[out] contract_address The contract address YP: \f$c\f$. - */ - __host__ __device__ void evm_message_call_t::get_contract_address( - ArithEnv &arith, - bn_t &contract_address) const { - cgbn_load(arith.env, contract_address, (cgbn_evm_word_t_ptr) &this->contract_address); - } + // sender = other.sender; + // recipient = other.recipient; + // contract_address = other.contract_address; + // gas_limit = other.gas_limit; + // value = other.value; + // storage_address = other.storage_address; + // return_data_offset = other.return_data_offset; + // return_data_size = other.return_data_size; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // memcpy(sender._limbs, other->sender._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // memcpy(recipient._limbs, other->recipient._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // memcpy(contract_address._limbs, other->contract_address._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // memcpy(gas_limit._limbs, other->gas_limit._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // memcpy(value._limbs, other->value._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // memcpy(storage_address._limbs, other->storage_address._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // memcpy(return_data_offset._limbs, other->return_data_offset._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // memcpy(return_data_size._limbs, other->return_data_size._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t)); + // may not work: + memcpy(sender._limbs, other->params_data[0]._limbs, CuEVM::cgbn_limbs * sizeof(uint32_t) * 8); + // printf("evm_message_call_t copy_from other after memcpy\n "); + data = other->data; + byte_code = other->byte_code; + static_env = other->static_env; + depth = other->depth; + // printf("evm_message_call_t copy_from other->depth\n "); + call_type = other->call_type; + jump_destinations = other->jump_destinations; + __ONE_GPU_THREAD_END__ +} +__host__ __device__ evm_message_call_t::~evm_message_call_t() { + // todo maybe to delete the inside vectors who knows + delete jump_destinations; + jump_destinations = nullptr; + delete data; + data = nullptr; + delete byte_code; + byte_code = nullptr; +} - /** - * Get the gas limit. - * @param[in] arith The arithmetical environment. - * @param[out] gas_limit The gas limit YP: \f$g\f$. - */ - __host__ __device__ void evm_message_call_t::get_gas_limit( - ArithEnv &arith, - bn_t &gas_limit) const { - cgbn_load(arith.env, gas_limit, (cgbn_evm_word_t_ptr) &this->gas_limit); - } +/** + * Get the sender address. + * @param[in] arith The arithmetical environment. + * @param[out] sender The sender address YP: \f$s\f$. + */ +__host__ __device__ void evm_message_call_t::get_sender(ArithEnv &arith, bn_t &sender) const { + cgbn_load(arith.env, sender, (cgbn_evm_word_t_ptr) & this->sender); +} - /** - * Get the value. - * @param[in] arith The arithmetical environment. - * @param[out] value The value YP: \f$v\f$ or \f$v^{'}\f$ for DelegateCALL. - */ - __host__ __device__ void evm_message_call_t::get_value( - ArithEnv &arith, - bn_t &value) const { - cgbn_load(arith.env, value, (cgbn_evm_word_t_ptr) &this->value); - } +/** + * Get the recipient address. + * @param[in] arith The arithmetical environment. + * @param[out] recipient The recipient address YP: \f$r\f$. + */ +__host__ __device__ void evm_message_call_t::get_recipient(ArithEnv &arith, bn_t &recipient) const { + cgbn_load(arith.env, recipient, (cgbn_evm_word_t_ptr) & this->recipient); +} - /** - * Get the depth. - * @return The depth YP: \f$e\f$. - */ - __host__ __device__ uint32_t evm_message_call_t::get_depth() const { - return this->depth; - } +/** + * Get the contract address. + * @param[in] arith The arithmetical environment. + * @param[out] contract_address The contract address YP: \f$c\f$. + */ +__host__ __device__ void evm_message_call_t::get_contract_address(ArithEnv &arith, bn_t &contract_address) const { + cgbn_load(arith.env, contract_address, (cgbn_evm_word_t_ptr) & this->contract_address); +} - /** - * Get the call type. - * @return The call type internal has the opcode YP: \f$w\f$. - */ - __host__ __device__ uint32_t evm_message_call_t::get_call_type() const { - return this->call_type; - } +/** + * Get the gas limit. + * @param[in] arith The arithmetical environment. + * @param[out] gas_limit The gas limit YP: \f$g\f$. + */ +__host__ __device__ void evm_message_call_t::get_gas_limit(ArithEnv &arith, bn_t &gas_limit) const { + cgbn_load(arith.env, gas_limit, (cgbn_evm_word_t_ptr) & this->gas_limit); +} - /** - * Get the storage address. - * @param[in] arith The arithmetical environment. - * @param[out] storage_address The storage address YP: \f$a\f$. - */ - __host__ __device__ void evm_message_call_t::get_storage_address( - ArithEnv &arith, - bn_t &storage_address) const { - cgbn_load(arith.env, storage_address, (cgbn_evm_word_t_ptr) &this->storage_address); - } +/** + * Get the value. + * @param[in] arith The arithmetical environment. + * @param[out] value The value YP: \f$v\f$ or \f$v^{'}\f$ for DelegateCALL. + */ +__host__ __device__ void evm_message_call_t::get_value(ArithEnv &arith, bn_t &value) const { + cgbn_load(arith.env, value, (cgbn_evm_word_t_ptr) & this->value); +} - /** - * Get the call/init data. - * @return The data YP: \f$d\f$. - */ - __host__ __device__ CuEVM::byte_array_t evm_message_call_t::get_data() const { - return this->data; - } +/** + * Get the depth. + * @return The depth YP: \f$e\f$. + */ +__host__ __device__ uint32_t evm_message_call_t::get_depth() const { return this->depth; } - /** - * Get the byte code. - * @return The byte code YP: \f$b\f$. - */ - __host__ __device__ CuEVM::byte_array_t evm_message_call_t::get_byte_code() const { - return this->byte_code; - } +/** + * Get the call type. + * @return The call type internal has the opcode YP: \f$w\f$. + */ +__host__ __device__ uint32_t evm_message_call_t::get_call_type() const { return this->call_type; } - /** - * Get the return data offset. - * @param[in] arith The arithmetical environment. - * @param[out] return_data_offset The return data offset in memory. - */ - __host__ __device__ void evm_message_call_t::get_return_data_offset( - ArithEnv &arith, - bn_t &return_data_offset) const { - cgbn_load(arith.env, return_data_offset, (cgbn_evm_word_t_ptr) &this->return_data_offset); - } +/** + * Get the storage address. + * @param[in] arith The arithmetical environment. + * @param[out] storage_address The storage address YP: \f$a\f$. + */ +__host__ __device__ void evm_message_call_t::get_storage_address(ArithEnv &arith, bn_t &storage_address) const { + cgbn_load(arith.env, storage_address, (cgbn_evm_word_t_ptr) & this->storage_address); +} - /** - * Get the return data size. - * @param[in] arith The arithmetical environment. - * @param[out] return_data_size The return data size in memory. - */ - __host__ __device__ void evm_message_call_t::get_return_data_size( - ArithEnv &arith, - bn_t &return_data_size) const { - cgbn_load(arith.env, return_data_size, (cgbn_evm_word_t_ptr) &this->return_data_size); - } +/** + * Get the call/init data. + * @return The data YP: \f$d\f$. + */ +__host__ __device__ CuEVM::byte_array_t evm_message_call_t::get_data() const { return *this->data; } - /** - * Get the static flag. - * @return The static flag (STATICCALL) YP: \f$w\f$. - */ - __host__ __device__ uint32_t evm_message_call_t::get_static_env() const { - return this->static_env; - } +/** + * Get the byte code. + * @return The byte code YP: \f$b\f$. + */ +__host__ __device__ CuEVM::byte_array_t evm_message_call_t::get_byte_code() const { return *this->byte_code; } - /** - * Set the gas limit. - * @param[in] arith The arithmetical environment. - * @param[in] gas_limit The gas limit YP: \f$g\f$. - */ - __host__ __device__ void evm_message_call_t::set_gas_limit( - ArithEnv &arith, - bn_t &gas_limit) { - cgbn_store(arith.env, &this->gas_limit, gas_limit); - } +/** + * Get the return data offset. + * @param[in] arith The arithmetical environment. + * @param[out] return_data_offset The return data offset in memory. + */ +__host__ __device__ void evm_message_call_t::get_return_data_offset(ArithEnv &arith, bn_t &return_data_offset) const { + cgbn_load(arith.env, return_data_offset, (cgbn_evm_word_t_ptr) & this->return_data_offset); +} - /** - * Set the call data. - * @param[in] data The data YP: \f$d\f$. - */ - __host__ __device__ void evm_message_call_t::set_data( - CuEVM::byte_array_t &data) { - this->data = data; - } +/** + * Get the return data size. + * @param[in] arith The arithmetical environment. + * @param[out] return_data_size The return data size in memory. + */ +__host__ __device__ void evm_message_call_t::get_return_data_size(ArithEnv &arith, bn_t &return_data_size) const { + cgbn_load(arith.env, return_data_size, (cgbn_evm_word_t_ptr) & this->return_data_size); +} - /** - * Set the byte code. - * @param[in] byte_code The byte code YP: \f$b\f$. - */ - __host__ __device__ void evm_message_call_t::set_byte_code( - CuEVM::byte_array_t &byte_code) { - this->byte_code = byte_code; - if (jump_destinations != nullptr) - { - delete jump_destinations; - jump_destinations = nullptr; - } - jump_destinations = new CuEVM::jump_destinations_t( - byte_code); - } +/** + * Get the static flag. + * @return The static flag (STATICCALL) YP: \f$w\f$. + */ +__host__ __device__ uint32_t evm_message_call_t::get_static_env() const { return this->static_env; } - /** - * Set the return data offset. - * @param[in] arith The arithmetical environment. - * @param[in] return_data_offset The return data offset in memory. - */ - __host__ __device__ void evm_message_call_t::set_return_data_offset( - ArithEnv &arith, - bn_t &return_data_offset) { - cgbn_store(arith.env, (cgbn_evm_word_t_ptr) &this->return_data_offset, return_data_offset); - } +/** + * Set the gas limit. + * @param[in] arith The arithmetical environment. + * @param[in] gas_limit The gas limit YP: \f$g\f$. + */ +__host__ __device__ void evm_message_call_t::set_gas_limit(ArithEnv &arith, bn_t &gas_limit) { + cgbn_store(arith.env, &this->gas_limit, gas_limit); +} - /** - * Set the return data size. - * @param[in] arith The arithmetical environment. - * @param[in] return_data_size The return data size in memory. - */ - __host__ __device__ void evm_message_call_t::set_return_data_size( - ArithEnv &arith, - bn_t &return_data_size) { - cgbn_store(arith.env, (cgbn_evm_word_t_ptr) &this->return_data_size, return_data_size); - } +/** + * Set the call data. + * @param[in] data The data YP: \f$d\f$. + */ +__host__ __device__ void evm_message_call_t::set_data(CuEVM::byte_array_t &data) { *this->data = data; } - /** - * Get the jump destinations. - * @return The jump destinations. - */ - __host__ __device__ CuEVM::jump_destinations_t* evm_message_call_t::get_jump_destinations() const { - return jump_destinations; +/** + * Set the byte code. + * @param[in] byte_code The byte code YP: \f$b\f$. + */ +__host__ __device__ void evm_message_call_t::set_byte_code(CuEVM::byte_array_t &byte_code) { + *this->byte_code = byte_code; + // printf("*this->byte_code = byte_code; \n"); + // this->byte_code->print(); + // printf("other byte_code; \n"); + // byte_code.print(); +#ifdef __CUDA_ARCH__ + // printf("*this->byte_code = byte_code; idx %d \n", threadIdx.x); +#endif + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + if (jump_destinations == nullptr) { + jump_destinations = new CuEVM::jump_destinations_t(*this->byte_code); + // delete jump_destinations; + // jump_destinations = nullptr; } + // __ONE_GPU_THREAD_END__ + jump_destinations->set_bytecode(byte_code); +} - /** - * Print the message. - */ - __host__ __device__ void evm_message_call_t::print() const { - printf("sender: "); - sender.print(); - printf("\nrecipient: "); - recipient.print(); - printf("\ncontract_address: "); - contract_address.print(); - printf("\ngas_limit: "); - gas_limit.print(); - printf("\nvalue: "); - value.print(); - printf("\ndepth: %d", depth); - printf("\ncall_type: %d", call_type); - printf("\nstorage_address: "); - storage_address.print(); - printf("\ndata: "); - data.print(); - printf("\nbyte_code: "); - byte_code.print(); - printf("\nreturn_data_offset: "); - return_data_offset.print(); - printf("\nreturn_data_size: "); - return_data_size.print(); - printf("\nstatic_env: %d\n", static_env); - } +/** + * Set the return data offset. + * @param[in] arith The arithmetical environment. + * @param[in] return_data_offset The return data offset in memory. + */ +__host__ __device__ void evm_message_call_t::set_return_data_offset(ArithEnv &arith, bn_t &return_data_offset) { + cgbn_store(arith.env, (cgbn_evm_word_t_ptr) & this->return_data_offset, return_data_offset); +} + +/** + * Set the return data size. + * @param[in] arith The arithmetical environment. + * @param[in] return_data_size The return data size in memory. + */ +__host__ __device__ void evm_message_call_t::set_return_data_size(ArithEnv &arith, bn_t &return_data_size) { + cgbn_store(arith.env, (cgbn_evm_word_t_ptr) & this->return_data_size, return_data_size); +} + +/** + * Get the jump destinations. + * @return The jump destinations. + */ +// __host__ __device__ CuEVM::jump_destinations_t *evm_message_call_t::get_jump_destinations() const { +// return jump_destinations; +// } + +/** + * Print the message. + */ +__host__ __device__ void evm_message_call_t::print() const { + printf("sender: "); + sender.print(); + printf("\nrecipient: "); + recipient.print(); + printf("\ncontract_address: "); + contract_address.print(); + printf("\ngas_limit: "); + gas_limit.print(); + printf("\nvalue: "); + value.print(); + printf("\ndepth: %d", depth); + printf("\ncall_type: %d", call_type); + printf("\nstorage_address: "); + storage_address.print(); + printf("\ndata: "); + data->print(); + printf("\nbyte_code: "); + byte_code->print(); + printf("\nreturn_data_offset: "); + return_data_offset.print(); + printf("\nreturn_data_size: "); + return_data_size.print(); + printf("\nstatic_env: %d\n", static_env); } +} // namespace CuEVM diff --git a/CuEVM/src/core/stack.cu b/CuEVM/src/core/stack.cu index 622569c..65df05d 100644 --- a/CuEVM/src/core/stack.cu +++ b/CuEVM/src/core/stack.cu @@ -8,96 +8,241 @@ namespace CuEVM::stack { -__host__ __device__ evm_stack_t::evm_stack_t() : stack_base(nullptr), stack_offset(0), capacity(0) {} +__host__ __device__ evm_stack_t::evm_stack_t(evm_word_t *shared_stack_base, uint32_t stack_base_offset) + : shared_stack_base(shared_stack_base), + global_stack_base(nullptr), + stack_base_offset(stack_base_offset), + stack_offset(0) {} __host__ __device__ evm_stack_t::~evm_stack_t() { free(); } -__host__ __device__ evm_stack_t::evm_stack_t(const evm_stack_t &other) { - // free(); - duplicate(other); -} +// __host__ __device__ evm_stack_t::evm_stack_t(const evm_stack_t &other) { +// // free(); +// duplicate(other); +// } __host__ __device__ void evm_stack_t::free() { - __ONE_GPU_THREAD_BEGIN__ - if (stack_base != nullptr) { - delete[] stack_base; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + if (global_stack_base != nullptr) { + delete[] global_stack_base; } - __ONE_GPU_THREAD_END__ + __ONE_GPU_THREAD_WOSYNC_END__ clear(); } __host__ __device__ void evm_stack_t::clear() { stack_offset = 0; - capacity = 0; - stack_base = nullptr; + // capacity = 0; + global_stack_base = nullptr; } -__host__ __device__ evm_stack_t &evm_stack_t::operator=(const evm_stack_t &other) { - if (this != &other) { - free(); - duplicate(other); - } - return *this; -} +// __host__ __device__ evm_stack_t &evm_stack_t::operator=(const evm_stack_t &other) { +// if (this != &other) { +// free(); +// duplicate(other); +// } +// return *this; +// } -__host__ __device__ void evm_stack_t::duplicate(const evm_stack_t &other) { - __SHARED_MEMORY__ evm_word_t *tmp_stack_base; - __ONE_GPU_THREAD_BEGIN__ - tmp_stack_base = new evm_word_t[other.capacity]; - if (tmp_stack_base != nullptr) { - memcpy(tmp_stack_base, other.stack_base, other.stack_offset * sizeof(evm_word_t)); - } - __ONE_GPU_THREAD_END__ - stack_offset = other.stack_offset; - capacity = other.stack_offset; - stack_base = tmp_stack_base; -} +// __host__ __device__ void evm_stack_t::duplicate(const evm_stack_t &other) { +// __SHARED_MEMORY__ evm_word_t *tmp_stack_base; +// __ONE_GPU_THREAD_BEGIN__ +// tmp_stack_base = new evm_word_t[other.capacity]; +// if (tmp_stack_base != nullptr) { +// memcpy(tmp_stack_base, other.global_stack_base, other.stack_offset * sizeof(evm_word_t)); +// } +// __ONE_GPU_THREAD_END__ +// stack_offset = other.stack_offset; +// capacity = other.stack_offset; +// global_stack_base = tmp_stack_base; +// } -__host__ __device__ int32_t evm_stack_t::grow() { - capacity = (capacity == 0) ? initial_capacity : capacity * 2; - if (capacity > max_size) { - return ERROR_STACK_OVERFLOW; - } - __SHARED_MEMORY__ evm_word_t *new_stack_base; - __ONE_GPU_THREAD_BEGIN__ - new_stack_base = new evm_word_t[capacity]; - if (stack_base != nullptr && new_stack_base != nullptr) { - memcpy(new_stack_base, stack_base, stack_offset * sizeof(evm_word_t)); - delete[] stack_base; - } - __ONE_GPU_THREAD_END__ - if (new_stack_base == nullptr) { - return ERROR_MEMORY_ALLOCATION_FAILED; +// TODO : reimplement +__host__ __device__ void evm_stack_t::extract_data(evm_word_t *other) const { + // printf("Extract data stack offset %d\n", stack_offset); + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + if (stack_offset + stack_base_offset < CuEVM::shared_stack_size) { + memcpy(other, shared_stack_base, stack_offset * sizeof(evm_word_t)); + } else { + int32_t left_over = CuEVM::shared_stack_size - stack_base_offset; + if (left_over > 0) { + memcpy(other, shared_stack_base, left_over * sizeof(evm_word_t)); + memcpy(other + left_over, global_stack_base, (stack_offset - left_over) * sizeof(evm_word_t)); + } else + memcpy(other, global_stack_base, stack_offset * sizeof(evm_word_t)); } - stack_base = new_stack_base; - return ERROR_SUCCESS; + // if (global_stack_base != nullptr) { + // memcpy(other, global_stack_base, stack_offset * sizeof(evm_word_t)); + // } + __ONE_GPU_THREAD_WOSYNC_END__ } +// __host__ __device__ int32_t evm_stack_t::grow() { +// // capacity = (capacity == 0) ? initial_capacity : capacity * 2; +// // if (capacity > max_size) { +// // return ERROR_STACK_OVERFLOW; +// // } +// if (stack_base_offset + stack_offset < CuEVM::shared_stack_size) { +// return ERROR_SUCCESS; +// } +// __SHARED_MEMORY__ evm_word_t *new_stack_base; +// __ONE_GPU_THREAD_BEGIN__ +// new_stack_base = new evm_word_t[capacity]; +// if (global_stack_base != nullptr && new_stack_base != nullptr) { +// memcpy(new_stack_base, global_stack_base, stack_offset * sizeof(evm_word_t)); +// delete[] global_stack_base; +// } +// __ONE_GPU_THREAD_END__ +// if (new_stack_base == nullptr) { +// return ERROR_MEMORY_ALLOCATION_FAILED; +// } +// global_stack_base = new_stack_base; +// return ERROR_SUCCESS; +// } + __host__ __device__ uint32_t evm_stack_t::size() const { return stack_offset; } -__host__ __device__ evm_word_t *evm_stack_t::top() { return stack_base + stack_offset; } +__host__ __device__ evm_word_t *evm_stack_t::top() { + if (stack_base_offset + stack_offset < CuEVM::shared_stack_size) { + // printf("shared stack base %p stack offset %d\n", shared_stack_base, stack_offset); + return shared_stack_base + stack_offset; + } else { + // page size is max stack size + if ((stack_base_offset + stack_offset - CuEVM::shared_stack_size) % max_stack_size == 0) { + __SHARED_MEMORY__ evm_word_t *new_stack_base[CGBN_IBP]; + // allocate one + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + new_stack_base[INSTANCE_IDX_PER_BLOCK] = new evm_word_t[max_stack_size]; + if (global_stack_base != nullptr) { + delete[] global_stack_base; + } + __ONE_GPU_THREAD_END__ + global_stack_base = new_stack_base[INSTANCE_IDX_PER_BLOCK]; + } + return global_stack_base + stack_base_offset + stack_offset - CuEVM::shared_stack_size; + } +} + +// __host__ __device__ int32_t evm_stack_t::push(ArithEnv &arith, const bn_t &value) { +// int32_t error_code = (size() >= CuEVM::shared_stack_size) ? grow() : ERROR_SUCCESS; +// if (error_code == ERROR_SUCCESS) { +// cgbn_store(arith.env, top(), value); +// stack_offset++; +// } +// return error_code; +// } __host__ __device__ int32_t evm_stack_t::push(ArithEnv &arith, const bn_t &value) { - int32_t error_code = (size() >= capacity) ? grow() : ERROR_SUCCESS; - if (error_code == ERROR_SUCCESS) { + if (stack_offset < max_stack_size) { cgbn_store(arith.env, top(), value); stack_offset++; + // printf("Stack offset %d pointer %p top %p\n", stack_offset, shared_stack_base, top()); + + return ERROR_SUCCESS; + } else { + return ERROR_STACK_OVERFLOW; } +} - return error_code; +__host__ __device__ int32_t evm_stack_t::push_evm_word_t(ArithEnv &arith, const evm_word_t *value) { + if (stack_offset < max_stack_size) { + *top() = *value; + stack_offset++; + // printf("Stack offset %d pointer %p top %p\n", stack_offset, shared_stack_base, top()); + + return ERROR_SUCCESS; + } else { + return ERROR_STACK_OVERFLOW; + } } __host__ __device__ int32_t evm_stack_t::pop(ArithEnv &arith, bn_t &y) { - if (size() == 0) { + if (stack_offset == 0) { // TODO: delete maybe? cgbn_set_ui32(arith.env, y, 0); return ERROR_STACK_UNDERFLOW; } + cgbn_load(arith.env, y, get_address_at_index(1)); stack_offset--; - cgbn_load(arith.env, y, top()); + // printf("Stack pop offset %d idx %d\n", stack_offset, THREADIDX); + // cgbn_load(arith.env, y, top()); return ERROR_SUCCESS; } +__host__ __device__ int32_t evm_stack_t::pop_evm_word(ArithEnv &arith, evm_word_t *&y) { + if (stack_offset == 0) { + return ERROR_STACK_UNDERFLOW; + } + y = get_address_at_index(1); + stack_offset--; + return ERROR_SUCCESS; +} + +#ifdef __CUDA_ARCH__ +__host__ __device__ int32_t evm_stack_t::pushx(ArithEnv &arith, uint8_t x, uint8_t *src_byte_data, + uint8_t src_byte_size) { + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // printf("pushx x %d data size %d thread_idx %d\n", x, src_byte_size, THREADIDX); + // for (uint8_t idx = 0; idx < src_byte_size; idx++) { + // printf("%02x", src_byte_data[idx]); + // } + // __ONE_GPU_THREAD_WOSYNC_END__ + + // int32_t error_code = (size() >= capacity) ? grow() : ERROR_SUCCESS; + if (stack_offset < max_stack_size) { + int last_idx_from_left = 31 - min(x, src_byte_size); + int my_idx = THREAD_IDX_PER_INSTANCE; + evm_word_t *top_ = top(); + + if (my_idx < CuEVM::cgbn_limbs) { + // each thead will insert 4 bytes/ hardcoded big endian for now + int byte_start = (my_idx + 1) * 4 - 1; + // printf("pushx data inserted %d myidx %d firstidxleft %d\n", THREADIDX, my_idx, last_idx_from_left); + // printf("%02x byte_start %d first idx %d\n", src_byte_data[src_byte_size - 1 - (31 - byte_start)], + // byte_start, last_idx_from_left); + uint32_t limb_value = 0; + if (byte_start > last_idx_from_left) { + // printf("byte_start %d last_idx_from_left %d THREADIDX %d value %02x\n", byte_start, + // last_idx_from_left, + // THREADIDX, src_byte_data[src_byte_size - 1 - (31 - byte_start)]); + + limb_value |= src_byte_data[src_byte_size - 1 - (31 - byte_start)]; //<< 24; + } + byte_start--; + if (byte_start > last_idx_from_left) { + limb_value |= src_byte_data[src_byte_size - 1 - (31 - byte_start)] << 8; // << 16; + } + byte_start--; + if (byte_start > last_idx_from_left) { + limb_value |= src_byte_data[src_byte_size - 1 - (31 - byte_start)] << 16; // << 8; + } + byte_start--; + if (byte_start > last_idx_from_left) { + // printf("bytestart %d src data idx %d thread idx %d, srcbyte %02x \n", byte_start, 31 - byte_start, + // threadIdx.x, src_byte_data[31 - byte_start]); + limb_value |= src_byte_data[src_byte_size - 1 - (31 - byte_start)] << 24; + } + // printf("limb value %08x THREADIDX %d store to top at %d\n", limb_value, THREADIDX, + // CuEVM::cgbn_limbs - my_idx - 1); + top_->_limbs[CuEVM::cgbn_limbs - my_idx - 1] = limb_value; + } + stack_offset++; + + // __SYNC_THREADS__ // do we need to sync here? + // __ONE_THREAD_PER_INSTANCE(printf("after pushx\n");); + // __SYNC_THREADS__ + // if (INSTANCE_IDX_PER_BLOCK == 1) { + // // printf("THREADIDX %d\n", THREADIDX); + // this->print(); + // } + return ERROR_SUCCESS; + } else { + printf("pushx overflow stack offset %d\n", stack_offset); + return ERROR_STACK_OVERFLOW; + } +} + +#else __host__ __device__ int32_t evm_stack_t::pushx(ArithEnv &arith, uint8_t x, uint8_t *src_byte_data, uint8_t src_byte_size) { // TODO:: for sure is something more efficient here @@ -112,12 +257,63 @@ __host__ __device__ int32_t evm_stack_t::pushx(ArithEnv &arith, uint8_t x, uint8 return push(arith, r); } +#endif +#ifdef __CUDA_ARCH__ +// The caller must check underflow +__host__ __device__ evm_word_t *evm_stack_t::get_address_at_index(uint32_t index) const { + // printf("global stack base %p shared stack base %p\n", global_stack_base, shared_stack_base); + if (stack_base_offset + stack_offset - index < CuEVM::shared_stack_size) // stack_offset is after added + return shared_stack_base + stack_offset - index; + else + return global_stack_base + stack_base_offset + stack_offset - index - CuEVM::shared_stack_size; +} + +__host__ __device__ int32_t evm_stack_t::dupx(ArithEnv &arith, uint32_t x) { + // if ((x > 16) || (x < 1)) return ERROR_STACK_INVALID_SIZE; + // for efficiency this must be checked from outside this func + + if ((stack_offset < max_stack_size) && (x <= stack_offset)) { + // cgbn_store(arith.env, top(), value); + *top() = *get_address_at_index(x); + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // // TODO: optimize memcpy + // memcpy(top(), get_address_at_index(x), sizeof(evm_word_t)); + // __ONE_GPU_THREAD_WOSYNC_END__ + stack_offset++; + return ERROR_SUCCESS; + } else { + printf(" dupx overflow or underflow stack offset %d\n", stack_offset); + return ERROR_STACK_OVERFLOW; // represent underflow also + }; +} + +__host__ __device__ int32_t evm_stack_t::swapx(ArithEnv &arith, uint32_t x) { + // if ((x > 16) || (x < 1)) return ERROR_STACK_INVALID_SIZE; + // for efficiency this must be checked from outside this func + + // cgbn_store(arith.env, global_stack_base + size() - x - 1, a); + // cgbn_store(arith.env, global_stack_base + size() - 1, b); + // __ONE_THREAD_PER_INSTANCE(printf("swapx %d x %d\n", THREADIDX, x);); + x++; + if (x > stack_offset) { + return ERROR_STACK_UNDERFLOW; + } + __SHARED_MEMORY__ evm_word_t tmp[CGBN_IBP]; + tmp[INSTANCE_IDX_PER_BLOCK] = *get_address_at_index(x); + *get_address_at_index(x) = *get_address_at_index(1); + *get_address_at_index(1) = tmp[INSTANCE_IDX_PER_BLOCK]; + + return ERROR_SUCCESS; +} + +#else +__host__ __device__ evm_word_t *evm_stack_t::get_address_at_index(uint32_t index) const {} __host__ __device__ int32_t evm_stack_t::get_index(ArithEnv &arith, uint32_t index, bn_t &y) { if (index > size()) { return ERROR_STACK_INVALID_INDEX; } - cgbn_load(arith.env, y, stack_base + size() - index); + cgbn_load(arith.env, y, global_stack_base + size() - index); return ERROR_SUCCESS; } @@ -132,17 +328,20 @@ __host__ __device__ int32_t evm_stack_t::swapx(ArithEnv &arith, uint32_t x) { int32_t error_code = ((x > 16) || (x < 1)) ? ERROR_STACK_INVALID_SIZE : (get_index(arith, 1, a) | get_index(arith, x + 1, b)); if (error_code == ERROR_SUCCESS) { - cgbn_store(arith.env, stack_base + size() - x - 1, a); - cgbn_store(arith.env, stack_base + size() - 1, b); + cgbn_store(arith.env, global_stack_base + size() - x - 1, a); + cgbn_store(arith.env, global_stack_base + size() - 1, b); } return error_code; } +#endif __host__ __device__ void evm_stack_t::print() { __ONE_GPU_THREAD_WOSYNC_BEGIN__ printf("Stack size: %d, data:\n", size()); - for (uint32_t idx = 0; idx < size(); idx++) { - stack_base[idx].print(); + for (uint32_t idx = 1; idx <= size(); idx++) { + evm_word_t *elem = get_address_at_index(idx); + printf("idx %d, elem %p\n", idx, elem); + elem->print(); } __ONE_GPU_THREAD_WOSYNC_END__ } @@ -152,7 +351,7 @@ __host__ cJSON *evm_stack_t::to_json() { char *hex_string_ptr = new char[CuEVM::word_size * 2 + 3]; cJSON *stack = cJSON_CreateArray(); for (uint32_t idx = 0; idx < size(); idx++) { - stack_base[idx].to_hex(hex_string_ptr); + global_stack_base[idx].to_hex(hex_string_ptr); cJSON_AddItemToArray(stack, cJSON_CreateString(hex_string_ptr)); } cJSON_AddItemToObject(json, "data", stack); @@ -164,17 +363,18 @@ __host__ evm_stack_t *evm_stack_t::get_cpu(uint32_t count) { return instances; } __host__ void evm_stack_t::cpu_free(evm_stack_t *instances, uint32_t count) { delete[] instances; } -__host__ evm_stack_t *evm_stack_t::gpu_from_cpu(evm_stack_t *cpu_instances, uint32_t count) { + +/*__host__ evm_stack_t *evm_stack_t::gpu_from_cpu(evm_stack_t *cpu_instances, uint32_t count) { evm_stack_t *gpu_instances, *tmp_gpu_instances; tmp_gpu_instances = new evm_stack_t[count]; for (uint32_t idx = 0; idx < count; idx++) { - if (cpu_instances[idx].stack_base != nullptr) { - CUDA_CHECK( - cudaMalloc(&tmp_gpu_instances[idx].stack_base, cpu_instances[idx].capacity * sizeof(evm_word_t))); - CUDA_CHECK(cudaMemcpy(tmp_gpu_instances[idx].stack_base, cpu_instances[idx].stack_base, + if (cpu_instances[idx].global_stack_base != nullptr) { + CUDA_CHECK(cudaMalloc(&tmp_gpu_instances[idx].global_stack_base, + cpu_instances[idx].capacity * sizeof(evm_word_t))); + CUDA_CHECK(cudaMemcpy(tmp_gpu_instances[idx].global_stack_base, cpu_instances[idx].global_stack_base, cpu_instances[idx].stack_offset * sizeof(evm_word_t), cudaMemcpyHostToDevice)); } else { - tmp_gpu_instances[idx].stack_base = nullptr; + tmp_gpu_instances[idx].global_stack_base = nullptr; } tmp_gpu_instances[idx].stack_offset = cpu_instances[idx].stack_offset; tmp_gpu_instances[idx].capacity = cpu_instances[idx].capacity; @@ -186,14 +386,13 @@ __host__ evm_stack_t *evm_stack_t::gpu_from_cpu(evm_stack_t *cpu_instances, uint } delete[] tmp_gpu_instances; return gpu_instances; -} +}*/ __host__ void evm_stack_t::gpu_free(evm_stack_t *gpu_instances, uint32_t count) { evm_stack_t *tmp_gpu_instances = new evm_stack_t[count]; CUDA_CHECK(cudaMemcpy(tmp_gpu_instances, gpu_instances, count * sizeof(evm_stack_t), cudaMemcpyDeviceToHost)); for (uint32_t idx = 0; idx < count; idx++) { - if (tmp_gpu_instances[idx].stack_base != nullptr && tmp_gpu_instances[idx].capacity > 0 && - tmp_gpu_instances[idx].stack_offset > 0) { - CUDA_CHECK(cudaFree(tmp_gpu_instances[idx].stack_base)); + if (tmp_gpu_instances[idx].global_stack_base != nullptr && tmp_gpu_instances[idx].stack_offset > 0) { + CUDA_CHECK(cudaFree(tmp_gpu_instances[idx].global_stack_base)); } tmp_gpu_instances[idx].clear(); } @@ -201,62 +400,4 @@ __host__ void evm_stack_t::gpu_free(evm_stack_t *gpu_instances, uint32_t count) CUDA_CHECK(cudaFree(gpu_instances)); } -__host__ evm_stack_t *evm_stack_t::cpu_from_gpu(evm_stack_t *gpu_instances, uint32_t count) { - evm_stack_t *cpu_instances = new evm_stack_t[count]; - evm_stack_t *tmp_gpu_instances = new evm_stack_t[count]; - evm_stack_t *tmp_cpu_instances = new evm_stack_t[count]; - CUDA_CHECK(cudaMemcpy(cpu_instances, gpu_instances, count * sizeof(evm_stack_t), cudaMemcpyDeviceToHost)); - for (uint32_t idx = 0; idx < count; idx++) { - if (cpu_instances[idx].stack_offset > 0) { - CUDA_CHECK( - cudaMalloc(&tmp_cpu_instances[idx].stack_base, cpu_instances[idx].stack_offset * sizeof(evm_word_t))); - } else { - tmp_cpu_instances[idx].stack_base = nullptr; - } - tmp_cpu_instances[idx].stack_offset = cpu_instances[idx].stack_offset; - tmp_cpu_instances[idx].capacity = cpu_instances[idx].stack_offset; - } - CUDA_CHECK(cudaMalloc(&tmp_gpu_instances, count * sizeof(evm_stack_t))); - CUDA_CHECK(cudaMemcpy(tmp_gpu_instances, tmp_cpu_instances, count * sizeof(evm_stack_t), cudaMemcpyHostToDevice)); - for (uint32_t idx = 0; idx < count; idx++) { - tmp_cpu_instances[idx].clear(); - cpu_instances[idx].clear(); - } - transfer_kernel_evm_stack_t<<>>(tmp_gpu_instances, gpu_instances, count); - CUDA_CHECK(cudaDeviceSynchronize()); - CUDA_CHECK(cudaFree(gpu_instances)); - - CUDA_CHECK(cudaMemcpy(tmp_cpu_instances, tmp_gpu_instances, sizeof(evm_stack_t) * count, cudaMemcpyDeviceToHost)); - - for (uint32_t idx = 0; idx < count; idx++) { - if (tmp_cpu_instances[idx].stack_offset > 0) { - cpu_instances[idx].stack_base = new evm_word_t[tmp_cpu_instances[idx].stack_offset]; - CUDA_CHECK(cudaMemcpy(cpu_instances[idx].stack_base, tmp_cpu_instances[idx].stack_base, - sizeof(evm_word_t) * tmp_cpu_instances[idx].stack_offset, cudaMemcpyDeviceToHost)); - } else { - cpu_instances[idx].stack_base = NULL; - } - cpu_instances[idx].stack_offset = tmp_cpu_instances[idx].stack_offset; - cpu_instances[idx].capacity = tmp_cpu_instances[idx].stack_offset; - } - for (uint32_t idx = 0; idx < count; idx++) { - tmp_cpu_instances[idx].clear(); - } - delete[] tmp_cpu_instances; - evm_stack_t::gpu_free(tmp_gpu_instances, count); - return cpu_instances; -} - -__global__ void transfer_kernel_evm_stack_t(evm_stack_t *dst, evm_stack_t *src, uint32_t count) { - uint32_t instance = blockIdx.x * blockDim.x + threadIdx.x; - if (instance >= count) { - return; - } - dst[instance].stack_offset = src[instance].stack_offset; - dst[instance].capacity = src[instance].stack_offset; - memcpy(dst[instance].stack_base, src[instance].stack_base, src[instance].stack_offset * sizeof(evm_word_t)); - delete[] src[instance].stack_base; - src[instance].clear(); -} - } // namespace CuEVM::stack \ No newline at end of file diff --git a/CuEVM/src/core/transaction.cu b/CuEVM/src/core/transaction.cu index 8d01e08..dd0e75e 100644 --- a/CuEVM/src/core/transaction.cu +++ b/CuEVM/src/core/transaction.cu @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -29,9 +30,7 @@ __host__ int32_t access_list_account_t::from_json(const cJSON *json, int32_t man if (address_json == NULL) { return ERROR_FAILED; } - if (!address.from_hex(address_json->valuestring)) { - return ERROR_FAILED; - } + address.from_hex(address_json->valuestring); cJSON *storage_keys_json = cJSON_GetObjectItemCaseSensitive(json, "storageKeys"); if (storage_keys_json == NULL) { storage_keys_count = 0; @@ -199,23 +198,24 @@ __host__ __device__ int32_t evm_transaction_t::get_transaction_fees(ArithEnv &ar } __host__ __device__ int32_t evm_transaction_t::access_list_warm_up(ArithEnv &arith, - CuEVM::TouchState &touch_state) const { + CuEVM::TouchState *touch_state_ptr) const { for (uint32_t i = 0; i < access_list.accounts_count; i++) { - bn_t address; - cgbn_load(arith.env, address, (cgbn_evm_word_t_ptr) & (access_list.accounts[i].address)); + // bn_t address; + // cgbn_load(arith.env, address, (cgbn_evm_word_t_ptr) & (access_list.accounts[i].address)); CuEVM::account_t *account_ptr = nullptr; - touch_state.set_warm_account(arith, address); + touch_state_ptr->set_warm_account(arith, &(access_list.accounts[i].address)); for (uint32_t j = 0; j < access_list.accounts[i].storage_keys_count; j++) { bn_t key; cgbn_load(arith.env, key, (cgbn_evm_word_t_ptr) & (access_list.accounts[i].storage_keys[j])); bn_t value; - touch_state.set_warm_key(arith, address, key, value); + cgbn_set_ui32(arith.env, value, 0); + touch_state_ptr->set_warm_key(arith, &(access_list.accounts[i].address), key, value); } } return ERROR_SUCCESS; } -__host__ __device__ int32_t evm_transaction_t::validate(ArithEnv &arith, CuEVM::TouchState &touch_state, +__host__ __device__ int32_t evm_transaction_t::validate(ArithEnv &arith, CuEVM::TouchState *touch_state_ptr, CuEVM::block_info_t &block_info, bn_t &gas_used, bn_t &gas_price, bn_t &gas_priority_fee) const { // printf("begin validating transaction\n"); @@ -237,12 +237,15 @@ __host__ __device__ int32_t evm_transaction_t::validate(ArithEnv &arith, CuEVM:: if (error_code) { return error_code; } - bn_t sender_address; - get_sender(arith, sender_address); + // bn_t sender_address; + // get_sender(arith, sender_address); // printf("after get_sender\n"); + // __ONE_THREAD_PER_INSTANCE(printf("sender address\n");); + // this->sender.print(); + CuEVM::account_t *sender_account = nullptr; - touch_state.get_account(arith, sender_address, sender_account, - ACCOUNT_BALANCE_FLAG | ACCOUNT_NONCE_FLAG | ACCOUNT_BYTE_CODE_FLAG); + touch_state_ptr->get_account(arith, &this->sender, sender_account, + ACCOUNT_BALANCE_FLAG | ACCOUNT_NONCE_FLAG | ACCOUNT_BYTE_CODE_FLAG); bn_t sender_balance; sender_account->get_balance(arith, sender_balance); @@ -297,11 +300,11 @@ __host__ __device__ int32_t evm_transaction_t::validate(ArithEnv &arith, CuEVM:: // if transaction is valid update the touch state // \f$\simga(T_{s})_{b} = \simga(T_{s})_{b} - (p \dot T_{g})\f$ cgbn_sub(arith.env, sender_balance, sender_balance, gas_value); - touch_state.set_balance(arith, sender_address, sender_balance); + touch_state_ptr->set_balance(arith, &this->sender, sender_balance); // printf("after set balance account\n"); // \f$\simga(T_{s})_{n} = T_{n} + 1\f$ cgbn_add_ui32(arith.env, sender_nonce, sender_nonce, 1); - touch_state.set_nonce(arith, sender_address, sender_nonce); + touch_state_ptr->set_nonce(arith, &this->sender, sender_nonce); // set the gas used to the intrisinc gas cgbn_set(arith.env, gas_used, gas_intrinsic); // TODO: maybe sent the priority fee to the miner @@ -309,25 +312,18 @@ __host__ __device__ int32_t evm_transaction_t::validate(ArithEnv &arith, CuEVM:: // by asking the balacne of the coinbase accountq // printf("after set nonce account\n"); // warm up the access list - access_list_warm_up(arith, touch_state); + access_list_warm_up(arith, touch_state_ptr); // printf("after warm up account\n"); // warmup coinbase and precompile contracts #ifdef EIP_3651 - bn_t coin_base_address; - block_info.get_coin_base(arith, coin_base_address); + // bn_t coin_base_address; + // block_info.get_coin_base(arith, coin_base_address); - touch_state.set_warm_account(arith, coin_base_address); + touch_state_ptr->set_warm_account(arith, &block_info.coin_base); #endif - // printf("after warm up coinbase\n"); - bn_t precompile_contract_address; -#pragma unroll - for (uint32_t idx = 1; idx < CuEVM::no_precompile_contracts; idx++) { - cgbn_set_ui32(arith.env, precompile_contract_address, idx); - touch_state.set_warm_account(arith, precompile_contract_address); - } - // printf("end validating transaction\n"); + return ERROR_SUCCESS; } @@ -338,19 +334,24 @@ __host__ __device__ int32_t evm_transaction_t::validate(ArithEnv &arith, CuEVM:: * @param[out] evm_message_call_ptr the message call. * @return 1 for success, 0 for failure. */ -__host__ __device__ int32_t evm_transaction_t::get_message_call( - ArithEnv &arith, CuEVM::TouchState &touch_state, CuEVM::evm_message_call_t *&evm_message_call_ptr) const { - bn_t sender_address, to_address, value, gas_limit; - get_sender(arith, sender_address); - get_to(arith, to_address); - get_value(arith, value); - get_gas_limit(arith, gas_limit); +__host__ __device__ int32_t +evm_transaction_t::get_message_call(ArithEnv &arith, CuEVM::TouchState *touch_state_ptr, + CuEVM::evm_message_call_t_shadow *&evm_message_call_ptr) const { + // bn_t sender_address, to_address, value, gas_limit; + // get_sender(arith, sender_address); + // printf("evm_transaction_t::get_message_call sender address\n"); + // this->sender.print(); + // get_to(arith, to_address); + // printf("to address\n"); + // this->to.print(); + // get_value(arith, value); + // get_gas_limit(arith, gas_limit); uint32_t depth = 0; uint32_t call_type = OP_CALL; CuEVM::byte_array_t byte_code; // if is a contract creation CuEVM::account_t *to_account = nullptr; - touch_state.get_account(arith, to_address, to_account, ACCOUNT_BYTE_CODE_FLAG); + touch_state_ptr->get_account(arith, &this->to, to_account, ACCOUNT_BYTE_CODE_FLAG); uint32_t static_env = 0; bn_t return_data_offset; cgbn_set_ui32(arith.env, return_data_offset, 0); @@ -359,15 +360,20 @@ __host__ __device__ int32_t evm_transaction_t::get_message_call( if (is_create) { call_type = OP_CREATE; byte_code = data_init; + // bn_t sender_nonce, sender_address, contract_address; + // touch_state_ptr->get_nonce(arith, &this->sender, sender_nonce); + // cgbn_load(arith.env, sender_address, (cgbn_evm_word_t_ptr) & (this->sender)); + // CuEVM::utils::get_contract_address_create(arith, contract_address, sender_address, sender_nonce); + // cgbn_store(arith.env, (cgbn_evm_word_t_ptr) & (this->to), contract_address); // blank call data in create - evm_message_call_ptr = new CuEVM::evm_message_call_t( - arith, sender_address, to_address, to_address, gas_limit, value, depth, call_type, to_address, + evm_message_call_ptr = new CuEVM::evm_message_call_t_shadow( + arith, &this->sender, &this->to, &this->to, &this->gas_limit, &this->value, depth, call_type, &this->to, CuEVM::byte_array_t(), byte_code, return_data_offset, return_data_size, static_env); -#ifdef __CUDA_ARCH__ - printf("CREATE to_account %p init code size %d account code size %d idx %d \n", to_account, - to_account->byte_code.size, byte_code.size, threadIdx.x); + + __ONE_THREAD_PER_INSTANCE(printf("CREATE to_account %p init code size %d account code size %d idx %d \n", + to_account, to_account->byte_code.size, byte_code.size, THREADIDX);); to_account->address.print(); -#endif + } else { // CuEVM::account_t *to_account = nullptr; // touch_state.get_account(arith, to_address, to_account, ACCOUNT_BYTE_CODE_FLAG); @@ -375,14 +381,15 @@ __host__ __device__ int32_t evm_transaction_t::get_message_call( // printf("to_account %p size %d idx %d \n", to_account, to_account->byte_code.size , threadIdx.x); // #endif byte_code = to_account->byte_code; - evm_message_call_ptr = new CuEVM::evm_message_call_t(arith, sender_address, to_address, to_address, gas_limit, - value, depth, call_type, to_address, data_init, byte_code, - return_data_offset, return_data_size, static_env); + evm_message_call_ptr = new CuEVM::evm_message_call_t_shadow( + arith, &this->sender, &this->to, &this->to, &this->gas_limit, &this->value, depth, call_type, &this->to, + data_init, byte_code, return_data_offset, return_data_size, static_env); } // #ifdef __CUDA_ARCH__ - // printf("bytecode size %d idx %d \n", byte_code.size , threadIdx.x); + // printf("bytecode size %d idx %d \n", byte_code.size, threadIdx.x); // #endif + return ERROR_SUCCESS; } @@ -499,7 +506,7 @@ __host__ int32_t get_transactions(ArithEnv &arith, evm_transaction_t *&transacti } evm_transaction_t *template_transaction_ptr = new evm_transaction_t(); - uint32_t data_idnex, gas_limit_index, value_index, idx; + uint32_t data_index, gas_limit_index, value_index, access_list_index, idx; uint32_t type = 0; @@ -515,14 +522,15 @@ __host__ int32_t get_transactions(ArithEnv &arith, evm_transaction_t *&transacti const cJSON *to_json = cJSON_GetObjectItemCaseSensitive(transaction_json, "to"); // verify what is happening from strlen 0 if (strlen(to_json->valuestring) == 0) { + // printf(" CREATE when loading json\n"); CuEVM::account_t *sender_account = nullptr; - bn_t sender, contract_address; - cgbn_load(arith.env, sender, &template_transaction_ptr->sender); - world_state_ptr->get_account(arith, sender, sender_account); - bn_t sender_nonce; - cgbn_load(arith.env, sender_nonce, &sender_account->nonce); - CuEVM::utils::get_contract_address_create(arith, contract_address, sender, sender_nonce); - cgbn_store(arith.env, &template_transaction_ptr->to, contract_address); + + world_state_ptr->get_account(arith, &template_transaction_ptr->sender, sender_account); + + CuEVM::utils::get_contract_address_create_word(arith, &template_transaction_ptr->to, + &template_transaction_ptr->sender, &sender_account->nonce); + // printf("contract address\n"); + // template_transaction_ptr->to.print(); template_transaction_ptr->is_create = true; } else { template_transaction_ptr->to.from_hex(to_json->valuestring); @@ -531,10 +539,9 @@ __host__ int32_t get_transactions(ArithEnv &arith, evm_transaction_t *&transacti const cJSON *value_json = cJSON_GetObjectItemCaseSensitive(transaction_json, "value"); uint32_t value_counts = cJSON_GetArraySize(value_json); - const cJSON *access_list_json = cJSON_GetObjectItemCaseSensitive(transaction_json, "accessList"); - if (access_list_json != nullptr) { - template_transaction_ptr->access_list.from_json(access_list_json, managed); - } + uint32_t access_list_counts = 0; + const cJSON *access_list_json = cJSON_GetObjectItem(transaction_json, "accessLists"); + if (access_list_json != nullptr) access_list_counts = cJSON_GetArraySize(access_list_json); const cJSON *max_fee_per_gas_json = cJSON_GetObjectItemCaseSensitive(transaction_json, "maxFeePerGas"); @@ -571,11 +578,17 @@ __host__ int32_t get_transactions(ArithEnv &arith, evm_transaction_t *&transacti uint32_t index; for (idx = 0; idx < transactions_count; idx++) { index = (start_index + idx) % original_count; - data_idnex = index % data_counts; + data_index = index % data_counts; + if (access_list_counts > 0) { + access_list_index = data_index % access_list_counts; // TODO: check if this is correct + template_transaction_ptr->access_list.from_json(cJSON_GetArrayItem(access_list_json, access_list_index), + managed); + } gas_limit_index = (index / data_counts) % gas_limit_counts; value_index = (index / (data_counts * gas_limit_counts)) % value_counts; - std::copy(template_transaction_ptr, template_transaction_ptr + 1, transactions_ptr + idx); - transactions_ptr[idx].data_init.from_hex(cJSON_GetArrayItem(data_json, data_idnex)->valuestring, LITTLE_ENDIAN, + // std::copy(template_transaction_ptr, template_transaction_ptr + 1, transactions_ptr + idx); + memcpy(&transactions_ptr[idx], template_transaction_ptr, sizeof(evm_transaction_t)); + transactions_ptr[idx].data_init.from_hex(cJSON_GetArrayItem(data_json, data_index)->valuestring, LITTLE_ENDIAN, CuEVM::PaddingDirection::NO_PADDING, managed); transactions_ptr[idx].gas_limit.from_hex(cJSON_GetArrayItem(gas_limit_json, gas_limit_index)->valuestring); // better refactorign the boundary checks diff --git a/CuEVM/src/evm.cu b/CuEVM/src/evm.cu index 3024830..d23fcc4 100644 --- a/CuEVM/src/evm.cu +++ b/CuEVM/src/evm.cu @@ -18,38 +18,103 @@ #include namespace CuEVM { + +// define the kernel function +__global__ void kernel_evm_multiple_instances(cgbn_error_report_t *report, CuEVM::evm_instance_t *instances, + uint32_t count) { + int32_t instance = (blockIdx.x * blockDim.x + threadIdx.x) / CuEVM::cgbn_tpi; + if (instance >= count) return; + CuEVM::ArithEnv arith(cgbn_no_checks, report, instance); + // CuEVM::bn_t test; + // printf("print simplified trace data device\n"); + // instances[instance].simplified_trace_data_ptr->print(); +// printf("new instance %d\n", instance); +#ifdef EIP_3155 + // if (instance == 0) { + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // printf("instance %d\n", instance); + // printf("world state\n"); + // instances[instance].world_state_data_ptr->print(); + // printf("touch state\n"); + // instances[instance].touch_state_data_ptr->print(); + // printf("instance %d\n", instance); + // printf("transaction\n"); + // instances[instance].transaction_ptr->print(); + // __ONE_GPU_THREAD_WOSYNC_END__ + // } +#endif + + __SHARED_MEMORY__ CuEVM::evm_message_call_t shared_message_call[CGBN_IBP]; + __SHARED_MEMORY__ CuEVM::evm_word_t shared_stack[CGBN_IBP][CuEVM::shared_stack_size]; + CuEVM::evm_t *evm = new CuEVM::evm_t(arith, instances[instance], &shared_message_call[INSTANCE_IDX_PER_BLOCK], + shared_stack[INSTANCE_IDX_PER_BLOCK]); + + if (evm->status == ERROR_SUCCESS) { + CuEVM::cached_evm_call_state cached_state(arith, evm->call_state_ptr); + + __SYNC_THREADS__ + evm->run(arith, cached_state); + +#ifdef EIP_3155 + if (instance == 0) { + __ONE_GPU_THREAD_BEGIN__ + // instances[0].tracer_ptr->print(arith); + instances[0].tracer_ptr->print_err(); + __ONE_GPU_THREAD_WOSYNC_END__ + } +#endif + } +} + __host__ __device__ evm_t::evm_t(ArithEnv &arith, CuEVM::state_t *world_state_data_ptr, CuEVM::block_info_t *block_info_ptr, CuEVM::evm_transaction_t *transaction_ptr, CuEVM::state_access_t *touch_state_data_ptr, CuEVM::log_state_data_t *log_state_ptr, - CuEVM::evm_return_data_t *return_data_ptr, CuEVM::EccConstants *ecc_constants_ptr + CuEVM::evm_return_data_t *return_data_ptr, CuEVM::EccConstants *ecc_constants_ptr, + CuEVM::evm_message_call_t *shared_message_call_ptr, CuEVM::evm_word_t *shared_stack_ptr #ifdef EIP_3155 , CuEVM::utils::tracer_t *tracer_ptr #endif - ) + + , + CuEVM::serialized_worldstate_data *serialized_worldstate_data_ptr, + CuEVM::utils::simplified_trace_data *simplified_trace_data_ptr) : world_state(world_state_data_ptr), block_info_ptr(block_info_ptr), transaction_ptr(transaction_ptr), + + serialized_worldstate_data_ptr(serialized_worldstate_data_ptr), + simplified_trace_data_ptr(simplified_trace_data_ptr), ecc_constants_ptr(ecc_constants_ptr) { + // TODO: store in local/shared memory call_state_ptr = new CuEVM::evm_call_state_t(arith, &world_state, nullptr, nullptr, log_state_ptr, touch_state_data_ptr, return_data_ptr); -#ifdef EIP_3155 - // printing debug when enabling tracer. - printf("call_state_ptr allocated\n"); - transaction_ptr->print(); -#endif - int32_t error_code = transaction_ptr->validate(arith, call_state_ptr->touch_state, *block_info_ptr, + // call_state_local = evm_call_steate_t(arith, call_state_ptr); + // #ifndef __CUDA_ARCH__ + // shared_message_call_ptr = new evm_message_call_t(); + // #endif + + int32_t error_code = transaction_ptr->validate(arith, call_state_ptr->touch_state_ptr, *block_info_ptr, call_state_ptr->gas_used, gas_price, gas_priority_fee); - // printf("transaction validated\n"); + // printf("transaction validated error code %d\n", error_code); // #ifdef __CUDA_ARCH__ // printf("error code %d idx %d \n", error_code, threadIdx.x); // #endif + // __SHARED_MEMORY__ evm_message_call_t shared_message_call; if (error_code == ERROR_SUCCESS) { - CuEVM::evm_message_call_t *transaction_call_message_ptr = nullptr; + CuEVM::evm_message_call_t_shadow *transaction_call_message_ptr = nullptr; error_code = - transaction_ptr->get_message_call(arith, call_state_ptr->touch_state, transaction_call_message_ptr); - CuEVM::evm_call_state_t *child_call_state_ptr = - new CuEVM::evm_call_state_t(arith, call_state_ptr, transaction_call_message_ptr); + transaction_ptr->get_message_call(arith, call_state_ptr->touch_state_ptr, transaction_call_message_ptr); + + shared_message_call_ptr->copy_from(transaction_call_message_ptr); + + // printf("\n\n message call copied %d\n", THREADIDX); + // shared_message_call_ptr->print(); + + CuEVM::evm_call_state_t *child_call_state_ptr = new CuEVM::evm_call_state_t( + arith, call_state_ptr, shared_message_call_ptr, transaction_call_message_ptr, shared_stack_ptr); + // printf("child_call_state_ptr allocated %p, threadid %d\n", child_call_state_ptr, THREADIDX); + // print_bnt(arith, child_call_state_ptr->gas_limit); // subtract the gas used by the transaction initialization from the gas // limit cgbn_sub(arith.env, child_call_state_ptr->gas_limit, child_call_state_ptr->gas_limit, call_state_ptr->gas_used); @@ -61,22 +126,25 @@ __host__ __device__ evm_t::evm_t(ArithEnv &arith, CuEVM::state_t *world_state_da status = error_code; } -__host__ __device__ evm_t::evm_t(ArithEnv &arith, CuEVM::evm_instance_t &evm_instance) +__host__ __device__ evm_t::evm_t(ArithEnv &arith, CuEVM::evm_instance_t &evm_instance, + CuEVM::evm_message_call_t *message_call, CuEVM::evm_word_t *shared_stack_ptr) : evm_t(arith, evm_instance.world_state_data_ptr, evm_instance.block_info_ptr, evm_instance.transaction_ptr, evm_instance.touch_state_data_ptr, evm_instance.log_state_ptr, evm_instance.return_data_ptr, - evm_instance.ecc_constants_ptr + evm_instance.ecc_constants_ptr, message_call, shared_stack_ptr #ifdef EIP_3155 , evm_instance.tracer_ptr #endif - ) { + , + evm_instance.serialized_worldstate_data_ptr, evm_instance.simplified_trace_data_ptr) { } __host__ __device__ evm_t::~evm_t() { - if (call_state_ptr != nullptr) { - call_state_ptr->touch_state.clear(); - delete call_state_ptr; - } + // if (call_state_ptr != nullptr) { + // call_state_ptr->touch_state.clear(); + // delete call_state_ptr; + // } + /// Todo double check touch_state_ptr call_state_ptr = nullptr; block_info_ptr = nullptr; transaction_ptr = nullptr; @@ -85,54 +153,67 @@ __host__ __device__ evm_t::~evm_t() { #endif } -__host__ __device__ int32_t evm_t::start_CALL(ArithEnv &arith) { - bn_t sender, recipient, value; - call_state_ptr->message_ptr->get_sender(arith, sender); - call_state_ptr->message_ptr->get_recipient(arith, recipient); +__host__ __device__ int32_t evm_t::start_CALL(ArithEnv &arith, cached_evm_call_state &cached_call_state) { + // printf("Start call sender receipient contract address %d\n", THREADIDX); + // call_state_ptr->message_ptr->sender.print(); + // call_state_ptr->message_ptr->recipient.print(); + // call_state_ptr->message_ptr->contract_address.print(); + bn_t value; + const evm_word_t *sender = &call_state_ptr->message_ptr->sender; + const evm_word_t *recipient = &call_state_ptr->message_ptr->recipient; call_state_ptr->message_ptr->get_value(arith, value); int32_t error_code = (((cgbn_compare_ui32(arith.env, value, 0) > 0) && // (cgbn_compare(arith.env, sender, recipient) != 0) && (call_state_ptr->message_ptr->call_type != OP_DELEGATECALL)) - ? call_state_ptr->touch_state.transfer(arith, sender, recipient, value) + ? call_state_ptr->touch_state_ptr->transfer(arith, sender, recipient, value) : ERROR_SUCCESS); if (error_code != ERROR_SUCCESS) { // avoid complication in the subsequent code // call failed = account never warmed up return error_code; } -#ifdef EIP_3155 -#ifdef __CUDA_ARCH__ - printf("start_CALL transfer error code %d idx %d \n", error_code, threadIdx.x); - __ONE_THREAD_PER_INSTANCE(printf("value ");) - print_bnt(arith, value); -#endif -#endif if (call_state_ptr->message_ptr->call_type == OP_CALL || call_state_ptr->message_ptr->call_type == OP_CALLCODE || call_state_ptr->message_ptr->call_type == OP_DELEGATECALL || call_state_ptr->message_ptr->call_type == OP_STATICCALL) { CuEVM::account_t *contract = nullptr; - bn_t contract_address; - call_state_ptr->message_ptr->get_contract_address(arith, contract_address); + const evm_word_t *contract_address = &call_state_ptr->message_ptr->contract_address; + // call_state_ptr->message_ptr->get_contract_address(arith, contract_address); // error_code |= - call_state_ptr->touch_state.get_account(arith, contract_address, contract, ACCOUNT_BYTE_CODE_FLAG); + // #ifdef __CUDA_ARCH__ + // printf("get byte code idx %d contract_address %p \n", threadIdx.x, contract_address); + // contract_address->print(); + // #endif + call_state_ptr->touch_state_ptr->get_account(arith, contract_address, contract, ACCOUNT_BYTE_CODE_FLAG); + // #ifdef __CUDA_ARCH__ + // printf("call_state_ptr->touch_state.get_account idx %d \n", threadIdx.x); + // contract_address->print(); + // contract->byte_code.print(); + // #endif call_state_ptr->message_ptr->set_byte_code(contract->byte_code); + // #ifdef __CUDA_ARCH__ + // printf("call_state_ptr->message_ptr->set_byte_code %d \n", threadIdx.x); + // contract_address->print(); + // #endif } + // #ifdef __CUDA_ARCH__ + // printf("before warmup sender %p recipient %p idx %d\n", sender, recipient, threadIdx.x); + // #endif // warmup the accounts CuEVM::account_t *account_ptr = nullptr; - call_state_ptr->touch_state.set_warm_account(arith, sender); - call_state_ptr->touch_state.set_warm_account(arith, recipient); - + call_state_ptr->touch_state_ptr->set_warm_account(arith, sender); + // #ifdef __CUDA_ARCH__ + // printf("after set_warm_account first %d\n", threadIdx.x); + // #endif + call_state_ptr->touch_state_ptr->set_warm_account(arith, recipient); + // #ifdef __CUDA_ARCH__ + // printf("after set_warm_account %d\n", threadIdx.x); + // #endif // error_code |= - call_state_ptr->touch_state.get_account(arith, recipient, account_ptr, ACCOUNT_NONE_FLAG); -#ifdef EIP_3155 -#ifdef __CUDA_ARCH__ - printf("call_state_ptr->touch_state.get_account error code %d, idx %d pointer %p, balance\n", error_code, - threadIdx.x, account_ptr); - account_ptr->balance.print(); -#endif -#endif + call_state_ptr->touch_state_ptr->get_account(arith, recipient, account_ptr, ACCOUNT_NONE_FLAG); + + cached_call_state.set_byte_code(call_state_ptr->message_ptr->byte_code); if ((call_state_ptr->message_ptr->call_type == OP_CREATE) || (call_state_ptr->message_ptr->call_type == OP_CREATE2)) { @@ -140,16 +221,16 @@ __host__ __device__ int32_t evm_t::start_CALL(ArithEnv &arith) { // printf("start_CALL contract ERROR_MESSAGE_CALL_CREATE_CONTRACT_EXISTS\n"); bn_t contract_nonce; cgbn_set_ui32(arith.env, contract_nonce, 1); - error_code |= call_state_ptr->touch_state.set_nonce(arith, recipient, contract_nonce); + error_code |= call_state_ptr->touch_state_ptr->set_nonce(arith, recipient, contract_nonce); bn_t sender_nonce; - error_code |= call_state_ptr->touch_state.get_nonce(arith, sender, sender_nonce); + error_code |= call_state_ptr->touch_state_ptr->get_nonce(arith, sender, sender_nonce); uint64_t nonce; error_code |= cgbn_get_uint64_t(arith.env, nonce, sender_nonce) == ERROR_VALUE_OVERFLOW ? ERROR_MESSAGE_CALL_CREATE_NONCE_EXCEEDED : ERROR_SUCCESS; cgbn_add_ui32(arith.env, sender_nonce, sender_nonce, 1); - + error_code |= call_state_ptr->touch_state_ptr->set_nonce(arith, sender, sender_nonce); } else { // Go-ethereum: check depth > 1024 before increase // -> depth > 1025 after increase @@ -159,7 +240,7 @@ __host__ __device__ int32_t evm_t::start_CALL(ArithEnv &arith) { // printf("else code size 0 code %d idx %d \n", error_code, threadIdx.x); // #endif // Dont use account ptr here, byte_code already set - if (call_state_ptr->message_ptr->byte_code.size == 0) { + if (call_state_ptr->message_ptr->byte_code->size == 0) { bn_t contract_address; call_state_ptr->message_ptr->get_contract_address(arith, contract_address); if (cgbn_compare_ui32(arith.env, contract_address, CuEVM::no_precompile_contracts) == -1) { @@ -167,40 +248,40 @@ __host__ __device__ int32_t evm_t::start_CALL(ArithEnv &arith) { case 0x01: return CuEVM::precompile_operations::operation_ecRecover( - arith, this->ecc_constants_ptr, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, this->ecc_constants_ptr, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); break; case 0x02: return CuEVM::precompile_operations::operation_SHA256( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); case 0x03: return CuEVM::precompile_operations::operation_RIPEMD160( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); case 0x04: return CuEVM::precompile_operations::operation_IDENTITY( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); case 0x05: return CuEVM::precompile_operations::operation_MODEXP( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); case 0x06: return CuEVM::precompile_operations::operation_ecAdd( - arith, this->ecc_constants_ptr, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, this->ecc_constants_ptr, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); case 0x07: return CuEVM::precompile_operations::operation_ecMul( - arith, this->ecc_constants_ptr, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, this->ecc_constants_ptr, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); case 0x08: return CuEVM::precompile_operations::operation_ecPairing( - arith, this->ecc_constants_ptr, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, this->ecc_constants_ptr, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); case 0x09: return CuEVM::precompile_operations::operation_BLAKE2( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, + arith, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->parent->last_return_data_ptr, call_state_ptr->message_ptr); case 0x0a: return ERROR_RETURN; @@ -211,29 +292,49 @@ __host__ __device__ int32_t evm_t::start_CALL(ArithEnv &arith) { } else { // operation stop // clear return data - call_state_ptr->parent->last_return_data_ptr->free(); - call_state_ptr->parent->last_return_data_ptr = new CuEVM::evm_return_data_t(); + // call_state_ptr->parent->last_return_data_ptr->free(); + // call_state_ptr->parent->last_return_data_ptr = new CuEVM::evm_return_data_t(); + CuEVM::byte_array_t::reset_return_data(call_state_ptr->parent->last_return_data_ptr); return ERROR_RETURN; } } } - + // #ifdef __CUDA_ARCH__ + // printf("start_CALL end error code %d idx %d\n", error_code, threadIdx.x); + // #endif return error_code; } - __host__ __device__ void evm_t::run(ArithEnv &arith) { + cached_evm_call_state cached_call_state(arith, call_state_ptr); + run(arith, cached_call_state); +} + +__host__ __device__ void evm_t::run(ArithEnv &arith, cached_evm_call_state &cached_call_state) { if (status != ERROR_SUCCESS) { return; // finish transaction } - int32_t error_code = start_CALL(arith); +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->start_call(0, call_state_ptr->message_ptr); +#endif + int32_t error_code = start_CALL(arith, cached_call_state); if (error_code != ERROR_SUCCESS) { +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->finish_call(0); +#endif return; // finish call } uint8_t opcode; +#ifdef BUILD_LIBRARY + uint32_t pc_src; +#endif CuEVM::evm_call_state_t *child_call_state_ptr = nullptr; - while (status == ERROR_SUCCESS) { - opcode = ((call_state_ptr->pc < ((call_state_ptr->message_ptr)->byte_code).size) - ? (call_state_ptr->message_ptr)->byte_code.data[call_state_ptr->pc] + while (true) { + // uint32_t current_pc = call_state_ptr->pc; // TODO: store in local/shared memory + // opcode = ((current_pc < ((call_state_ptr->message_ptr)->byte_code)->size) + // ? (call_state_ptr->message_ptr)->byte_code->data[current_pc] + // : OP_STOP); + opcode = ((cached_call_state.pc < cached_call_state.byte_code_size) + ? cached_call_state.byte_code_data[cached_call_state.pc] : OP_STOP); __SYNC_THREADS__ #ifdef EIP_3155 @@ -244,395 +345,450 @@ __host__ __device__ void evm_t::run(ArithEnv &arith) { // opcode, call_state_ptr->trace_idx, tracer_ptr, tracer_ptr->size); // __ONE_GPU_THREAD_WOSYNC_END__ // #endif - uint32_t trace_idx = tracer_ptr->start_operation(arith, call_state_ptr->pc, opcode, *call_state_ptr->memory_ptr, - *call_state_ptr->stack_ptr, call_state_ptr->depth, - *call_state_ptr->last_return_data_ptr, - call_state_ptr->gas_limit, call_state_ptr->gas_used); + // printf("before start_operation mem ptr %p memsize %d threadidx %d\n", call_state_ptr->memory_ptr, + // call_state_ptr->memory_ptr->size, THREADIDX); + uint32_t trace_idx = tracer_ptr->start_operation(arith, cached_call_state.pc, opcode, + *call_state_ptr->memory_ptr, *cached_call_state.stack_ptr, + call_state_ptr->depth, *call_state_ptr->last_return_data_ptr, + cached_call_state.gas_limit, cached_call_state.gas_used); call_state_ptr->trace_idx = trace_idx; -#ifdef __CUDA_ARCH__ - __ONE_GPU_THREAD_WOSYNC_BEGIN__ - printf("\npc: %d opcode: %d, depth %d, thread %d \n", call_state_ptr->pc, opcode, call_state_ptr->depth, - threadIdx.x); - __ONE_GPU_THREAD_WOSYNC_END__ + + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // printf("\npc: %d opcode: %d, depth %d, thread %d \n", cached_call_state.pc, opcode, call_state_ptr->depth, + // THREADIDX); + // // print_bnt(arith, cached_call_state.gas_limit); + // // print_bnt(arith, cached_call_state.gas_used); + // __ONE_GPU_THREAD_WOSYNC_END__ + #endif + + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // printf("\npc: %d opcode: %d, depth %d, thread %d \n", cached_call_state.pc, opcode, call_state_ptr->depth, + // THREADIDX); + // __ONE_GPU_THREAD_WOSYNC_END__ + +#ifdef BUILD_LIBRARY + // comparison, arithmetic, revert/invalid + if ((opcode <= OP_EXP || opcode >= OP_REVERT || opcode == OP_SSTORE) && opcode != 0) { + simplified_trace_data_ptr->start_operation(cached_call_state.pc, opcode, *cached_call_state.stack_ptr); + } + if (opcode == OP_JUMPI) pc_src = cached_call_state.pc; #endif // DEBUG PRINT - // __ONE_THREAD_PER_INSTANCE( - // printf("\npc: %d opcode: %d\n", call_state_ptr->pc, opcode);); + // __ONE_THREAD_PER_INSTANCE(printf("\npc: %d opcode: %d\n", call_state_ptr->pc, opcode);); // printf("touch state BEGIN BEGIN BEGIN\n"); // call_state_ptr->touch_state.print(); // printf("touch state END END END\n"); if (((opcode & 0xF0) == 0x60) || ((opcode & 0xF0) == 0x70)) { - error_code = CuEVM::operations::PUSHX(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - call_state_ptr->pc, *call_state_ptr->stack_ptr, - ((call_state_ptr->message_ptr)->byte_code), opcode); + error_code = CuEVM::operations::PUSHX(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + cached_call_state.pc, *cached_call_state.stack_ptr, + *((call_state_ptr->message_ptr)->byte_code), opcode); } else if ((opcode & 0xF0) == 0x80) // DUPX { - error_code = CuEVM::operations::DUPX(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, opcode); + error_code = CuEVM::operations::DUPX(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, opcode); } else if ((opcode & 0xF0) == 0x90) // SWAPX { - error_code = CuEVM::operations::SWAPX(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, opcode); - } else if ((opcode >= 0xA0) && (opcode <= 0xA4)) // LOGX - { - error_code = CuEVM::operations::LOGX(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->memory_ptr, - *call_state_ptr->message_ptr, *call_state_ptr->log_state_ptr, opcode); + error_code = CuEVM::operations::SWAPX(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, opcode); } else { switch (opcode) { case OP_STOP: error_code = CuEVM::operations::STOP(*call_state_ptr->parent->last_return_data_ptr); break; case OP_ADD: - error_code = CuEVM::operations::ADD(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::ADD(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_MUL: - error_code = CuEVM::operations::MUL(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::MUL(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SUB: - error_code = CuEVM::operations::SUB(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::SUB(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_DIV: - error_code = CuEVM::operations::DIV(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::DIV(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SDIV: - error_code = CuEVM::operations::SDIV(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::SDIV(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_MOD: - error_code = CuEVM::operations::MOD(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::MOD(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SMOD: - error_code = CuEVM::operations::SMOD(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::SMOD(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_ADDMOD: - error_code = CuEVM::operations::ADDMOD(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::ADDMOD(arith, cached_call_state.gas_limit, + cached_call_state.gas_used, *cached_call_state.stack_ptr); break; case OP_MULMOD: - error_code = CuEVM::operations::MULMOD(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::MULMOD(arith, cached_call_state.gas_limit, + cached_call_state.gas_used, *cached_call_state.stack_ptr); break; case OP_EXP: - error_code = CuEVM::operations::EXP(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::EXP(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SIGNEXTEND: - error_code = CuEVM::operations::SIGNEXTEND(arith, call_state_ptr->gas_limit, - call_state_ptr->gas_used, *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::SIGNEXTEND( + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr); break; case OP_LT: - error_code = CuEVM::operations::LT(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->record_distance(arith, opcode, *cached_call_state.stack_ptr); +#endif + error_code = CuEVM::operations::LT(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_GT: - error_code = CuEVM::operations::GT(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->record_distance(arith, opcode, *cached_call_state.stack_ptr); +#endif + error_code = CuEVM::operations::GT(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SLT: - error_code = CuEVM::operations::SLT(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->record_distance(arith, opcode, *cached_call_state.stack_ptr); +#endif + error_code = CuEVM::operations::SLT(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SGT: - error_code = CuEVM::operations::SGT(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->record_distance(arith, opcode, *cached_call_state.stack_ptr); +#endif + error_code = CuEVM::operations::SGT(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_EQ: - error_code = CuEVM::operations::EQ(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->record_distance(arith, opcode, *cached_call_state.stack_ptr); +#endif + error_code = CuEVM::operations::EQ(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_ISZERO: - error_code = CuEVM::operations::ISZERO(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::ISZERO(arith, cached_call_state.gas_limit, + cached_call_state.gas_used, *cached_call_state.stack_ptr); break; case OP_AND: - error_code = CuEVM::operations::AND(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::AND(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_OR: - error_code = CuEVM::operations::OR(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::OR(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_XOR: - error_code = CuEVM::operations::XOR(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::XOR(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_NOT: - error_code = CuEVM::operations::NOT(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::NOT(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_BYTE: - error_code = CuEVM::operations::BYTE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::BYTE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SHL: - error_code = CuEVM::operations::SHL(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::SHL(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SHR: - error_code = CuEVM::operations::SHR(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::SHR(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SAR: - error_code = CuEVM::operations::SAR(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::SAR(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_SHA3: - error_code = CuEVM::operations::SHA3(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->memory_ptr); + error_code = CuEVM::operations::SHA3(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->memory_ptr); break; case OP_ADDRESS: - error_code = CuEVM::operations::ADDRESS(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->message_ptr); + error_code = + CuEVM::operations::ADDRESS(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->message_ptr); break; case OP_BALANCE: - error_code = CuEVM::operations::BALANCE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, call_state_ptr->touch_state); + error_code = + CuEVM::operations::BALANCE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->touch_state_ptr); break; case OP_ORIGIN: - error_code = CuEVM::operations::ORIGIN(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *transaction_ptr); + error_code = + CuEVM::operations::ORIGIN(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *transaction_ptr); break; case OP_CALLER: - error_code = CuEVM::operations::CALLER(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->message_ptr); + error_code = + CuEVM::operations::CALLER(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->message_ptr); break; case OP_CALLVALUE: error_code = - CuEVM::operations::CALLVALUE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->message_ptr); + CuEVM::operations::CALLVALUE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->message_ptr); break; case OP_CALLDATALOAD: error_code = - CuEVM::operations::CALLDATALOAD(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->message_ptr); + CuEVM::operations::CALLDATALOAD(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->message_ptr); break; case OP_CALLDATASIZE: error_code = - CuEVM::operations::CALLDATASIZE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->message_ptr); + CuEVM::operations::CALLDATASIZE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->message_ptr); break; case OP_CALLDATACOPY: error_code = CuEVM::operations::CALLDATACOPY( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, *call_state_ptr->stack_ptr, + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, *call_state_ptr->message_ptr, *call_state_ptr->memory_ptr); break; case OP_CODESIZE: - error_code = CuEVM::operations::CODESIZE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->message_ptr); + error_code = + CuEVM::operations::CODESIZE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->message_ptr); break; case OP_CODECOPY: - error_code = CuEVM::operations::CODECOPY(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->message_ptr, - *call_state_ptr->memory_ptr); + error_code = CuEVM::operations::CODECOPY(arith, cached_call_state.gas_limit, + cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->message_ptr, *call_state_ptr->memory_ptr); break; case OP_GASPRICE: error_code = - CuEVM::operations::GASPRICE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr, *transaction_ptr); + CuEVM::operations::GASPRICE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr, *transaction_ptr); break; case OP_EXTCODESIZE: error_code = - CuEVM::operations::EXTCODESIZE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, call_state_ptr->touch_state); + CuEVM::operations::EXTCODESIZE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->touch_state_ptr); break; case OP_EXTCODECOPY: error_code = CuEVM::operations::EXTCODECOPY( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, *call_state_ptr->stack_ptr, - call_state_ptr->touch_state, *call_state_ptr->memory_ptr); + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->touch_state_ptr, *call_state_ptr->memory_ptr); break; case OP_RETURNDATASIZE: - error_code = CuEVM::operations::RETURNDATASIZE(arith, call_state_ptr->gas_limit, - call_state_ptr->gas_used, *call_state_ptr->stack_ptr, - *call_state_ptr->last_return_data_ptr); + error_code = CuEVM::operations::RETURNDATASIZE( + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->last_return_data_ptr); break; case OP_RETURNDATACOPY: error_code = CuEVM::operations::RETURNDATACOPY( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, *call_state_ptr->stack_ptr, + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, *call_state_ptr->memory_ptr, *call_state_ptr->last_return_data_ptr); break; case OP_EXTCODEHASH: error_code = - CuEVM::operations::EXTCODEHASH(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, call_state_ptr->touch_state); + CuEVM::operations::EXTCODEHASH(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->touch_state_ptr); break; case OP_BLOCKHASH: error_code = - CuEVM::operations::BLOCKHASH(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr); + CuEVM::operations::BLOCKHASH(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr); break; case OP_COINBASE: - error_code = CuEVM::operations::COINBASE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr); + error_code = + CuEVM::operations::COINBASE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr); break; case OP_TIMESTAMP: error_code = - CuEVM::operations::TIMESTAMP(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr); + CuEVM::operations::TIMESTAMP(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr); break; case OP_NUMBER: - error_code = CuEVM::operations::NUMBER(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr); + error_code = + CuEVM::operations::NUMBER(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr); break; case OP_DIFFICULTY: error_code = - CuEVM::operations::PREVRANDAO(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr); + CuEVM::operations::PREVRANDAO(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr); break; case OP_GASLIMIT: - error_code = CuEVM::operations::GASLIMIT(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr); + error_code = + CuEVM::operations::GASLIMIT(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr); break; case OP_CHAINID: - error_code = CuEVM::operations::CHAINID(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr); + error_code = + CuEVM::operations::CHAINID(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr); break; case OP_SELFBALANCE: error_code = CuEVM::operations::SELFBALANCE( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, *call_state_ptr->stack_ptr, - call_state_ptr->touch_state, *call_state_ptr->message_ptr); + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->touch_state_ptr, *call_state_ptr->message_ptr); break; case OP_BASEFEE: - error_code = CuEVM::operations::BASEFEE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *block_info_ptr); + error_code = + CuEVM::operations::BASEFEE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *block_info_ptr); break; case OP_POP: - error_code = CuEVM::operations::POP(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::POP(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_MLOAD: - error_code = CuEVM::operations::MLOAD(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->memory_ptr); + error_code = + CuEVM::operations::MLOAD(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->memory_ptr); break; case OP_MSTORE: - error_code = CuEVM::operations::MSTORE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->memory_ptr); + error_code = + CuEVM::operations::MSTORE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->memory_ptr); break; case OP_MSTORE8: - error_code = CuEVM::operations::MSTORE8(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->memory_ptr); + error_code = + CuEVM::operations::MSTORE8(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->memory_ptr); break; case OP_SLOAD: - error_code = CuEVM::operations::SLOAD(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, call_state_ptr->touch_state, - *call_state_ptr->message_ptr); + error_code = CuEVM::operations::SLOAD( + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->touch_state_ptr, *call_state_ptr->message_ptr); break; case OP_SSTORE: - error_code = CuEVM::operations::SSTORE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - call_state_ptr->gas_refund, *call_state_ptr->stack_ptr, - call_state_ptr->touch_state, *call_state_ptr->message_ptr); + error_code = CuEVM::operations::SSTORE( + arith, cached_call_state.gas_limit, cached_call_state.gas_used, call_state_ptr->gas_refund, + *cached_call_state.stack_ptr, *call_state_ptr->touch_state_ptr, *call_state_ptr->message_ptr); break; case OP_JUMP: - error_code = CuEVM::operations::JUMP(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - call_state_ptr->pc, *call_state_ptr->stack_ptr, + error_code = CuEVM::operations::JUMP(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + cached_call_state.pc, *cached_call_state.stack_ptr, *call_state_ptr->message_ptr); break; case OP_JUMPI: - error_code = CuEVM::operations::JUMPI(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - call_state_ptr->pc, *call_state_ptr->stack_ptr, - *call_state_ptr->message_ptr); + + error_code = CuEVM::operations::JUMPI(arith, cached_call_state.gas_limit, + cached_call_state.gas_used, cached_call_state.pc, + *cached_call_state.stack_ptr, *call_state_ptr->message_ptr +#ifdef BUILD_LIBRARY + , + simplified_trace_data_ptr +#endif + ); + break; case OP_PC: - error_code = CuEVM::operations::PC(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - call_state_ptr->pc, *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::PC(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + cached_call_state.pc, *cached_call_state.stack_ptr); break; case OP_MSIZE: - error_code = CuEVM::operations::MSIZE(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->memory_ptr); + error_code = + CuEVM::operations::MSIZE(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr, *call_state_ptr->memory_ptr); break; case OP_GAS: - error_code = CuEVM::operations::GAS(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::GAS(arith, cached_call_state.gas_limit, cached_call_state.gas_used, + *cached_call_state.stack_ptr); break; case OP_JUMPDEST: error_code = - CuEVM::operations::JUMPDEST(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used); + CuEVM::operations::JUMPDEST(arith, cached_call_state.gas_limit, cached_call_state.gas_used); break; case OP_PUSH0: - error_code = CuEVM::operations::PUSH0(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr); + error_code = CuEVM::operations::PUSH0(arith, cached_call_state.gas_limit, + cached_call_state.gas_used, *cached_call_state.stack_ptr); break; case OP_CREATE: child_call_state_ptr = nullptr; - error_code = CuEVM::operations::CREATE(arith, *call_state_ptr, child_call_state_ptr); + error_code = + CuEVM::operations::CREATE(arith, *call_state_ptr, child_call_state_ptr, cached_call_state); break; case OP_CALL: child_call_state_ptr = nullptr; - error_code = CuEVM::operations::CALL(arith, *call_state_ptr, child_call_state_ptr); + error_code = + CuEVM::operations::CALL(arith, *call_state_ptr, child_call_state_ptr, cached_call_state); break; case OP_CALLCODE: child_call_state_ptr = nullptr; - error_code = CuEVM::operations::CALLCODE(arith, *call_state_ptr, child_call_state_ptr); + error_code = + CuEVM::operations::CALLCODE(arith, *call_state_ptr, child_call_state_ptr, cached_call_state); break; case OP_RETURN: - error_code = CuEVM::operations::RETURN(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->memory_ptr, - *call_state_ptr->parent->last_return_data_ptr); + error_code = CuEVM::operations::RETURN( + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->memory_ptr, *call_state_ptr->parent->last_return_data_ptr); break; case OP_DELEGATECALL: child_call_state_ptr = nullptr; - error_code = CuEVM::operations::DELEGATECALL(arith, *call_state_ptr, child_call_state_ptr); + error_code = CuEVM::operations::DELEGATECALL(arith, *call_state_ptr, child_call_state_ptr, + cached_call_state); break; case OP_CREATE2: child_call_state_ptr = nullptr; - error_code = CuEVM::operations::CREATE2(arith, *call_state_ptr, child_call_state_ptr); + error_code = + CuEVM::operations::CREATE2(arith, *call_state_ptr, child_call_state_ptr, cached_call_state); break; case OP_STATICCALL: child_call_state_ptr = nullptr; - error_code = CuEVM::operations::STATICCALL(arith, *call_state_ptr, child_call_state_ptr); + error_code = + CuEVM::operations::STATICCALL(arith, *call_state_ptr, child_call_state_ptr, cached_call_state); break; case OP_REVERT: - error_code = CuEVM::operations::REVERT(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, - *call_state_ptr->stack_ptr, *call_state_ptr->memory_ptr, - *call_state_ptr->parent->last_return_data_ptr); + error_code = CuEVM::operations::REVERT( + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->memory_ptr, *call_state_ptr->parent->last_return_data_ptr); break; case OP_SELFDESTRUCT: error_code = CuEVM::operations::SELFDESTRUCT( - arith, call_state_ptr->gas_limit, call_state_ptr->gas_used, *call_state_ptr->stack_ptr, - *call_state_ptr->message_ptr, call_state_ptr->touch_state, + arith, cached_call_state.gas_limit, cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->message_ptr, *call_state_ptr->touch_state_ptr, *call_state_ptr->parent->last_return_data_ptr); break; default: - error_code = CuEVM::operations::INVALID(); + if ((opcode >= 0xA0) && (opcode <= 0xA4)) // LOGX // not common + { + error_code = CuEVM::operations::LOGX(arith, cached_call_state.gas_limit, + cached_call_state.gas_used, *cached_call_state.stack_ptr, + *call_state_ptr->memory_ptr, *call_state_ptr->message_ptr, + *call_state_ptr->log_state_ptr, opcode); + } else + error_code = CuEVM::operations::INVALID(); break; } } // TODO: to see after calls // increase program counter - call_state_ptr->pc++; - // __SYNC_THREADS__ -// #ifdef __CUDA_ARCH__ -// __SYNC_THREADS__ -// printf("idx %d after increase pc %d , call_state_ptr %p, call_state_ptr->trace_idx %d , depth %d\n", -// threadIdx.x, call_state_ptr->pc, call_state_ptr, call_state_ptr->trace_idx, call_state_ptr->depth); -// #endif + cached_call_state.pc++; + #ifdef EIP_3155 if (call_state_ptr->trace_idx > 0 || (call_state_ptr->trace_idx == 0 && call_state_ptr->depth == 1)) { - tracer_ptr->finish_operation(arith, call_state_ptr->trace_idx, call_state_ptr->gas_used, + tracer_ptr->finish_operation(arith, call_state_ptr->trace_idx, cached_call_state.gas_used, call_state_ptr->gas_refund #ifdef EIP_3155_OPTIONAL , @@ -641,14 +797,22 @@ __host__ __device__ void evm_t::run(ArithEnv &arith) { ); } #endif - // #ifdef __CUDA_ARCH__ - // printf("after finish_operation idx %d opcode %d error code %d\n", threadIdx.x, opcode, error_code); - // #endif - if ((opcode == OP_CALL) || (opcode == OP_CALLCODE) || (opcode == OP_DELEGATECALL) || (opcode == OP_CREATE) || - (opcode == OP_CREATE2) || (opcode == OP_STATICCALL)) { +#ifdef BUILD_LIBRARY + if ((opcode <= OP_EXP || opcode >= OP_REVERT || opcode == OP_SSTORE) && opcode != 0) { + simplified_trace_data_ptr->finish_operation(*cached_call_state.stack_ptr, error_code); + } +#endif + + // all calls + create + if (opcode >= OP_CREATE && opcode <= OP_STATICCALL && opcode != OP_RETURN) { if (error_code == ERROR_SUCCESS) { + cached_call_state.write_cache_to_state(arith, call_state_ptr); call_state_ptr = child_call_state_ptr; - error_code = start_CALL(arith); + cached_call_state = cached_evm_call_state(arith, call_state_ptr); + error_code = start_CALL(arith, cached_call_state); +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->start_call(call_state_ptr->parent->pc, call_state_ptr->message_ptr); +#endif } else if (opcode == OP_CREATE || opcode == OP_CREATE2) { // Logic: when op_create or create2 does not succeed, // there is no start_CALL but do not revert parent contract: @@ -656,11 +820,13 @@ __host__ __device__ void evm_t::run(ArithEnv &arith) { // + other (inside start_CALL) if (error_code == ERROR_MESSAGE_CALL_CREATE_CONTRACT_EXISTS) { // bypass the below by setting error_code == ERROR_SUCCESS + printf("ERROR_MESSAGE_CALL_CREATE_CONTRACT_EXISTS\n"); error_code = ERROR_SUCCESS; // setting address = 0 to the stack bn_t create_output; cgbn_set_ui32(arith.env, create_output, 0); call_state_ptr->stack_ptr->push(arith, create_output); + call_state_ptr->message_ptr->copy_from(call_state_ptr->message_ptr_copy); CuEVM::byte_array_t::reset_return_data(call_state_ptr->last_return_data_ptr); } } @@ -674,7 +840,7 @@ __host__ __device__ void evm_t::run(ArithEnv &arith) { call_state_ptr->message_ptr->call_type == OP_CREATE2)) { // TODO: finish create call add the contract to the state // printf("Create call\n"); - error_code = finish_CREATE(arith); + error_code = finish_CREATE(arith, cached_call_state); } if (call_state_ptr->depth == 1) { @@ -684,13 +850,16 @@ __host__ __device__ void evm_t::run(ArithEnv &arith) { // printf(" call_state_ptr->depth == 1 finish call %d error_code: %d\n", threadIdx.x, // error_code); // #endif + cached_call_state.write_cache_to_state(arith, call_state_ptr); finish_CALL(arith, error_code); - - error_code |= finish_TRANSACTION(arith, error_code); + finish_TRANSACTION(arith, error_code); + return; } else { // TODO: finish call // printf("Finish call\n"); + cached_call_state.write_cache_to_state(arith, call_state_ptr); error_code |= finish_CALL(arith, error_code); + cached_call_state = cached_evm_call_state(arith, call_state_ptr); } } } @@ -699,12 +868,10 @@ __host__ __device__ void evm_t::run(ArithEnv &arith) { __host__ __device__ int32_t evm_t::finish_TRANSACTION(ArithEnv &arith, int32_t error_code) { // sent the gas value to the block beneficiary bn_t gas_value; - bn_t beneficiary; - block_info_ptr->get_coin_base(arith, beneficiary); + const evm_word_t *beneficiary = &(block_info_ptr->coin_base); + // block_info_ptr->get_coin_base(arith, beneficiary); #ifdef EIP_3155 -#ifdef __CUDA_ARCH__ - printf("finish_TRANSACTION %d error_code: %d\n", threadIdx.x, error_code); -#endif + __ONE_THREAD_PER_INSTANCE(printf("finish_TRANSACTION %d error_code: %d\n", THREADIDX, error_code);); #endif if ((error_code == ERROR_RETURN) || (error_code == ERROR_REVERT)) { bn_t gas_left; @@ -730,9 +897,9 @@ __host__ __device__ int32_t evm_t::finish_TRANSACTION(ArithEnv &arith, int32_t e cgbn_mul(arith.env, send_back_gas, gas_value, gas_price); // add to sender balance g^{*} bn_t sender_balance; - bn_t sender_address; + // bn_t sender_address; // send back the gas left and gas refund to the sender - transaction_ptr->get_sender(arith, sender_address); + // transaction_ptr->get_sender(arith, sender_address); // deduct transaction value; TODO this probably should be done at some // other place _transaction->get_value(tx_value); cgbn_sub(arith.env, // sender_balance, sender_balance, tx_value); the gas value for the @@ -748,41 +915,55 @@ __host__ __device__ int32_t evm_t::finish_TRANSACTION(ArithEnv &arith, int32_t e call_state_ptr->parent->update(arith, *call_state_ptr); } // sent the value of unused gas to the sender - call_state_ptr->parent->touch_state.get_balance(arith, sender_address, sender_balance); + call_state_ptr->parent->touch_state_ptr->get_balance(arith, &transaction_ptr->sender, sender_balance); cgbn_add(arith.env, sender_balance, sender_balance, send_back_gas); - call_state_ptr->parent->touch_state.set_balance(arith, sender_address, sender_balance); + call_state_ptr->parent->touch_state_ptr->set_balance(arith, &transaction_ptr->sender, sender_balance); // set the eror code for a succesfull transaction status = error_code; } else { // TODO: do we consider gas_priority_fee in revert? cgbn_set(arith.env, call_state_ptr->parent->gas_used, call_state_ptr->gas_limit); - // cgbn_mul(arith.env, gas_value, call_state_ptr->gas_limit, gas_priority_fee); + // cgbn_mul(arith.env, gas_value, cached_call_state.gas_limit, gas_priority_fee); // set z to the given error or 1 TODO: 1 in YP #ifdef EIP_3155 -#ifdef __CUDA_ARCH__ - printf("finish_TRANSACTION %d error_code: %d\n", threadIdx.x, error_code); - print_bnt(arith, gas_value); - print_bnt(arith, call_state_ptr->gas_limit); - print_bnt(arith, call_state_ptr->gas_used); - print_bnt(arith, gas_priority_fee); -#endif + // __ONE_THREAD_PER_INSTANCE(printf("finish_TRANSACTION %d error_code: %d\n", THREADIDX, error_code);); + // print_bnt(arith, gas_value); + // print_bnt(arith, call_state_ptr->gas_limit); + // print_bnt(arith, call_state_ptr->gas_used); + // print_bnt(arith, gas_priority_fee); + #endif status = error_code; } // send the gas value to the beneficiary if (cgbn_compare_ui32(arith.env, gas_value, 0) > 0) { bn_t beneficiary_balance; - call_state_ptr->parent->touch_state.get_balance(arith, beneficiary, beneficiary_balance); + call_state_ptr->parent->touch_state_ptr->get_balance(arith, beneficiary, beneficiary_balance); cgbn_add(arith.env, beneficiary_balance, beneficiary_balance, gas_value); - call_state_ptr->parent->touch_state.set_balance(arith, beneficiary, beneficiary_balance); + call_state_ptr->parent->touch_state_ptr->set_balance(arith, beneficiary, beneficiary_balance); } CuEVM::evm_call_state_t *parent_call_state_ptr = call_state_ptr->parent; delete call_state_ptr; call_state_ptr = parent_call_state_ptr; + // call_state_local = evm_call_state_t(arith, call_state_ptr); +// #ifdef EIP_3155 +// // printing debug when enabling tracer. +// printf("call_state_ptr allocated %p, threadid %d\n", call_state_ptr, THREADIDX); +// // transaction_ptr->print(); +// call_state_ptr->print(arith); +// printf("call_state_local %d\n", THREADIDX); +// call_state_local.print(arith); +// #endif #ifdef EIP_3155 tracer_ptr->finish_transaction(arith, *call_state_ptr->last_return_data_ptr, call_state_ptr->gas_used, status); #endif + // update the final world state : TODO combine both + // __SYNC_THREADS__ + this->world_state.update(arith, call_state_ptr->touch_state_ptr->get_state()); + this->world_state.serialize_data(arith, serialized_worldstate_data_ptr); + // printf("updated final world state\n"); + return status; } @@ -791,12 +972,12 @@ __host__ __device__ int32_t evm_t::finish_CALL(ArithEnv &arith, int32_t error_co // set the child call to failure cgbn_set_ui32(arith.env, child_success, 0); - // #ifdef __CUDA_ARCH__ - // printf("evm_t::finish_CALL %d error_code: %d\n", threadIdx.x, error_code); - // #endif + // printf("evm_t::finish_CALL %d error_code: %d\n", THREADIDX, error_code); // if the child call return from normal halting // no errors - // printf(" finish_CALL error_code: %d\n", error_code); + // #ifdef EIP_3155 + // printf(" finish_CALL error_code: %d %d\n", error_code, THREADIDX); + // #endif if ((error_code == ERROR_RETURN) || (error_code == ERROR_REVERT) || (error_code == ERROR_INSUFFICIENT_FUNDS) || (error_code == ERROR_MESSAGE_CALL_CREATE_NONCE_EXCEEDED) || error_code == ERROR_MESSAGE_CALL_DEPTH_EXCEEDED) { // give back the gas left from the child computation @@ -824,26 +1005,27 @@ __host__ __device__ int32_t evm_t::finish_CALL(ArithEnv &arith, int32_t error_co } } } +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->finish_call((error_code == ERROR_RETURN)); +#endif + // printf("end finish_CALL before set warm account %d idx %d\n", error_code, THREADIDX); // #ifdef __CUDA_ARCH__ // printf("evm_t::finish_CALL %d before setting warm accounts error_code: %d\n", threadIdx.x, error_code); // #endif // warm the sender and receiver regardless of revert - bn_t sender, receiver; - call_state_ptr->message_ptr->get_sender(arith, sender); - call_state_ptr->parent->touch_state.set_warm_account(arith, sender); + // bn_t sender, receiver; + // call_state_ptr->message_ptr->get_sender(arith, sender); + call_state_ptr->parent->touch_state_ptr->set_warm_account(arith, &call_state_ptr->message_ptr->sender); - call_state_ptr->message_ptr->get_recipient(arith, receiver); - call_state_ptr->parent->touch_state.set_warm_account(arith, receiver); - // #ifdef __CUDA_ARCH__ - // printf("evm_t::finish_CALL %d after setting warm accounts error_code: %d\n", threadIdx.x, error_code); - // #endif + // call_state_ptr->message_ptr->get_recipient(arith, receiver); + call_state_ptr->parent->touch_state_ptr->set_warm_account(arith, &call_state_ptr->message_ptr->recipient); if (call_state_ptr->depth > 1 && error_code != ERROR_RETURN && error_code != ERROR_REVERT) { // abnormal halting where return data ptr is not handled, need to reset // it - if (call_state_ptr->parent->last_return_data_ptr != nullptr) - delete call_state_ptr->parent->last_return_data_ptr; - call_state_ptr->parent->last_return_data_ptr = new CuEVM::evm_return_data_t(); - // CuEVM::byte_array_t::reset_return_data(call_state_ptr->parent->last_return_data_ptr); + // if (call_state_ptr->parent->last_return_data_ptr != nullptr) + // delete call_state_ptr->parent->last_return_data_ptr; + // call_state_ptr->parent->last_return_data_ptr = new CuEVM::evm_return_data_t(); + CuEVM::byte_array_t::reset_return_data(call_state_ptr->parent->last_return_data_ptr); } // get the memory offset and size of the return data // in the parent memory @@ -868,46 +1050,35 @@ __host__ __device__ int32_t evm_t::finish_CALL(ArithEnv &arith, int32_t error_co // change the call state to the parent CuEVM::evm_call_state_t *parent_call_state_ptr = call_state_ptr->parent; delete call_state_ptr; + call_state_ptr = parent_call_state_ptr; + + // copy back the shadow message_call t to shared memory + call_state_ptr->message_ptr->copy_from(call_state_ptr->message_ptr_copy); + // cached_call_state = cached_evm_call_state(arith, call_state_ptr); } - // #ifdef __CUDA_ARCH__ - // printf("evm_t::finish_CALL %d before return error_code: %d\n", threadIdx.x, error_code); - // #endif + // printf("end finish_CALL error_code: %d idx %d\n", error_code, THREADIDX); return error_code; } -__host__ __device__ int32_t evm_t::finish_CREATE(ArithEnv &arith) { +__host__ __device__ int32_t evm_t::finish_CREATE(ArithEnv &arith, cached_evm_call_state &cached_call_state) { // TODO: increase sender nonce if the sender is a contract // to see if the contract is a contract - bn_t sender_address; - call_state_ptr->message_ptr->get_sender(arith, sender_address); + // bn_t sender_address; + // call_state_ptr->message_ptr->get_sender(arith, sender_address); CuEVM::account_t *sender_account = nullptr; - call_state_ptr->parent->touch_state.get_account(arith, sender_address, sender_account, ACCOUNT_BYTE_CODE_FLAG); - // if (sender_account->is_contract()) { - // printf("\naccount is contract\n"); - // bn_t sender_nonce; - // call_state_ptr->parent->touch_state.get_nonce(arith, sender_address, - // sender_nonce); - // cgbn_add_ui32(arith.env, sender_nonce, sender_nonce, 1); - // call_state_ptr->parent->touch_state.set_nonce(arith, sender_address, - // sender_nonce); - // } - - // bn_t sender_nonce; - // call_state_ptr->parent->touch_state.get_nonce(arith, sender_address, - // sender_nonce); cgbn_add_ui32(arith.env, sender_nonce, sender_nonce, 1); - // call_state_ptr->parent->touch_state.set_nonce(arith, sender_address, - // sender_nonce); compute the gas to deposit the contract + call_state_ptr->parent->touch_state_ptr->get_account(arith, &call_state_ptr->message_ptr->sender, sender_account, + ACCOUNT_BYTE_CODE_FLAG); bn_t code_size; cgbn_set_ui32(arith.env, code_size, call_state_ptr->parent->last_return_data_ptr->size); - CuEVM::gas_cost::code_cost(arith, call_state_ptr->gas_used, code_size); + CuEVM::gas_cost::code_cost(arith, cached_call_state.gas_used, code_size); int32_t error_code = ERROR_SUCCESS; - error_code |= CuEVM::gas_cost::has_gas(arith, call_state_ptr->gas_limit, call_state_ptr->gas_used); + error_code |= CuEVM::gas_cost::has_gas(arith, cached_call_state.gas_limit, cached_call_state.gas_used); if (error_code == ERROR_SUCCESS) { // compute the address of the contract - bn_t contract_address; - call_state_ptr->message_ptr->get_recipient(arith, contract_address); + // bn_t contract_address; + // call_state_ptr->message_ptr->get_recipient(arith, contract_address); #ifdef EIP_3541 uint8_t *code = call_state_ptr->parent->last_return_data_ptr->data; #endif @@ -919,16 +1090,16 @@ __host__ __device__ int32_t evm_t::finish_CREATE(ArithEnv &arith) { error_code = ERROR_CREATE_CODE_FIRST_BYTE_INVALID; } #endif - call_state_ptr->touch_state.set_code(arith, contract_address, - *call_state_ptr->parent->last_return_data_ptr); + call_state_ptr->touch_state_ptr->set_code(arith, &call_state_ptr->message_ptr->recipient, + *call_state_ptr->parent->last_return_data_ptr); } else { error_code = ERROR_CREATE_CODE_SIZE_EXCEEDED; } // reset last return data after CREATE - if (call_state_ptr->parent->last_return_data_ptr != nullptr) - delete call_state_ptr->parent->last_return_data_ptr; - call_state_ptr->parent->last_return_data_ptr = new CuEVM::evm_return_data_t(); - // CuEVM::byte_array_t::reset_return_data(call_state_ptr->parent->last_return_data_ptr); + // if (call_state_ptr->parent->last_return_data_ptr != nullptr) + // delete call_state_ptr->parent->last_return_data_ptr; + // call_state_ptr->parent->last_return_data_ptr = new CuEVM::evm_return_data_t(); + CuEVM::byte_array_t::reset_return_data(call_state_ptr->parent->last_return_data_ptr); } // if success, return ERROR_RETURN to continue finish call return error_code ? error_code : ERROR_RETURN; @@ -1004,6 +1175,20 @@ __host__ int32_t get_evm_instances(ArithEnv &arith, evm_instance_t *&evm_instanc memcpy(evm_instances[index].tracer_ptr, tracer, sizeof(CuEVM::utils::tracer_t)); delete tracer; #endif + + CuEVM::serialized_worldstate_data *serialized_worldstate_data = new CuEVM::serialized_worldstate_data(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].serialized_worldstate_data_ptr, + sizeof(CuEVM::serialized_worldstate_data))); + memcpy(evm_instances[index].serialized_worldstate_data_ptr, serialized_worldstate_data, + sizeof(CuEVM::serialized_worldstate_data)); + delete serialized_worldstate_data; + + CuEVM::utils::simplified_trace_data *simplified_trace_data = new CuEVM::utils::simplified_trace_data(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].simplified_trace_data_ptr, + sizeof(CuEVM::utils::simplified_trace_data))); + memcpy(evm_instances[index].simplified_trace_data_ptr, simplified_trace_data, + sizeof(CuEVM::utils::simplified_trace_data)); + delete simplified_trace_data; } } num_instances = num_transactions; @@ -1040,5 +1225,6 @@ __host__ void free_evm_instances(evm_instance_t *&evm_instances, uint32_t num_in CUDA_CHECK(cudaFree(evm_instances)); } } + } // namespace CuEVM // todo|: make a vector o functions global constants so you can call them diff --git a/CuEVM/src/evm_call_state.cu b/CuEVM/src/evm_call_state.cu index c6ff381..5226455 100644 --- a/CuEVM/src/evm_call_state.cu +++ b/CuEVM/src/evm_call_state.cu @@ -4,12 +4,30 @@ #include namespace CuEVM { +__host__ __device__ cached_evm_call_state::cached_evm_call_state(ArithEnv& arith, + evm_call_state_t* state) { // copy from state to cache + pc = state->pc; + cgbn_set(arith.env, gas_used, state->gas_used); + cgbn_set(arith.env, gas_limit, state->gas_limit); + stack_ptr = state->stack_ptr; + // printf("message ptr %p\n", state->message_ptr); + byte_code_size = state->message_ptr->byte_code->size; + byte_code_data = state->message_ptr->byte_code->data; +} +__host__ __device__ void cached_evm_call_state::write_cache_to_state(ArithEnv& arith, evm_call_state_t* state) { + state->pc = pc; + cgbn_set(arith.env, state->gas_used, gas_used); +} // copy from cache to state +__host__ __device__ void cached_evm_call_state::set_byte_code(const byte_array_t* byte_code) { + byte_code_size = byte_code->size; + byte_code_data = byte_code->data; +} __host__ __device__ evm_call_state_t::evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* parent, uint32_t depth, uint32_t pc, bn_t gas_used, bn_t gas_refund, CuEVM::evm_message_call_t* message_ptr, CuEVM::evm_stack_t* stack_ptr, CuEVM::evm_memory_t* memory_ptr, CuEVM::log_state_data_t* log_state_ptr, - CuEVM::TouchState touch_state, + CuEVM::TouchState* touch_state_ptr, CuEVM::evm_return_data_t* last_return_data_ptr) { this->parent = parent; this->depth = depth; @@ -21,33 +39,125 @@ __host__ __device__ evm_call_state_t::evm_call_state_t(ArithEnv& arith, CuEVM::e this->stack_ptr = stack_ptr; this->memory_ptr = memory_ptr; this->log_state_ptr = log_state_ptr; - this->touch_state = touch_state; + this->touch_state_ptr = touch_state_ptr; this->last_return_data_ptr = last_return_data_ptr; #ifdef EIP_3155 this->trace_idx = 0; + // printf("evm_call_state_t constructor no parent %d\n", THREADIDX); #endif } +// /** +// * The constructor with the parent state and message call +// */ +// __host__ __device__ evm_call_state_t::evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* parent, +// CuEVM::evm_message_call_t* message_ptr) +// : touch_state(new CuEVM::state_access_t(), &parent->touch_state) { +// this->parent = parent; +// this->depth = parent->depth + 1; +// this->pc = 0; +// cgbn_set_ui32(arith.env, this->gas_used, 0); +// cgbn_set(arith.env, this->gas_refund, parent->gas_refund); +// this->message_ptr = message_ptr; +// this->message_ptr->get_gas_limit(arith, this->gas_limit); +// this->stack_ptr = new CuEVM::evm_stack_t(); +// this->memory_ptr = new CuEVM::evm_memory_t(); +// this->log_state_ptr = new CuEVM::log_state_data_t(); +// this->last_return_data_ptr = new CuEVM::evm_return_data_t(); +// #ifdef EIP_3155 +// this->trace_idx = 0; +// #endif +// } + /** * The constructor with the parent state and message call */ __host__ __device__ evm_call_state_t::evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* parent, - CuEVM::evm_message_call_t* message_ptr) - : touch_state(new CuEVM::state_access_t(), &parent->touch_state) { + CuEVM::evm_message_call_t* shared_message_ptr, + CuEVM::evm_message_call_t_shadow* shadow_message_ptr, + evm_word_t* shared_stack_ptr) +// : touch_state(new CuEVM::state_access_t(), &parent->touch_state) { +{ + // printf("evm_call_state_t constructor with parent %d\n", THREADIDX); + __SHARED_MEMORY__ CuEVM::TouchState* touch_state_ptr[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + touch_state_ptr[INSTANCE_IDX_PER_BLOCK] = + new CuEVM::TouchState(new CuEVM::state_access_t(), parent->touch_state_ptr); + __ONE_GPU_THREAD_END__ + this->touch_state_ptr = touch_state_ptr[INSTANCE_IDX_PER_BLOCK]; this->parent = parent; this->depth = parent->depth + 1; this->pc = 0; cgbn_set_ui32(arith.env, this->gas_used, 0); cgbn_set(arith.env, this->gas_refund, parent->gas_refund); - this->message_ptr = message_ptr; + this->message_ptr = shared_message_ptr; + this->message_ptr_copy = shadow_message_ptr; // point to global memory, deallocate in destructor this->message_ptr->get_gas_limit(arith, this->gas_limit); - this->stack_ptr = new CuEVM::evm_stack_t(); - this->memory_ptr = new CuEVM::evm_memory_t(); - this->log_state_ptr = new CuEVM::log_state_data_t(); - this->last_return_data_ptr = new CuEVM::evm_return_data_t(); + __SHARED_MEMORY__ evm_stack_t* stack_ptr[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + if (parent->stack_ptr != nullptr) { + stack_ptr[INSTANCE_IDX_PER_BLOCK] = + new CuEVM::evm_stack_t(parent->stack_ptr->shared_stack_base + parent->stack_ptr->stack_offset, + parent->stack_ptr->stack_base_offset + parent->stack_ptr->stack_offset); + // printf("parent stack found %p thread %d\n", parent->stack_ptr, THREADIDX); + } else { + stack_ptr[INSTANCE_IDX_PER_BLOCK] = new CuEVM::evm_stack_t(shared_stack_ptr); + // printf("parent stack not found %p thread %d\n", parent->stack_ptr, THREADIDX); + } + // printf("Stack constructor done stack base %p stack base offset %d stack offset %d\n", + // stack_ptr->shared_stack_base, + // stack_ptr->stack_base_offset, stack_ptr->stack_offset); + // stack_ptr = new CuEVM::evm_stack_t(shared_stack_ptr); + __ONE_GPU_THREAD_END__ + this->stack_ptr = stack_ptr[INSTANCE_IDX_PER_BLOCK]; + + // printf("evm_call_state_t initialized stack pointer %p thread %d\n", stack_ptr, THREADIDX); + + __SHARED_MEMORY__ evm_memory_t* memory_ptr[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + memory_ptr[INSTANCE_IDX_PER_BLOCK] = new CuEVM::evm_memory_t(); + __ONE_GPU_THREAD_END__ + + // printf("evm_call_state_t initialized memory pointer %p thread %d\n", memory_ptr, THREADIDX); + + this->memory_ptr = memory_ptr[INSTANCE_IDX_PER_BLOCK]; + // printf("memory size %d idx %d\n", memory_ptr->size, THREADIDX); + __SHARED_MEMORY__ log_state_data_t* log_state_ptr[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + log_state_ptr[INSTANCE_IDX_PER_BLOCK] = new CuEVM::log_state_data_t(); + __ONE_GPU_THREAD_END__ + this->log_state_ptr = log_state_ptr[INSTANCE_IDX_PER_BLOCK]; + + // printf("evm_call_state_t initialized log state pointer %p thread %d\n", log_state_ptr, THREADIDX); + + __SHARED_MEMORY__ evm_return_data_t* last_return_data_ptr[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + last_return_data_ptr[INSTANCE_IDX_PER_BLOCK] = new CuEVM::evm_return_data_t(); + __ONE_GPU_THREAD_END__ + this->last_return_data_ptr = last_return_data_ptr[INSTANCE_IDX_PER_BLOCK]; + + // printf("evm_call_state_t initialized return data pointer %p thread %d\n", last_return_data_ptr, THREADIDX); + // this->memory_ptr = new CuEVM::evm_memory_t(); + // this->log_state_ptr = new CuEVM::log_state_data_t(); + // this->last_return_data_ptr = new CuEVM::evm_return_data_t(); #ifdef EIP_3155 this->trace_idx = 0; #endif + // printf("evm_call_state_t constructor with parent %d\n", THREADIDX); +} +__host__ __device__ evm_call_state_t::evm_call_state_t(ArithEnv& arith, CuEVM::evm_call_state_t* other) { + this->parent = other->parent; + this->depth = other->depth; + this->pc = other->pc; + cgbn_set(arith.env, this->gas_used, other->gas_used); + cgbn_set(arith.env, this->gas_refund, other->gas_refund); + this->message_ptr = other->message_ptr; + this->message_ptr_copy = other->message_ptr_copy; + this->stack_ptr = other->stack_ptr; + this->memory_ptr = other->memory_ptr; + this->log_state_ptr = other->log_state_ptr; + this->touch_state_ptr = other->touch_state_ptr; + this->last_return_data_ptr = other->last_return_data_ptr; } /** @@ -58,7 +168,13 @@ __host__ __device__ evm_call_state_t::evm_call_state_t(ArithEnv& arith, CuEVM::W CuEVM::log_state_data_t* log_state_ptr, CuEVM::state_access_t* state_access_ptr, CuEVM::evm_return_data_t* last_return_data_ptr) - : touch_state(state_access_ptr, word_state_ptr) { +// : touch_state(state_access_ptr, word_state_ptr) { +{ + __SHARED_MEMORY__ CuEVM::TouchState* touch_state_ptr[CGBN_IBP]; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + touch_state_ptr[INSTANCE_IDX_PER_BLOCK] = new CuEVM::TouchState(state_access_ptr, word_state_ptr); + __ONE_GPU_THREAD_END__ + this->touch_state_ptr = touch_state_ptr[INSTANCE_IDX_PER_BLOCK]; this->parent = nullptr; this->depth = 0; this->pc = 0; @@ -80,14 +196,51 @@ __host__ __device__ evm_call_state_t::evm_call_state_t(ArithEnv& arith, CuEVM::W */ __host__ __device__ evm_call_state_t::~evm_call_state_t() { if (parent != nullptr) { - delete message_ptr; + // delete message_ptr; TODO: fix this, currently using shared mem for message_ptr + // printf("evm_call_state_t destructor thread %d\n", THREADIDX); + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // printf( + // "evm_call_state_t destructor thread %d message ptr %p stack ptr %p memory ptr %p log state ptr %p last " + // "return data ptr %p\n", + // THREADIDX, message_ptr, stack_ptr, memory_ptr, log_state_ptr, last_return_data_ptr); + // __ONE_GPU_THREAD_WOSYNC_END__ + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + delete message_ptr_copy; delete stack_ptr; delete memory_ptr; delete log_state_ptr; delete last_return_data_ptr; + // TODO delete touch_state_ptr; + __ONE_GPU_THREAD_WOSYNC_END__ + // printf("evm_call_state_t done destructor thread %d\n", THREADIDX); } } +__host__ __device__ void evm_call_state_t::print(ArithEnv& arith) const { + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + printf("EVM Call State\n"); + printf("Depth: %d\n", depth); + printf("PC: %d\n", pc); + printf("Gas Used: \n"); + printf("Gas Refund: \n"); + printf("Gas Limit: \n"); + __ONE_GPU_THREAD_WOSYNC_END__ + print_bnt(arith, gas_used); + print_bnt(arith, gas_refund); + print_bnt(arith, gas_limit); + + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + printf("Message pointer: %p\n", message_ptr); + printf("Stack pointer: %p\n", stack_ptr); + printf("Memory pointer: %p\n", memory_ptr); + printf("Log state pointer: %p\n", log_state_ptr); + // printf("Touch state\n"); + // touch_state.print(); + printf("Last return data pointer: %p\n", last_return_data_ptr); + printf("\n"); + __ONE_GPU_THREAD_WOSYNC_END__ +} + __host__ __device__ int32_t evm_call_state_t::update(ArithEnv& arith, evm_call_state_t& other) { uint32_t error_code = ERROR_SUCCESS; // printf("\n\ntouch state update \n"); @@ -98,7 +251,7 @@ __host__ __device__ int32_t evm_call_state_t::update(ArithEnv& arith, evm_call_s // other.touch_state.print(); // printf("\n------------------\n\n"); - error_code |= this->touch_state.update(arith, &other.touch_state); + error_code |= this->touch_state_ptr->update(arith, other.touch_state_ptr); // printf("touch state update done \n"); // printf("this touch state \n"); // this->touch_state.print(); diff --git a/CuEVM/src/gas_cost.cu b/CuEVM/src/gas_cost.cu index bb800ae..54eec30 100644 --- a/CuEVM/src/gas_cost.cu +++ b/CuEVM/src/gas_cost.cu @@ -184,7 +184,7 @@ __host__ __device__ void ecpairing_cost(ArithEnv &arith, bn_t &gas_used, uint32_ } __host__ __device__ int32_t access_account_cost(ArithEnv &arith, bn_t &gas_used, CuEVM::TouchState &touch_state, - const bn_t &address) { + const evm_word_t *address) { if (touch_state.is_warm_account(arith, address)) { cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_WARM_ACCESS); } else { @@ -198,7 +198,7 @@ __host__ __device__ int32_t access_account_cost(ArithEnv &arith, bn_t &gas_used, } __host__ __device__ int32_t sload_cost(ArithEnv &arith, bn_t &gas_used, const CuEVM::TouchState &touch_state, - const bn_t &address, const bn_t &key) { + const evm_word_t *address, const bn_t &key) { // get the key warm if (touch_state.is_warm_key(arith, address, key)) { cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_WARM_ACCESS); @@ -209,8 +209,8 @@ __host__ __device__ int32_t sload_cost(ArithEnv &arith, bn_t &gas_used, const Cu return ERROR_SUCCESS; } __host__ __device__ int32_t sstore_cost(ArithEnv &arith, bn_t &gas_used, bn_t &gas_refund, - const CuEVM::TouchState &touch_state, const bn_t &address, const bn_t &key, - const bn_t &new_value) { + const CuEVM::TouchState &touch_state, const evm_word_t *address, + const bn_t &key, const bn_t &new_value) { // get the key warm if (touch_state.is_warm_key(arith, address, key) == false) { // #ifdef __CUDA_ARCH__ @@ -281,15 +281,13 @@ __host__ __device__ int32_t transaction_intrinsic_gas(ArithEnv &arith, const CuE } } - // if transaction type is 1 it might have access list - if (transaction.type == 1) { - // gas_intrinsic += GAS_ACCESS_LIST_ADDRESS/GAS_ACCESS_LIST_STORAGE for - // each address in transaction.access_list - for (uint32_t idx = 0; idx < transaction.access_list.accounts_count; idx++) { - cgbn_add_ui32(arith.env, gas_intrinsic, gas_intrinsic, GAS_ACCESS_LIST_ADDRESS); - cgbn_add_ui32(arith.env, gas_intrinsic, gas_intrinsic, - GAS_ACCESS_LIST_STORAGE * transaction.access_list.accounts[idx].storage_keys_count); - } + // gas_intrinsic += GAS_ACCESS_LIST_ADDRESS/GAS_ACCESS_LIST_STORAGE for + // each address in transaction.access_list + + for (uint32_t idx = 0; idx < transaction.access_list.accounts_count; idx++) { + cgbn_add_ui32(arith.env, gas_intrinsic, gas_intrinsic, GAS_ACCESS_LIST_ADDRESS); + cgbn_add_ui32(arith.env, gas_intrinsic, gas_intrinsic, + GAS_ACCESS_LIST_STORAGE * transaction.access_list.accounts[idx].storage_keys_count); } #ifdef EIP_3860 diff --git a/CuEVM/src/operations/environmental.cu b/CuEVM/src/operations/environmental.cu index 8f06c02..52ee0ab 100644 --- a/CuEVM/src/operations/environmental.cu +++ b/CuEVM/src/operations/environmental.cu @@ -33,13 +33,16 @@ __host__ __device__ int32_t SHA3(ArithEnv &arith, const bn_t &gas_limit, bn_t &g CuEVM::byte_array_t memory_input; error_code |= memory.get(arith, offset, length, memory_input); if (error_code == ERROR_SUCCESS) { - CuEVM::byte_array_t *hash; - hash = new CuEVM::byte_array_t(CuEVM::hash_size); - CuCrypto::keccak::sha3(memory_input.data, memory_input.size, hash->data, hash->size); - bn_t hash_bn; - error_code |= cgbn_set_byte_array_t(arith.env, hash_bn, *hash); - delete hash; - error_code |= stack.push(arith, hash_bn); + // CuEVM::byte_array_t *hash; + // hash = new CuEVM::byte_array_t(CuEVM::hash_size); + // CuCrypto::keccak::sha3(memory_input.data, memory_input.size, hash->data, hash->size); + // bn_t hash_bn; + // error_code |= cgbn_set_byte_array_t(arith.env, hash_bn, *hash); + // delete hash; + // error_code |= stack.push(arith, hash_bn); + uint8_t hash_data[CuEVM::hash_size]; + CuCrypto::keccak::sha3(memory_input.data, memory_input.size, hash_data, CuEVM::hash_size); + error_code |= stack.pushx(arith, CuEVM::word_size, hash_data, CuEVM::hash_size); } } } @@ -65,12 +68,15 @@ __host__ __device__ int32_t BALANCE(ArithEnv &arith, const bn_t &gas_limit, bn_t bn_t address; int32_t error_code = stack.pop(arith, address); CuEVM::evm_address_conversion(arith, address); - error_code |= CuEVM::gas_cost::access_account_cost(arith, gas_used, touch_state, address); + __SHARED_MEMORY__ evm_word_t address_shared[CGBN_IBP]; + cgbn_store(arith.env, &address_shared[INSTANCE_IDX_PER_BLOCK], address); + error_code |= + CuEVM::gas_cost::access_account_cost(arith, gas_used, touch_state, &address_shared[INSTANCE_IDX_PER_BLOCK]); error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); if (error_code == ERROR_SUCCESS) { bn_t balance; - touch_state.get_balance(arith, address, balance); + touch_state.get_balance(arith, &address_shared[INSTANCE_IDX_PER_BLOCK], balance); error_code |= stack.push(arith, balance); } @@ -126,6 +132,8 @@ __host__ __device__ int32_t CALLDATALOAD(ArithEnv &arith, const bn_t &gas_limit, uint32_t data_offset_ui32, length_ui32; // get values saturated to uint32_max, in overflow case data_offset_ui32 = cgbn_get_ui32(arith.env, index); + // printf("CALLDATALOAD: error_code: %d data_length %d idx %d\n", error_code, message.get_data().size, + // data_offset_ui32); if (cgbn_compare_ui32(arith.env, index, data_offset_ui32) != 0) data_offset_ui32 = UINT32_MAX; length_ui32 = CuEVM::word_size; CuEVM::byte_array_t data = CuEVM::byte_array_t(message.get_data(), data_offset_ui32, length_ui32); @@ -248,11 +256,13 @@ __host__ __device__ int32_t EXTCODESIZE(ArithEnv &arith, const bn_t &gas_limit, bn_t address; int32_t error_code = stack.pop(arith, address); CuEVM::evm_address_conversion(arith, address); - CuEVM::gas_cost::access_account_cost(arith, gas_used, touch_state, address); + __SHARED_MEMORY__ evm_word_t address_shared[CGBN_IBP]; + cgbn_store(arith.env, &address_shared[INSTANCE_IDX_PER_BLOCK], address); + CuEVM::gas_cost::access_account_cost(arith, gas_used, touch_state, &address_shared[INSTANCE_IDX_PER_BLOCK]); error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); CuEVM::byte_array_t byte_code; // error_code |= - touch_state.get_code(arith, address, byte_code); + touch_state.get_code(arith, &address_shared[INSTANCE_IDX_PER_BLOCK], byte_code); bn_t code_size; cgbn_set_ui32(arith.env, code_size, byte_code.size); error_code |= stack.push(arith, code_size); @@ -266,7 +276,10 @@ __host__ __device__ int32_t EXTCODECOPY(ArithEnv &arith, const bn_t &gas_limit, bn_t address, memory_offset, code_offset, length; int32_t error_code = stack.pop(arith, address); + // TODO implement stack.pop_address; CuEVM::evm_address_conversion(arith, address); + __SHARED_MEMORY__ evm_word_t address_shared[CGBN_IBP]; + cgbn_store(arith.env, &address_shared[INSTANCE_IDX_PER_BLOCK], address); error_code |= stack.pop(arith, memory_offset); error_code |= stack.pop(arith, code_offset); error_code |= stack.pop(arith, length); @@ -278,7 +291,7 @@ __host__ __device__ int32_t EXTCODECOPY(ArithEnv &arith, const bn_t &gas_limit, bn_t memory_expansion_cost; error_code |= CuEVM::gas_cost::memory_grow_cost(arith, memory, memory_offset, length, memory_expansion_cost, gas_used); - CuEVM::gas_cost::access_account_cost(arith, gas_used, touch_state, address); + CuEVM::gas_cost::access_account_cost(arith, gas_used, touch_state, &address_shared[INSTANCE_IDX_PER_BLOCK]); error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); @@ -286,7 +299,7 @@ __host__ __device__ int32_t EXTCODECOPY(ArithEnv &arith, const bn_t &gas_limit, memory.increase_memory_cost(arith, memory_expansion_cost); CuEVM::byte_array_t byte_code; // error_code |= - touch_state.get_code(arith, address, byte_code); + touch_state.get_code(arith, &address_shared[INSTANCE_IDX_PER_BLOCK], byte_code); uint32_t data_offset_ui32, length_ui32; // get values saturated to uint32_max, in overflow case @@ -369,19 +382,28 @@ __host__ __device__ int32_t EXTCODEHASH(ArithEnv &arith, const bn_t &gas_limit, bn_t address; int32_t error_code = stack.pop(arith, address); CuEVM::evm_address_conversion(arith, address); - CuEVM::gas_cost::access_account_cost(arith, gas_used, touch_state, address); + printf("ext code hash Thread %d\n", THREADIDX); + print_bnt(arith, address); + __SHARED_MEMORY__ evm_word_t address_shared[CGBN_IBP]; + cgbn_store(arith.env, &address_shared[INSTANCE_IDX_PER_BLOCK], address); + address_shared[INSTANCE_IDX_PER_BLOCK].print(); + CuEVM::gas_cost::access_account_cost(arith, gas_used, touch_state, &address_shared[INSTANCE_IDX_PER_BLOCK]); error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); - bn_t hash_bn; - if ((touch_state.is_empty_account(arith, address)) || touch_state.is_deleted_account(arith, address)) { - cgbn_set_ui32(arith.env, hash_bn, 0); + // bn_t hash_bn; + if ((touch_state.is_empty_account(arith, &address_shared[INSTANCE_IDX_PER_BLOCK])) || + touch_state.is_deleted_account(arith, &address_shared[INSTANCE_IDX_PER_BLOCK])) { + // cgbn_set_ui32(arith.env, hash_bn, 0); + address_shared[INSTANCE_IDX_PER_BLOCK].set_zero(); } else { CuEVM::byte_array_t byte_code; - error_code |= touch_state.get_code(arith, address, byte_code); + error_code |= touch_state.get_code(arith, &address_shared[INSTANCE_IDX_PER_BLOCK], byte_code); CuEVM::byte_array_t hash(CuEVM::hash_size); CuCrypto::keccak::sha3(byte_code.data, byte_code.size, hash.data, hash.size); - error_code |= cgbn_set_byte_array_t(arith.env, hash_bn, hash); + // error_code |= cgbn_set_byte_array_t(arith.env, hash_bn, hash); + address_shared[INSTANCE_IDX_PER_BLOCK].from_byte_array_t(hash, BIG_ENDIAN); } - error_code |= stack.push(arith, hash_bn); + // result is in address_shared[INSTANCE_IDX_PER_BLOCK] + error_code |= stack.push_evm_word_t(arith, &address_shared[INSTANCE_IDX_PER_BLOCK]); return error_code; } @@ -389,12 +411,12 @@ __host__ __device__ int32_t SELFBALANCE(ArithEnv &arith, const bn_t &gas_limit, CuEVM::evm_stack_t &stack, CuEVM::TouchState &touch_state, const CuEVM::evm_message_call_t &message) { cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_LOW); - bn_t address; - message.get_recipient(arith, address); + // bn_t address; + // message.get_recipient(arith, address); int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); if (error_code == ERROR_SUCCESS) { bn_t balance; - touch_state.get_balance(arith, address, balance); + touch_state.get_balance(arith, &message.recipient, balance); error_code |= stack.push(arith, balance); } diff --git a/CuEVM/src/operations/flow.cu b/CuEVM/src/operations/flow.cu index afb3f36..6e20bba 100644 --- a/CuEVM/src/operations/flow.cu +++ b/CuEVM/src/operations/flow.cu @@ -4,124 +4,105 @@ // Data: 2023-11-30 // SPDX-License-Identifier: MIT -#include #include +#include #include - +#include namespace CuEVM::operations { - __host__ __device__ int32_t JUMP( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - uint32_t &pc, - CuEVM::evm_stack_t &stack, - const CuEVM::evm_message_call_t &message) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_MID); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - if (error_code == ERROR_SUCCESS) - { - bn_t destination; - error_code |= stack.pop(arith, destination); - uint32_t destination_u32; - error_code = cgbn_get_uint32_t(arith.env, destination_u32, destination) == ERROR_VALUE_OVERFLOW ? ERROR_INVALID_JUMP_DESTINATION : error_code; - if (error_code == ERROR_SUCCESS) - { - pc = message.get_jump_destinations()->has(destination_u32) == ERROR_SUCCESS ? destination_u32 - 1 : ([&]() -> uint32_t { - error_code = ERROR_INVALID_JUMP_DESTINATION; - return pc; - })(); - } +__host__ __device__ int32_t JUMP(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, uint32_t &pc, + CuEVM::evm_stack_t &stack, const CuEVM::evm_message_call_t &message) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_MID); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + if (error_code == ERROR_SUCCESS) { + bn_t destination; + error_code |= stack.pop(arith, destination); + uint32_t destination_u32; + error_code = cgbn_get_uint32_t(arith.env, destination_u32, destination) == ERROR_VALUE_OVERFLOW + ? ERROR_INVALID_JUMP_DESTINATION + : error_code; + if ((destination_u32 >= message.byte_code->size) || (message.byte_code->data[destination_u32] != OP_JUMPDEST)) { + return ERROR_INVALID_JUMP_DESTINATION; + } + + if (error_code == ERROR_SUCCESS) { + pc = message.jump_destinations->has(destination_u32) == ERROR_SUCCESS + ? destination_u32 - 1 + : ([&]() -> uint32_t { + error_code = ERROR_INVALID_JUMP_DESTINATION; + return pc; + })(); } - return error_code; } + return error_code; +} - __host__ __device__ int32_t JUMPI( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - uint32_t &pc, - CuEVM::evm_stack_t &stack, - const CuEVM::evm_message_call_t &message) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_HIGH); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - if (error_code == ERROR_SUCCESS) - { - bn_t destination; - error_code |= stack.pop(arith, destination); - bn_t condition; - error_code |= stack.pop(arith, condition); +__host__ __device__ int32_t JUMPI(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, uint32_t &pc, + CuEVM::evm_stack_t &stack, const CuEVM::evm_message_call_t &message +#ifdef BUILD_LIBRARY + , + CuEVM::utils::simplified_trace_data *simplified_trace_data_ptr +#endif +) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_HIGH); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + if (error_code == ERROR_SUCCESS) { + bn_t destination; + error_code |= stack.pop(arith, destination); + bn_t condition; + error_code |= stack.pop(arith, condition); + uint32_t destination_u32; + error_code = cgbn_get_uint32_t(arith.env, destination_u32, destination) == ERROR_VALUE_OVERFLOW + ? ERROR_INVALID_JUMP_DESTINATION + : error_code; + if ((error_code == ERROR_SUCCESS) && (cgbn_compare_ui32(arith.env, condition, 0) != 0)) { +#ifdef BUILD_LIBRARY + simplified_trace_data_ptr->record_branch(pc, destination_u32, pc + 1); +#endif - if ( - (error_code == ERROR_SUCCESS) && - (cgbn_compare_ui32(arith.env, condition, 0) != 0) - ) { - uint32_t destination_u32; - error_code = cgbn_get_uint32_t(arith.env, destination_u32, destination) == ERROR_VALUE_OVERFLOW ? ERROR_INVALID_JUMP_DESTINATION : error_code; - if (error_code == ERROR_SUCCESS) - { - pc = message.get_jump_destinations()->has(destination_u32) == ERROR_SUCCESS ? destination_u32 - 1 : ([&]() -> uint32_t { - error_code = ERROR_INVALID_JUMP_DESTINATION; - return pc; - })(); - } + if ((destination_u32 >= message.byte_code->size) || + (message.byte_code->data[destination_u32] != OP_JUMPDEST)) { + return ERROR_INVALID_JUMP_DESTINATION; } + if (error_code == ERROR_SUCCESS) { + pc = message.jump_destinations->has(destination_u32) == ERROR_SUCCESS + ? destination_u32 - 1 + : ([&]() -> uint32_t { + error_code = ERROR_INVALID_JUMP_DESTINATION; + return pc; + })(); + } + } +#ifdef BUILD_LIBRARY + else { + simplified_trace_data_ptr->record_branch(pc, pc + 1, destination_u32); } - return error_code; +#endif } + return error_code; +} - __host__ __device__ int32_t PC( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - const uint32_t &pc, - CuEVM::evm_stack_t &stack) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_BASE); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - bn_t pc_bn; - cgbn_set_ui32(arith.env, pc_bn, pc); - error_code |= stack.push(arith, pc_bn); - return error_code; - } +__host__ __device__ int32_t PC(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, const uint32_t &pc, + CuEVM::evm_stack_t &stack) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_BASE); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + bn_t pc_bn; + cgbn_set_ui32(arith.env, pc_bn, pc); + error_code |= stack.push(arith, pc_bn); + return error_code; +} - __host__ __device__ int32_t GAS( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_BASE); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - bn_t gas_left; - cgbn_sub(arith.env, gas_left, gas_limit, gas_used); - error_code |= stack.push(arith, gas_left); - return error_code; - } +__host__ __device__ int32_t GAS(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_stack_t &stack) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_BASE); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + bn_t gas_left; + cgbn_sub(arith.env, gas_left, gas_limit, gas_used); + error_code |= stack.push(arith, gas_left); + return error_code; +} - __host__ __device__ int32_t JUMPDEST( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_JUMP_DEST); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - return error_code; - } -} \ No newline at end of file +__host__ __device__ int32_t JUMPDEST(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_JUMP_DEST); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + return error_code; +} +} // namespace CuEVM::operations \ No newline at end of file diff --git a/CuEVM/src/operations/memory.cu b/CuEVM/src/operations/memory.cu index 4a6f078..c8e52be 100644 --- a/CuEVM/src/operations/memory.cu +++ b/CuEVM/src/operations/memory.cu @@ -25,13 +25,25 @@ __host__ __device__ int32_t MLOAD(ArithEnv &arith, const bn_t &gas_limit, bn_t & error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); if (error_code == ERROR_SUCCESS) { + __SHARED_MEMORY__ evm_word_t value_word[CGBN_IBP]; memory.increase_memory_cost(arith, memory_expansion_cost); CuEVM::byte_array_t data; error_code |= memory.get(arith, memory_offset, length, data); - - bn_t value; - error_code |= cgbn_set_byte_array_t(arith.env, value, data); - error_code |= stack.push(arith, value); + // printf("MLOAD ERROR_SUCCESS %d\n", THREADIDX); + // bn_t value; + value_word[INSTANCE_IDX_PER_BLOCK].from_byte_array_t(data, BIG_ENDIAN); + // __ONE_GPU_THREAD_WOSYNC_BEGIN__ + // if (INSTANCE_IDX_PER_BLOCK == 1) { + // printf("MLOAD before push %d\n", THREADIDX); + // value_word[INSTANCE_IDX_PER_BLOCK].print(); + // data.print(); + // } + // __ONE_GPU_THREAD_WOSYNC_END__ + // error_code |= cgbn_set_byte_array_t(arith.env, value, data); + // printf("MLOAD before push %d\n", THREADIDX); + error_code |= stack.push_evm_word_t(arith, &value_word[INSTANCE_IDX_PER_BLOCK]); + // error_code |= stack.push(arith, value); + // printf("MLOAD push %d\n", THREADIDX); } return error_code; } @@ -45,7 +57,6 @@ __host__ __device__ int32_t MSTORE(ArithEnv &arith, const bn_t &gas_limit, bn_t error_code |= stack.pop(arith, memory_offset); bn_t value; error_code |= stack.pop(arith, value); - bn_t length; cgbn_set_ui32(arith.env, length, CuEVM::word_size); @@ -59,10 +70,13 @@ __host__ __device__ int32_t MSTORE(ArithEnv &arith, const bn_t &gas_limit, bn_t if (error_code == ERROR_SUCCESS) { memory.increase_memory_cost(arith, memory_expansion_cost); CuEVM::byte_array_t value_bytes(CuEVM::word_size); - __SHARED_MEMORY__ evm_word_t value_word; - cgbn_store(arith.env, (cgbn_evm_word_t_ptr)&value_word, value); + // printf("MSTORE %d %d instanceid %d\n", THREADIDX, THREAD_IDX_PER_INSTANCE, INSTANCE_IDX_PER_BLOCK); + // printf("byte array after construction size %d data %p threadidx %d\n", value_bytes.size, value_bytes.data, + // THREADIDX); + __SHARED_MEMORY__ evm_word_t value_word[CGBN_IBP]; + cgbn_store(arith.env, (cgbn_evm_word_t_ptr)&value_word[INSTANCE_IDX_PER_BLOCK], value); - value_word.to_byte_array_t(value_bytes); + value_word[INSTANCE_IDX_PER_BLOCK].to_byte_array_t(value_bytes, BIG_ENDIAN); error_code |= memory.set(arith, value_bytes, memory_offset, length); } @@ -73,7 +87,9 @@ __host__ __device__ int32_t MSTORE8(ArithEnv &arith, const bn_t &gas_limit, bn_t CuEVM::evm_memory_t &memory) { cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_VERY_LOW); int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); - + // #ifdef __CUDA_ARCH__ + // printf("MSTORE8 %d\n", threadIdx.x); + // #endif bn_t memory_offset; error_code |= stack.pop(arith, memory_offset); bn_t value; @@ -90,10 +106,12 @@ __host__ __device__ int32_t MSTORE8(ArithEnv &arith, const bn_t &gas_limit, bn_t if (error_code == ERROR_SUCCESS) { memory.increase_memory_cost(arith, memory_expansion_cost); CuEVM::byte_array_t value_bytes(CuEVM::word_size); + // TODO: bnt directly to byte array - __SHARED_MEMORY__ evm_word_t value_word; - cgbn_store(arith.env, (cgbn_evm_word_t_ptr)&value_word, value); - value_word.to_byte_array_t(value_bytes); + __SHARED_MEMORY__ evm_word_t value_word[CGBN_IBP]; + + cgbn_store(arith.env, (cgbn_evm_word_t_ptr)&value_word[INSTANCE_IDX_PER_BLOCK], value); + value_word[INSTANCE_IDX_PER_BLOCK].to_byte_array_t(value_bytes, BIG_ENDIAN); CuEVM::byte_array_t value_byte(value_bytes.data + CuEVM::word_size - 1, 1); diff --git a/CuEVM/src/operations/stack.cu b/CuEVM/src/operations/stack.cu index 06ee9de..079c60b 100644 --- a/CuEVM/src/operations/stack.cu +++ b/CuEVM/src/operations/stack.cu @@ -4,125 +4,74 @@ // Date: 2023-07-15 // SPDX-License-Identifier: MIT -#include #include +#include #include namespace CuEVM::operations { - __host__ __device__ int32_t POP( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_BASE); +__host__ __device__ int32_t POP(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_stack_t &stack) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_BASE); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - if (error_code == ERROR_SUCCESS) - { - bn_t y; + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + if (error_code == ERROR_SUCCESS) { + bn_t y; - error_code |= stack.pop(arith, y); - } - return error_code; + error_code |= stack.pop(arith, y); } + return error_code; +} - __host__ __device__ int32_t PUSH0( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_BASE); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - if (error_code == ERROR_SUCCESS) - { - bn_t r; - cgbn_set_ui32(arith.env, r, 0); +__host__ __device__ int32_t PUSH0(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_stack_t &stack) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_BASE); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + if (error_code == ERROR_SUCCESS) { + bn_t r; + cgbn_set_ui32(arith.env, r, 0); - error_code |= stack.push(arith, r); - } - return error_code; + error_code |= stack.push(arith, r); } + return error_code; +} - __host__ __device__ int32_t PUSHX( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - uint32_t &pc, - CuEVM::evm_stack_t &stack, - const CuEVM::byte_array_t &byte_code, - const uint8_t &opcode) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_VERY_LOW); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - if (error_code == ERROR_SUCCESS) - { - uint8_t push_size = (opcode & 0x1F) + 1; - uint8_t *byte_data = &(byte_code.data[pc + 1]); - // if pushx is outside code size - uint32_t available_size = (pc + push_size >= byte_code.size) ? - byte_code.size - pc - 1 : push_size; - // TODO: maybe make it a byte array for better transmission - error_code |= stack.pushx( - arith, - push_size, - byte_data, - available_size); +__host__ __device__ int32_t PUSHX(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, uint32_t &pc, + CuEVM::evm_stack_t &stack, const CuEVM::byte_array_t &byte_code, + const uint8_t &opcode) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_VERY_LOW); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + if (error_code == ERROR_SUCCESS) { + uint8_t push_size = (opcode & 0x1F) + 1; + uint8_t *byte_data = &(byte_code.data[pc + 1]); + // if pushx is outside code size + uint32_t available_size = (pc + push_size >= byte_code.size) ? byte_code.size - pc - 1 : push_size; + // TODO: maybe make it a byte array for better transmission + error_code |= stack.pushx(arith, push_size, byte_data, available_size); - pc = pc + push_size; - } - return error_code; + pc = pc + push_size; } + return error_code; +} - __host__ __device__ int32_t DUPX( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack, - const uint8_t &opcode) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_VERY_LOW); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - if (error_code == ERROR_SUCCESS) - { - uint8_t dup_index = (opcode & 0x0F) + 1; +__host__ __device__ int32_t DUPX(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_stack_t &stack, + const uint8_t &opcode) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_VERY_LOW); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + if (error_code == ERROR_SUCCESS) { + uint8_t dup_index = (opcode & 0x0F) + 1; - error_code |= stack.dupx(arith, dup_index); - } - return error_code; + error_code |= stack.dupx(arith, dup_index); } + return error_code; +} - __host__ __device__ int32_t SWAPX( - ArithEnv &arith, - const bn_t &gas_limit, - bn_t &gas_used, - CuEVM::evm_stack_t &stack, - const uint8_t &opcode) - { - cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_VERY_LOW); - int32_t error_code = CuEVM::gas_cost::has_gas( - arith, - gas_limit, - gas_used); - if (error_code == ERROR_SUCCESS) - { - uint8_t swap_index = (opcode & 0x0F) + 1; +__host__ __device__ int32_t SWAPX(ArithEnv &arith, const bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_stack_t &stack, + const uint8_t &opcode) { + cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_VERY_LOW); + int32_t error_code = CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); + if (error_code == ERROR_SUCCESS) { + uint8_t swap_index = (opcode & 0x0F) + 1; - error_code |= stack.swapx(arith, swap_index); - } - return error_code; + error_code |= stack.swapx(arith, swap_index); } -} \ No newline at end of file + return error_code; +} +} // namespace CuEVM::operations \ No newline at end of file diff --git a/CuEVM/src/operations/storage.cu b/CuEVM/src/operations/storage.cu index 5408ba1..16e9db1 100644 --- a/CuEVM/src/operations/storage.cu +++ b/CuEVM/src/operations/storage.cu @@ -13,16 +13,16 @@ __host__ __device__ int32_t SLOAD(ArithEnv &arith, const bn_t &gas_limit, bn_t & // cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_ZERO); bn_t key; int32_t error_code = stack.pop(arith, key); - bn_t storage_address; - message.get_storage_address(arith, storage_address); - error_code |= CuEVM::gas_cost::sload_cost(arith, gas_used, touch_state, storage_address, key); + // bn_t storage_address; + // message.get_storage_address(arith, storage_address); + error_code |= CuEVM::gas_cost::sload_cost(arith, gas_used, touch_state, &message.storage_address, key); error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); // #ifdef __CUDA_ARCH__ // printf("SLOAD %d error_code: %d\n", threadIdx.x, error_code); // #endif if (error_code == ERROR_SUCCESS) { bn_t value; - error_code |= touch_state.get_value(arith, storage_address, key, value); + error_code |= touch_state.get_value(arith, &message.storage_address, key, value); error_code |= stack.push(arith, value); } return error_code; @@ -44,16 +44,12 @@ __host__ __device__ int32_t SSTORE(ArithEnv &arith, const bn_t &gas_limit, bn_t error_code |= stack.pop(arith, key); bn_t value; error_code |= stack.pop(arith, value); - bn_t storage_address; - message.get_storage_address(arith, storage_address); - // #ifdef __CUDA_ARCH__ - // printf("SSTORE %d\n", threadIdx.x); - // print_bnt(arith, key); - // print_bnt(arith, value); - // print_bnt(arith, storage_address); - // #endif - error_code |= CuEVM::gas_cost::sstore_cost(arith, gas_used, gas_refund, touch_state, storage_address, key, value); + // bn_t storage_address; + // message.get_storage_address(arith, storage_address); + error_code |= + CuEVM::gas_cost::sstore_cost(arith, gas_used, gas_refund, touch_state, &message.storage_address, key, value); error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); - return (error_code ? error_code : touch_state.set_storage_value(arith, storage_address, key, value)); + + return (error_code ? error_code : touch_state.set_storage_value(arith, &message.storage_address, key, value)); } } // namespace CuEVM::operations \ No newline at end of file diff --git a/CuEVM/src/operations/system.cu b/CuEVM/src/operations/system.cu index cdb5c26..245271f 100644 --- a/CuEVM/src/operations/system.cu +++ b/CuEVM/src/operations/system.cu @@ -15,10 +15,14 @@ namespace CuEVM::operations { */ __host__ __device__ int32_t generic_CALL(ArithEnv &arith, const bn_t &args_offset, const bn_t &args_size, CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t *&new_state_ptr) { + CuEVM::evm_call_state_t *&new_state_ptr, + CuEVM::cached_evm_call_state &cached_state) { // try to send value in call bn_t value; new_state_ptr->message_ptr->get_value(arith, value); + // #ifdef __CUDA_ARCH__ + // printf("generic_CALL message_ptr->get_value %d\n", threadIdx.x); + // #endif int32_t error_code = ((new_state_ptr->message_ptr->get_static_env() && (cgbn_compare_ui32(arith.env, value, 0) != 0) && (new_state_ptr->message_ptr->get_call_type() == OP_CALL)) @@ -29,7 +33,7 @@ __host__ __device__ int32_t generic_CALL(ArithEnv &arith, const bn_t &args_offse // #ifdef __CUDA_ARCH__ // printf("Before memory_grow_cost %d\n", threadIdx.x); // __SYNC_THREADS__ - // print_bnt(arith, current_state.gas_used); + // print_bnt(arith, cached_state.gas_used); // #endif // memory call data bn_t memory_expansion_cost_args; @@ -42,6 +46,14 @@ __host__ __device__ int32_t generic_CALL(ArithEnv &arith, const bn_t &args_offse error_code |= CuEVM::gas_cost::memory_grow_cost(arith, *current_state.memory_ptr, args_offset, args_size, memory_expansion_cost_args, temp_memory_gas_used); + + // printf("generic_CALL memory_expansion_cost_args idx %d error_code %d mempointer %p memsize %d\n", THREADIDX, + // error_code, current_state.memory_ptr, current_state.memory_ptr->size); + // __SYNC_THREADS__ + // print_bnt(arith, temp_memory_gas_used); + // print_bnt(arith, args_offset); + // print_bnt(arith, args_size); + // memory return data bn_t ret_offset, ret_size; new_state_ptr->message_ptr->get_return_data_offset(arith, ret_offset); @@ -50,6 +62,14 @@ __host__ __device__ int32_t generic_CALL(ArithEnv &arith, const bn_t &args_offse error_code |= CuEVM::gas_cost::memory_grow_cost(arith, *current_state.memory_ptr, ret_offset, ret_size, memory_expansion_cost_ret, temp_memory_gas_used); + // #ifdef __CUDA_ARCH__ + // printf("generic_CALL memory_expansion_cost_ret idx %d error_code %d mempointer %p memsize %d\n", threadIdx.x, + // error_code, current_state.memory_ptr, current_state.memory_ptr->size); + // __SYNC_THREADS__ + // print_bnt(arith, temp_memory_gas_used); + // print_bnt(arith, ret_offset); + // print_bnt(arith, ret_size); + // #endif // compute the total memory expansion cost bn_t memory_expansion_cost; if (cgbn_compare(arith.env, memory_expansion_cost_args, memory_expansion_cost_ret) > 0) { @@ -57,56 +77,58 @@ __host__ __device__ int32_t generic_CALL(ArithEnv &arith, const bn_t &args_offse } else { cgbn_set(arith.env, memory_expansion_cost, memory_expansion_cost_ret); } - cgbn_add(arith.env, current_state.gas_used, current_state.gas_used, memory_expansion_cost); + cgbn_add(arith.env, cached_state.gas_used, cached_state.gas_used, memory_expansion_cost); // #ifdef __CUDA_ARCH__ // printf("after memory_grow_cost %d\n", threadIdx.x); // __SYNC_THREADS__ - // print_bnt(arith, current_state.gas_used); + // print_bnt(arith, cached_state.gas_used); // #endif // adress warm call - bn_t contract_address; - new_state_ptr->message_ptr->get_contract_address(arith, contract_address); - CuEVM::gas_cost::access_account_cost(arith, current_state.gas_used, current_state.touch_state, contract_address); + // bn_t contract_address; + evm_word_t *contract_address_ptr = &new_state_ptr->message_ptr->contract_address; + // new_state_ptr->message_ptr->get_contract_address(arith, contract_address); + CuEVM::gas_cost::access_account_cost(arith, cached_state.gas_used, *current_state.touch_state_ptr, + contract_address_ptr); // positive value call cost (except delegate call) // empty account call cost // #ifdef __CUDA_ARCH__ // printf("After access_account_cost cost %d\n", threadIdx.x); // __SYNC_THREADS__ - // print_bnt(arith, current_state.gas_used); + // print_bnt(arith, cached_state.gas_used); // #endif bn_t gas_stippend; cgbn_set_ui32(arith.env, gas_stippend, 0); if (new_state_ptr->message_ptr->get_call_type() != OP_DELEGATECALL) { if (cgbn_compare_ui32(arith.env, value, 0) > 0) { - cgbn_add_ui32(arith.env, current_state.gas_used, current_state.gas_used, GAS_CALL_VALUE); + cgbn_add_ui32(arith.env, cached_state.gas_used, cached_state.gas_used, GAS_CALL_VALUE); cgbn_set_ui32(arith.env, gas_stippend, GAS_CALL_STIPEND); // If the empty account is called // only for call opcode - if ((new_state_ptr->touch_state.is_empty_account(arith, contract_address)) && + if ((new_state_ptr->touch_state_ptr->is_empty_account(arith, contract_address_ptr)) && (new_state_ptr->message_ptr->get_call_type() == OP_CALL)) { - cgbn_add_ui32(arith.env, current_state.gas_used, current_state.gas_used, GAS_NEW_ACCOUNT); + cgbn_add_ui32(arith.env, cached_state.gas_used, cached_state.gas_used, GAS_NEW_ACCOUNT); }; } } // max gas call, gas_sent_with_call bn_t gas_capped; - CuEVM::gas_cost::max_gas_call(arith, gas_capped, current_state.gas_limit, current_state.gas_used); + CuEVM::gas_cost::max_gas_call(arith, gas_capped, cached_state.gas_limit, cached_state.gas_used); // limit the gas to the gas capped if (cgbn_compare(arith.env, new_state_ptr->gas_limit, gas_capped) > 0) { cgbn_set(arith.env, new_state_ptr->gas_limit, gas_capped); } // add the the gas sent to the gas used - cgbn_add(arith.env, current_state.gas_used, current_state.gas_used, new_state_ptr->gas_limit); + cgbn_add(arith.env, cached_state.gas_used, cached_state.gas_used, new_state_ptr->gas_limit); // Gas stipen 2300 is added to the total gas limit but not gas used // add the gas stippend to gas limit of the child call cgbn_add(arith.env, new_state_ptr->gas_limit, new_state_ptr->gas_limit, gas_stippend); - error_code |= CuEVM::gas_cost::has_gas(arith, current_state.gas_limit, current_state.gas_used); + error_code |= CuEVM::gas_cost::has_gas(arith, cached_state.gas_limit, cached_state.gas_used); if (error_code == ERROR_SUCCESS) { // increase the memory cost @@ -120,8 +142,11 @@ __host__ __device__ int32_t generic_CALL(ArithEnv &arith, const bn_t &args_offse // contract->byte_code); // get/set the call data - error_code |= current_state.memory_ptr->get(arith, args_offset, args_size, new_state_ptr->message_ptr->data); + error_code |= current_state.memory_ptr->get(arith, args_offset, args_size, *new_state_ptr->message_ptr->data); } + // #ifdef __CUDA_ARCH__ + // printf("generic_CALL error_code: %d idx %d\n", error_code, threadIdx.x); + // #endif return error_code; } @@ -133,35 +158,36 @@ __host__ __device__ int32_t generic_CALL(ArithEnv &arith, const bn_t &args_offse * @return 0 if the operation is successful, otherwise the error code. */ __host__ __device__ int32_t generic_CREATE(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t *&new_state_ptr, const uint32_t opcode) { + CuEVM::evm_call_state_t *&new_state_ptr, const uint32_t opcode, + cached_evm_call_state &cached_state) { bn_t value, memory_offset, length; - int32_t error_code = current_state.stack_ptr->pop(arith, value); - error_code |= current_state.stack_ptr->pop(arith, memory_offset); - error_code |= current_state.stack_ptr->pop(arith, length); + int32_t error_code = cached_state.stack_ptr->pop(arith, value); + error_code |= cached_state.stack_ptr->pop(arith, memory_offset); + error_code |= cached_state.stack_ptr->pop(arith, length); // create cost - cgbn_add_ui32(arith.env, current_state.gas_used, current_state.gas_used, GAS_CREATE); + cgbn_add_ui32(arith.env, cached_state.gas_used, cached_state.gas_used, GAS_CREATE); // compute the memory cost bn_t memory_expansion_cost; error_code |= CuEVM::gas_cost::memory_grow_cost(arith, *current_state.memory_ptr, memory_offset, length, - memory_expansion_cost, current_state.gas_used); + memory_expansion_cost, cached_state.gas_used); // compute the initcode gas cost - CuEVM::gas_cost::initcode_cost(arith, current_state.gas_used, length); + CuEVM::gas_cost::initcode_cost(arith, cached_state.gas_used, length); bn_t salt; if (opcode == OP_CREATE2) { - error_code |= current_state.stack_ptr->pop(arith, salt); + error_code |= cached_state.stack_ptr->pop(arith, salt); // compute the keccak gas cost - CuEVM::gas_cost::keccak_cost(arith, current_state.gas_used, length); + CuEVM::gas_cost::keccak_cost(arith, cached_state.gas_used, length); } // #ifdef __CUDA_ARCH__ // printf("Before has_gas %d error code %d\n", threadIdx.x, error_code); - // print_bnt(arith, current_state.gas_limit); - // print_bnt(arith, current_state.gas_used); + // print_bnt(arith, cached_state.gas_limit); + // print_bnt(arith, cached_state.gas_used); // #endif - error_code |= CuEVM::gas_cost::has_gas(arith, current_state.gas_limit, current_state.gas_used); + error_code |= CuEVM::gas_cost::has_gas(arith, cached_state.gas_limit, cached_state.gas_used); if (error_code == ERROR_SUCCESS) { // increase the memory cost @@ -181,47 +207,66 @@ __host__ __device__ int32_t generic_CREATE(ArithEnv &arith, CuEVM::evm_call_stat // #endif bn_t sender_address; current_state.message_ptr->get_recipient(arith, sender_address); + const evm_word_t *sender_address_ptr = ¤t_state.message_ptr->recipient; bn_t contract_address; // // warm up the contract address // error_code |= // current_state.touch_state.set_warm_account(arith, // contract_address); - + // printf("generic_CREATE senderaddress ptr %p\n", sender_address_ptr); + // sender_address_ptr->print(); CuEVM::account_t *sender_account = nullptr; - current_state.touch_state.get_account(arith, sender_address, sender_account, ACCOUNT_NON_STORAGE_FLAG); + current_state.touch_state_ptr->get_account(arith, sender_address_ptr, sender_account, ACCOUNT_NON_STORAGE_FLAG); // Do not get_account after this to reuse sender_account if (opcode == OP_CREATE2) { - error_code |= CuEVM::utils::get_contract_address_create2(arith, contract_address, sender_address, salt, - initialisation_code); + CuEVM::utils::get_contract_address_create2(arith, contract_address, sender_address, salt, + initialisation_code); } else { bn_t sender_nonce; sender_account->get_nonce(arith, sender_nonce); - error_code |= - CuEVM::utils::get_contract_address_create(arith, contract_address, sender_address, sender_nonce); + CuEVM::utils::get_contract_address_create(arith, contract_address, sender_address, sender_nonce); } - if (!current_state.touch_state.is_empty_account_create(arith, contract_address)) { + + __ONE_THREAD_PER_INSTANCE(printf("\n\ncontract address\n");); + print_bnt(arith, contract_address); + __SHARED_MEMORY__ evm_word_t contract_address_shared[CGBN_IBP], gas_shared[CGBN_IBP], value_shared[CGBN_IBP]; + cgbn_store(arith.env, &contract_address_shared[INSTANCE_IDX_PER_BLOCK], contract_address); + + __ONE_THREAD_PER_INSTANCE(printf("\n\ncontract address shared\n");); + contract_address_shared[INSTANCE_IDX_PER_BLOCK].print(); + if (!current_state.touch_state_ptr->is_empty_account_create(arith, + &contract_address_shared[INSTANCE_IDX_PER_BLOCK])) { // corner collision case: must set warm for the contract address - current_state.touch_state.set_warm_account(arith, contract_address); + current_state.touch_state_ptr->set_warm_account(arith, &contract_address_shared[INSTANCE_IDX_PER_BLOCK]); error_code |= ERROR_MESSAGE_CALL_CREATE_CONTRACT_EXISTS; } + // gas capped limit bn_t gas_capped; - CuEVM::gas_cost::max_gas_call(arith, gas_capped, current_state.gas_limit, current_state.gas_used); + CuEVM::gas_cost::max_gas_call(arith, gas_capped, cached_state.gas_limit, cached_state.gas_used); // add the gas sent to the gas used - cgbn_add(arith.env, current_state.gas_used, current_state.gas_used, gas_capped); + cgbn_add(arith.env, cached_state.gas_used, cached_state.gas_used, gas_capped); // the return data offset and size bn_t ret_offset, ret_size; cgbn_set_ui32(arith.env, ret_offset, 0); cgbn_set_ui32(arith.env, ret_size, 0); CuEVM::byte_array_t call_data; + + cgbn_store(arith.env, &gas_shared[INSTANCE_IDX_PER_BLOCK], gas_capped); + cgbn_store(arith.env, &value_shared[INSTANCE_IDX_PER_BLOCK], value); + + evm_message_call_t_shadow *message_call_ptr = new CuEVM::evm_message_call_t_shadow( + arith, ¤t_state.message_ptr->recipient, &contract_address_shared[INSTANCE_IDX_PER_BLOCK], + &contract_address_shared[INSTANCE_IDX_PER_BLOCK], &gas_shared[INSTANCE_IDX_PER_BLOCK], + &value_shared[INSTANCE_IDX_PER_BLOCK], current_state.message_ptr->get_depth() + 1, opcode, + &contract_address_shared[INSTANCE_IDX_PER_BLOCK], call_data, initialisation_code, ret_offset, ret_size, + current_state.message_ptr->get_static_env()); + + current_state.message_ptr->copy_from(message_call_ptr); // create the new evm call state - new_state_ptr = new CuEVM::evm_call_state_t( - arith, ¤t_state, - new CuEVM::evm_message_call_t(arith, sender_address, contract_address, contract_address, gas_capped, value, - current_state.message_ptr->get_depth() + 1, opcode, contract_address, - call_data, initialisation_code, ret_offset, ret_size, - current_state.message_ptr->get_static_env())); + new_state_ptr = new CuEVM::evm_call_state_t(arith, ¤t_state, current_state.message_ptr, message_call_ptr); + error_code |= (current_state.message_ptr->get_static_env() ? ERROR_STATIC_CALL_CONTEXT_CREATE : #ifdef EIP_3860 @@ -232,17 +277,20 @@ __host__ __device__ int32_t generic_CREATE(ArithEnv &arith, CuEVM::evm_call_stat ERROR_SUCCESS #endif ); - + // printf("generic_CREATE error_code: %d\n", error_code); if (sender_account->is_contract()) { bn_t sender_nonce; sender_account->get_nonce(arith, sender_nonce); cgbn_add_ui32(arith.env, sender_nonce, sender_nonce, 1); sender_account->set_nonce(arith, sender_nonce); // propagate to child state - new_state_ptr->touch_state.set_nonce(arith, sender_address, sender_nonce); + // printf("generic_CREATE set_nonce %p\n", sender_address_ptr); + // sender_address_ptr->print(); + // sender_account->address.print(); + new_state_ptr->touch_state_ptr->set_nonce(arith, &sender_account->address, sender_nonce); } } else - cgbn_bitwise_mask_and(arith.env, current_state.gas_used, current_state.gas_used, 64); + cgbn_bitwise_mask_and(arith.env, cached_state.gas_used, cached_state.gas_used, 64); // printf("generic_CREATE error_code: %d\n", error_code); return error_code; @@ -266,8 +314,9 @@ __host__ __device__ int32_t STOP(CuEVM::evm_return_data_t &return_data) { * @return 0 if the operation is successful, otherwise the error code. */ __host__ __device__ int32_t CREATE(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t *&new_state_ptr) { - return generic_CREATE(arith, current_state, new_state_ptr, OP_CREATE); + CuEVM::evm_call_state_t *&new_state_ptr, + CuEVM::cached_evm_call_state &cached_state) { + return generic_CREATE(arith, current_state, new_state_ptr, OP_CREATE, cached_state); } /** @@ -278,49 +327,78 @@ __host__ __device__ int32_t CREATE(ArithEnv &arith, CuEVM::evm_call_state_t &cur * @return 0 if the operation is successful, otherwise the error code. */ __host__ __device__ int32_t CALL(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t *&new_state_ptr) { + CuEVM::evm_call_state_t *&new_state_ptr, CuEVM::cached_evm_call_state &cached_state) { bn_t gas, address, value, args_offset, args_size, ret_offset, ret_size; // #ifdef __CUDA_ARCH__ // printf("opcode CALL %d\n", threadIdx.x); // #endif - int32_t error_code = current_state.stack_ptr->pop(arith, gas); - error_code |= current_state.stack_ptr->pop(arith, address); - error_code |= current_state.stack_ptr->pop(arith, value); - error_code |= current_state.stack_ptr->pop(arith, args_offset); - error_code |= current_state.stack_ptr->pop(arith, args_size); - error_code |= current_state.stack_ptr->pop(arith, ret_offset); - error_code |= current_state.stack_ptr->pop(arith, ret_size); + int32_t error_code = cached_state.stack_ptr->pop(arith, gas); + error_code |= cached_state.stack_ptr->pop(arith, address); + error_code |= cached_state.stack_ptr->pop(arith, value); + error_code |= cached_state.stack_ptr->pop(arith, args_offset); + error_code |= cached_state.stack_ptr->pop(arith, args_size); + error_code |= cached_state.stack_ptr->pop(arith, ret_offset); + error_code |= cached_state.stack_ptr->pop(arith, ret_size); + + // printf("opcode CALL params after pop\n"); + // print_bnt(arith, gas); + // print_bnt(arith, address); + // print_bnt(arith, value); + // print_bnt(arith, args_offset); + // print_bnt(arith, args_size); + // print_bnt(arith, ret_offset); + // print_bnt(arith, ret_size); // #ifdef __CUDA_ARCH__ // printf("opcode CALL before error_code == ERROR_SUCCESS %d\n", threadIdx.x); // #endif if (error_code == ERROR_SUCCESS) { // clean the address CuEVM::evm_address_conversion(arith, address); - bn_t sender; - current_state.message_ptr->get_recipient(arith, 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 + __SHARED_MEMORY__ evm_word_t target_address[CGBN_IBP], gas_shared[CGBN_IBP], value_shared[CGBN_IBP]; + cgbn_store(arith.env, &target_address[INSTANCE_IDX_PER_BLOCK], address); + cgbn_store(arith.env, &gas_shared[INSTANCE_IDX_PER_BLOCK], gas); + cgbn_store(arith.env, &value_shared[INSTANCE_IDX_PER_BLOCK], value); + // bn_t sender; + // current_state.message_ptr->get_recipient(arith, 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 CuEVM::byte_array_t call_data; CuEVM::byte_array_t code; - new_state_ptr = new CuEVM::evm_call_state_t( - arith, ¤t_state, - new CuEVM::evm_message_call_t(arith, sender, recipient, contract_address, gas, value, - current_state.message_ptr->get_depth() + 1, OP_CALL, storage_address, - call_data, code, ret_offset, ret_size, - current_state.message_ptr->get_static_env())); + // #ifdef __CUDA_ARCH__ + // printf("opcode CALL before constructing message call t %d\n", threadIdx.x); + // #endif + evm_message_call_t_shadow *message_call_ptr = new CuEVM::evm_message_call_t_shadow( + arith, ¤t_state.message_ptr->recipient, &target_address[INSTANCE_IDX_PER_BLOCK], + &target_address[INSTANCE_IDX_PER_BLOCK], &gas_shared[INSTANCE_IDX_PER_BLOCK], + &value_shared[INSTANCE_IDX_PER_BLOCK], current_state.message_ptr->get_depth() + 1, OP_CALL, + &target_address[INSTANCE_IDX_PER_BLOCK], call_data, code, ret_offset, ret_size, + current_state.message_ptr->get_static_env()); + + current_state.message_ptr->copy_from(message_call_ptr); + + // printf("after copy return data offset and size\n"); + // current_state.message_ptr->return_data_offset.print(); + // current_state.message_ptr->return_data_size.print(); + // message_call_ptr->params_data[6].print(); + // message_call_ptr->params_data[7].print(); + + new_state_ptr = new CuEVM::evm_call_state_t(arith, ¤t_state, current_state.message_ptr, message_call_ptr); + + // #ifdef __CUDA_ARCH__ + // printf("opcode CALL after constructing message call t %d\n", threadIdx.x); + // #endif // #ifdef __CUDA_ARCH__ // printf("opcode CALL after constructing message call t %d\n", threadIdx.x); // #endif - error_code |= generic_CALL(arith, args_offset, args_size, current_state, new_state_ptr); } + if (error_code == ERROR_SUCCESS) // break down scope to avoid stack problems + error_code |= generic_CALL(arith, args_offset, args_size, current_state, new_state_ptr, cached_state); - // #ifdef __CUDA_ARCH__ - // printf("opcode CALL after cgeneric_CALL %d\n", threadIdx.x); - // #endif + // printf("opcode CALL error_code %d thread %d\n", error_code, THREADIDX); return error_code; } @@ -332,38 +410,47 @@ __host__ __device__ int32_t CALL(ArithEnv &arith, CuEVM::evm_call_state_t &curre * @return 0 if the operation is successful, otherwise the error code. */ __host__ __device__ int32_t CALLCODE(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t *&new_state_ptr) { + CuEVM::evm_call_state_t *&new_state_ptr, + CuEVM::cached_evm_call_state &cached_state) { bn_t gas, address, value, args_offset, args_size, ret_offset, ret_size; - int32_t error_code = current_state.stack_ptr->pop(arith, gas); - error_code |= current_state.stack_ptr->pop(arith, address); - error_code |= current_state.stack_ptr->pop(arith, value); - error_code |= current_state.stack_ptr->pop(arith, args_offset); - error_code |= current_state.stack_ptr->pop(arith, args_size); - error_code |= current_state.stack_ptr->pop(arith, ret_offset); - error_code |= current_state.stack_ptr->pop(arith, ret_size); + int32_t error_code = cached_state.stack_ptr->pop(arith, gas); + error_code |= cached_state.stack_ptr->pop(arith, address); + error_code |= cached_state.stack_ptr->pop(arith, value); + error_code |= cached_state.stack_ptr->pop(arith, args_offset); + error_code |= cached_state.stack_ptr->pop(arith, args_size); + error_code |= cached_state.stack_ptr->pop(arith, ret_offset); + error_code |= cached_state.stack_ptr->pop(arith, ret_size); if (error_code == ERROR_SUCCESS) { // clean the address CuEVM::evm_address_conversion(arith, address); - bn_t sender; - current_state.message_ptr->get_recipient(arith, 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} + __SHARED_MEMORY__ evm_word_t target_address[CGBN_IBP], gas_shared[CGBN_IBP], value_shared[CGBN_IBP]; + cgbn_store(arith.env, &target_address[INSTANCE_IDX_PER_BLOCK], address); + cgbn_store(arith.env, &gas_shared[INSTANCE_IDX_PER_BLOCK], gas); + cgbn_store(arith.env, &value_shared[INSTANCE_IDX_PER_BLOCK], value); + + // bn_t sender; + // current_state.message_ptr->get_recipient(arith, 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} CuEVM::byte_array_t call_data; CuEVM::byte_array_t code; - new_state_ptr = new CuEVM::evm_call_state_t( - arith, ¤t_state, - new CuEVM::evm_message_call_t(arith, sender, recipient, contract_address, gas, value, - current_state.message_ptr->get_depth() + 1, OP_CALLCODE, storage_address, - call_data, code, ret_offset, ret_size, - current_state.message_ptr->get_static_env())); + evm_message_call_t_shadow *message_call_ptr = new CuEVM::evm_message_call_t_shadow( + arith, ¤t_state.message_ptr->recipient, ¤t_state.message_ptr->recipient, + &target_address[INSTANCE_IDX_PER_BLOCK], &gas_shared[INSTANCE_IDX_PER_BLOCK], + &value_shared[INSTANCE_IDX_PER_BLOCK], current_state.message_ptr->get_depth() + 1, OP_CALLCODE, + ¤t_state.message_ptr->recipient, call_data, code, ret_offset, ret_size, + current_state.message_ptr->get_static_env()); + + current_state.message_ptr->copy_from(message_call_ptr); + new_state_ptr = new CuEVM::evm_call_state_t(arith, ¤t_state, current_state.message_ptr, message_call_ptr); - error_code |= generic_CALL(arith, args_offset, args_size, current_state, new_state_ptr); + error_code |= generic_CALL(arith, args_offset, args_size, current_state, new_state_ptr, cached_state); } return error_code; } @@ -408,38 +495,46 @@ __host__ __device__ int32_t RETURN(ArithEnv &arith, const bn_t &gas_limit, bn_t * @return 0 if the operation is successful, otherwise the error code. */ __host__ __device__ int32_t DELEGATECALL(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t *&new_state_ptr) { + CuEVM::evm_call_state_t *&new_state_ptr, cached_evm_call_state &cached_state) { bn_t gas, address, value, args_offset, args_size, ret_offset, ret_size; - int32_t error_code = current_state.stack_ptr->pop(arith, gas); - error_code |= current_state.stack_ptr->pop(arith, address); + int32_t error_code = cached_state.stack_ptr->pop(arith, gas); + error_code |= cached_state.stack_ptr->pop(arith, address); current_state.message_ptr->get_value(arith, value); - error_code |= current_state.stack_ptr->pop(arith, args_offset); - error_code |= current_state.stack_ptr->pop(arith, args_size); - error_code |= current_state.stack_ptr->pop(arith, ret_offset); - error_code |= current_state.stack_ptr->pop(arith, ret_size); + error_code |= cached_state.stack_ptr->pop(arith, args_offset); + error_code |= cached_state.stack_ptr->pop(arith, args_size); + error_code |= cached_state.stack_ptr->pop(arith, ret_offset); + error_code |= cached_state.stack_ptr->pop(arith, ret_size); if (error_code == ERROR_SUCCESS) { // clean the address CuEVM::evm_address_conversion(arith, address); - bn_t sender; - current_state.message_ptr->get_sender(arith, sender); // keep the message call sender I_{s} - bn_t recipient; - current_state.message_ptr->get_recipient(arith, recipient); // I_{a} - bn_t contract_address; - cgbn_set(arith.env, contract_address, address); // t - bn_t storage_address; - cgbn_set(arith.env, storage_address, recipient); // I_{a} + // bn_t sender; + // current_state.message_ptr->get_sender(arith, sender); // keep the message call sender I_{s} + // bn_t recipient; + // current_state.message_ptr->get_recipient(arith, recipient); // I_{a} + // bn_t contract_address; + // cgbn_set(arith.env, contract_address, address); // t + __SHARED_MEMORY__ evm_word_t target_address[CGBN_IBP], gas_shared[CGBN_IBP], value_shared[CGBN_IBP]; + + cgbn_store(arith.env, &target_address[INSTANCE_IDX_PER_BLOCK], address); + cgbn_store(arith.env, &gas_shared[INSTANCE_IDX_PER_BLOCK], gas); + cgbn_store(arith.env, &value_shared[INSTANCE_IDX_PER_BLOCK], value); + // bn_t storage_address; + // cgbn_set(arith.env, storage_address, recipient); // I_{a} CuEVM::byte_array_t call_data; CuEVM::byte_array_t code; - new_state_ptr = new CuEVM::evm_call_state_t( - arith, ¤t_state, - new CuEVM::evm_message_call_t(arith, sender, recipient, contract_address, gas, value, - current_state.message_ptr->get_depth() + 1, OP_DELEGATECALL, storage_address, - call_data, code, ret_offset, ret_size, - current_state.message_ptr->get_static_env())); + evm_message_call_t_shadow *message_call_ptr = new CuEVM::evm_message_call_t_shadow( + arith, ¤t_state.message_ptr->sender, ¤t_state.message_ptr->recipient, + &target_address[INSTANCE_IDX_PER_BLOCK], &gas_shared[INSTANCE_IDX_PER_BLOCK], + &value_shared[INSTANCE_IDX_PER_BLOCK], current_state.message_ptr->get_depth() + 1, OP_DELEGATECALL, + ¤t_state.message_ptr->recipient, call_data, code, ret_offset, ret_size, + current_state.message_ptr->get_static_env()); + current_state.message_ptr->copy_from(message_call_ptr); + + new_state_ptr = new CuEVM::evm_call_state_t(arith, ¤t_state, current_state.message_ptr, message_call_ptr); - error_code |= generic_CALL(arith, args_offset, args_size, current_state, new_state_ptr); + error_code |= generic_CALL(arith, args_offset, args_size, current_state, new_state_ptr, cached_state); } return error_code; } @@ -452,8 +547,8 @@ __host__ __device__ int32_t DELEGATECALL(ArithEnv &arith, CuEVM::evm_call_state_ * @return 0 if the operation is successful, otherwise the error code. */ __host__ __device__ int32_t CREATE2(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t *&new_state_ptr) { - return generic_CREATE(arith, current_state, new_state_ptr, OP_CREATE2); + CuEVM::evm_call_state_t *&new_state_ptr, cached_evm_call_state &cached_state) { + return generic_CREATE(arith, current_state, new_state_ptr, OP_CREATE2, cached_state); } /** @@ -464,37 +559,44 @@ __host__ __device__ int32_t CREATE2(ArithEnv &arith, CuEVM::evm_call_state_t &cu * @return 0 if the operation is successful, otherwise the error code. */ __host__ __device__ int32_t STATICCALL(ArithEnv &arith, CuEVM::evm_call_state_t ¤t_state, - CuEVM::evm_call_state_t *&new_state_ptr) { + CuEVM::evm_call_state_t *&new_state_ptr, cached_evm_call_state &cached_state) { bn_t gas, address, value, args_offset, args_size, ret_offset, ret_size; - int32_t error_code = current_state.stack_ptr->pop(arith, gas); - error_code |= current_state.stack_ptr->pop(arith, address); + int32_t error_code = cached_state.stack_ptr->pop(arith, gas); + error_code |= cached_state.stack_ptr->pop(arith, address); cgbn_set_ui32(arith.env, value, 0); - error_code |= current_state.stack_ptr->pop(arith, args_offset); - error_code |= current_state.stack_ptr->pop(arith, args_size); - error_code |= current_state.stack_ptr->pop(arith, ret_offset); - error_code |= current_state.stack_ptr->pop(arith, ret_size); + error_code |= cached_state.stack_ptr->pop(arith, args_offset); + error_code |= cached_state.stack_ptr->pop(arith, args_size); + error_code |= cached_state.stack_ptr->pop(arith, ret_offset); + error_code |= cached_state.stack_ptr->pop(arith, ret_size); if (error_code == ERROR_SUCCESS) { // clean the address CuEVM::evm_address_conversion(arith, address); - bn_t sender; - current_state.message_ptr->get_recipient(arith, 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 + __SHARED_MEMORY__ evm_word_t target_address[CGBN_IBP], gas_shared[CGBN_IBP], value_shared[CGBN_IBP]; + cgbn_store(arith.env, &target_address[INSTANCE_IDX_PER_BLOCK], address); + cgbn_store(arith.env, &gas_shared[INSTANCE_IDX_PER_BLOCK], gas); + cgbn_store(arith.env, &value_shared[INSTANCE_IDX_PER_BLOCK], value); + // bn_t sender; + // current_state.message_ptr->get_recipient(arith, 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 CuEVM::byte_array_t call_data; CuEVM::byte_array_t code; - new_state_ptr = new CuEVM::evm_call_state_t( - arith, ¤t_state, - new CuEVM::evm_message_call_t(arith, sender, recipient, contract_address, gas, value, - current_state.message_ptr->get_depth() + 1, OP_STATICCALL, storage_address, - call_data, code, ret_offset, ret_size, 1)); + evm_message_call_t_shadow *message_call_ptr = new CuEVM::evm_message_call_t_shadow( + arith, ¤t_state.message_ptr->recipient, &target_address[INSTANCE_IDX_PER_BLOCK], + &target_address[INSTANCE_IDX_PER_BLOCK], &gas_shared[INSTANCE_IDX_PER_BLOCK], + &value_shared[INSTANCE_IDX_PER_BLOCK], current_state.message_ptr->get_depth() + 1, OP_STATICCALL, + &target_address[INSTANCE_IDX_PER_BLOCK], call_data, code, ret_offset, ret_size, 1); + current_state.message_ptr->copy_from(message_call_ptr); + + new_state_ptr = new CuEVM::evm_call_state_t(arith, ¤t_state, current_state.message_ptr, message_call_ptr); - error_code |= generic_CALL(arith, args_offset, args_size, current_state, new_state_ptr); + error_code |= generic_CALL(arith, args_offset, args_size, current_state, new_state_ptr, cached_state); } return error_code; @@ -556,36 +658,39 @@ __host__ __device__ int32_t SELFDESTRUCT(ArithEnv &arith, const bn_t &gas_limit, } else { bn_t recipient; error_code |= stack.pop(arith, recipient); - + __SHARED_MEMORY__ evm_word_t recipient_shared[CGBN_IBP]; + cgbn_store(arith.env, &recipient_shared[INSTANCE_IDX_PER_BLOCK], recipient); cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_SELFDESTRUCT); - bn_t contract_address; - message.get_contract_address(arith, contract_address); + // bn_t contract_address; + // message.get_contract_address(arith, contract_address); // custom logic, cannot use access_account_cost (no warm cost) - if (!touch_state.is_warm_account(arith, recipient)) + if (!touch_state.is_warm_account(arith, &recipient_shared[INSTANCE_IDX_PER_BLOCK])) cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_COLD_ACCOUNT_ACCESS); bn_t sender_balance; - touch_state.get_balance(arith, contract_address, sender_balance); + touch_state.get_balance(arith, &message.contract_address, sender_balance); if (cgbn_compare_ui32(arith.env, sender_balance, 0) > 0) { - if (touch_state.is_empty_account(arith, recipient)) { + if (touch_state.is_empty_account(arith, &recipient_shared[INSTANCE_IDX_PER_BLOCK])) { cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_NEW_ACCOUNT); } } error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); if (error_code == ERROR_SUCCESS) { bn_t recipient_balance; - touch_state.get_balance(arith, recipient, recipient_balance); + touch_state.get_balance(arith, &recipient_shared[INSTANCE_IDX_PER_BLOCK], recipient_balance); cgbn_add(arith.env, recipient_balance, recipient_balance, sender_balance); cgbn_set_ui32(arith.env, sender_balance, 0); - touch_state.set_balance(arith, recipient, recipient_balance); - touch_state.set_balance(arith, contract_address, sender_balance); + touch_state.set_balance(arith, &recipient_shared[INSTANCE_IDX_PER_BLOCK], recipient_balance); + touch_state.set_balance(arith, &message.contract_address, sender_balance); // receiver = self => 0 balance return_data = CuEVM::evm_return_data_t(); error_code |= ERROR_RETURN; } } + // printf("touch state after SELFDESTRUCT %d\n", THREADIDX); + // touch_state.print(); return error_code; } } // namespace CuEVM::operations diff --git a/CuEVM/src/precompile.cu b/CuEVM/src/precompile.cu index 4413cd6..f9cbbbd 100644 --- a/CuEVM/src/precompile.cu +++ b/CuEVM/src/precompile.cu @@ -41,7 +41,7 @@ __host__ __device__ int32_t operation_IDENTITY(ArithEnv &arith, bn_t &gas_limit, // dynamic gas // compute the dynamic gas cost bn_t length; - uint32_t length_size = message->data.size; + uint32_t length_size = message->data->size; cgbn_set_ui32(arith.env, length, length_size); CuEVM::gas_cost::memory_cost(arith, gas_used, length); @@ -51,7 +51,7 @@ __host__ __device__ int32_t operation_IDENTITY(ArithEnv &arith, bn_t &gas_limit, return error; } - *return_data = byte_array_t(message->data.data, length_size); + *return_data = byte_array_t(message->data->data, length_size); return ERROR_RETURN; } @@ -75,7 +75,7 @@ __host__ __device__ int32_t operation_SHA256(ArithEnv &arith, bn_t &gas_limit, b // dynamic gas // compute the dynamic gas cost bn_t length; - uint32_t length_size = message->data.size; + uint32_t length_size = message->data->size; cgbn_set_ui32(arith.env, length, length_size); CuEVM::gas_cost::sha256_cost(arith, gas_used, length); @@ -86,7 +86,7 @@ __host__ __device__ int32_t operation_SHA256(ArithEnv &arith, bn_t &gas_limit, b } uint8_t hash[32] = {0}; - CuCrypto::sha256::sha(message->data.data, length_size, &(hash[0])); + CuCrypto::sha256::sha(message->data->data, length_size, &(hash[0])); *return_data = byte_array_t(hash, 32); return ERROR_RETURN; } @@ -97,7 +97,7 @@ __host__ __device__ int32_t operation_RIPEMD160(ArithEnv &arith, bn_t &gas_limit // static gas cgbn_add_ui32(arith.env, gas_used, gas_used, GAS_PRECOMPILE_RIPEMD160); - uint32_t data_size = message->data.size; + uint32_t data_size = message->data->size; bn_t length; cgbn_set_ui32(arith.env, length, data_size); @@ -114,7 +114,7 @@ __host__ __device__ int32_t operation_RIPEMD160(ArithEnv &arith, bn_t &gas_limit uint8_t output[32] = {0}; uint8_t *hash; hash = output + 12; - CuCrypto::ripemd160::ripemd160(message->data.data, data_size, hash); + CuCrypto::ripemd160::ripemd160(message->data->data, data_size, hash); *return_data = byte_array_t(output, 32); return ERROR_RETURN; @@ -129,26 +129,31 @@ __host__ __device__ int32_t operation_MODEXP(ArithEnv &arith, bn_t &gas_limit, b byte_array_t bsize_array = byte_array_t(input_data.data, 32); byte_array_t esize_array = byte_array_t(input_data.data + 32, 32); byte_array_t msize_array = byte_array_t(input_data.data + 64, 32); - - int32_t error = cgbn_set_byte_array_t(arith.env, base_size, bsize_array); - error |= cgbn_set_byte_array_t(arith.env, exponent_size, esize_array); - error |= cgbn_set_byte_array_t(arith.env, modulus_size, msize_array); + int32_t error = ERROR_SUCCESS; + // int32_t error = cgbn_set_byte_array_t(arith.env, base_size, bsize_array); + // error |= cgbn_set_byte_array_t(arith.env, exponent_size, esize_array); + // error |= cgbn_set_byte_array_t(arith.env, modulus_size, msize_array); + cgbn_set_memory(arith.env, base_size, bsize_array.data); + cgbn_set_memory(arith.env, exponent_size, esize_array.data); + cgbn_set_memory(arith.env, modulus_size, msize_array.data); #ifdef EIP_3155 + __ONE_GPU_THREAD_WOSYNC_BEGIN__ printf("base size\n"); print_bnt(arith, base_size); printf("exponent size\n"); print_bnt(arith, exponent_size); printf("modulus size\n"); print_bnt(arith, modulus_size); + __ONE_GPU_THREAD_WOSYNC_END__ #endif - if (error) { - return error; - } + // if (error) { + // return error; + // } uint32_t base_len, exp_len, mod_len, data_len; - data_len = message->data.size; + data_len = message->data->size; error = cgbn_get_uint32_t(arith.env, base_len, base_size); error |= cgbn_get_uint32_t(arith.env, mod_len, modulus_size); error |= cgbn_get_uint32_t(arith.env, exp_len, exponent_size); @@ -182,8 +187,9 @@ __host__ __device__ int32_t operation_MODEXP(ArithEnv &arith, bn_t &gas_limit, b bool exp_is_zero = true; #ifdef __CUDA_ARCH__ - printf("data len %d\n", data_len); - message->data.print(); + + __ONE_THREAD_PER_INSTANCE(printf("data len %d\n", data_len);); + message->data->print(); #endif // get a pointer to available bytes (call_exponent_size) of exponen // send through call data the remaining bytes are consider @@ -197,7 +203,7 @@ __host__ __device__ int32_t operation_MODEXP(ArithEnv &arith, bn_t &gas_limit, b __ONE_GPU_THREAD_WOSYNC_BEGIN__ if (idx < data_len) { - e_data.data[i] = message->data.data[idx]; + e_data.data[i] = message->data->data[idx]; } else { e_data.data[i] = 0; } @@ -258,7 +264,7 @@ __host__ __device__ int32_t operation_MODEXP(ArithEnv &arith, bn_t &gas_limit, b auto idx = 96 + i; if (idx < data_len) { __ONE_GPU_THREAD_WOSYNC_BEGIN__ - base_data.data[i] = message->data.data[idx]; + base_data.data[i] = message->data->data[idx]; __ONE_GPU_THREAD_END__ } else { break; @@ -281,7 +287,7 @@ __host__ __device__ int32_t operation_MODEXP(ArithEnv &arith, bn_t &gas_limit, b for (uint32_t i = 0; i < mod_len; i++) { auto idx = 96 + base_len + exp_len + i; __ONE_GPU_THREAD_WOSYNC_BEGIN__ - mod_data.data[i] = (idx < data_len) ? message->data.data[idx] : 0; + mod_data.data[i] = (idx < data_len) ? message->data->data[idx] : 0; __ONE_GPU_THREAD_END__ if (mod_data.data[i] != 0) { mod_is_zero = false; @@ -348,14 +354,14 @@ __host__ __device__ int32_t operation_BLAKE2(ArithEnv &arith, bn_t &gas_limit, b CuEVM::evm_return_data_t *return_data, CuEVM::evm_message_call_t *message) { // expecting 213 bytes inputs - uint32_t length_size = message->data.size; + uint32_t length_size = message->data->size; if (length_size != 213) { return ERROR_PRECOMPILE_UNEXPECTED_INPUT_LENGTH; } uint8_t *input; - input = message->data.data; + input = message->data->data; uint8_t f = input[212]; // final byte must be 1 or 0 @@ -399,54 +405,62 @@ __host__ __device__ int32_t operation_ecRecover(ArithEnv &arith, CuEVM::EccConst // printf("has gas %d\n", error_code); // printf("gas limit \n"); // print_bnt(arith, gas_limit); - // printf("data size %d\n", message->data.size); - message->data.print(); + // printf("data size %d\n", message->data->size); + message->data->print(); if (error_code == ERROR_SUCCESS) { bn_t length; - cgbn_set_ui32(arith.env, length, message->data.size); + cgbn_set_ui32(arith.env, length, message->data->size); bn_t index; cgbn_set_ui32(arith.env, index, 0); // complete with zeroes the remaing bytes // input = arith.padded_malloc_byte_array(tmp_input, size, 128); CuEVM::byte_array_t input(message->get_data(), 0, 128); - __SHARED_MEMORY__ ecc::signature_t signature; + __SHARED_MEMORY__ ecc::signature_t *signature[CGBN_IBP]; + __ONE_THREAD_PER_INSTANCE(signature[INSTANCE_IDX_PER_BLOCK] = new ecc::signature_t();); bn_t msg_hash, v, r, s, signer; cgbn_set_memory(arith.env, msg_hash, input.data, 32); cgbn_set_memory(arith.env, v, input.data + 32, 32); cgbn_set_memory(arith.env, r, input.data + 64, 32); cgbn_set_memory(arith.env, s, input.data + 96, 32); - cgbn_store(arith.env, &signature.msg_hash, msg_hash); - cgbn_store(arith.env, &signature.r, r); - cgbn_store(arith.env, &signature.s, s); - signature.v = cgbn_get_ui32(arith.env, v); + cgbn_store(arith.env, &signature[INSTANCE_IDX_PER_BLOCK]->msg_hash, msg_hash); + cgbn_store(arith.env, &signature[INSTANCE_IDX_PER_BLOCK]->r, r); + cgbn_store(arith.env, &signature[INSTANCE_IDX_PER_BLOCK]->s, s); + signature[INSTANCE_IDX_PER_BLOCK]->v = cgbn_get_ui32(arith.env, v); #ifdef EIP_3155 - printf("\n v %d\n", signature.v); + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + printf("\n v %d\n", signature[INSTANCE_IDX_PER_BLOCK]->v); printf("r : \n"); print_bnt(arith, r); printf("s : \n"); print_bnt(arith, s); printf("msgh: \n"); print_bnt(arith, msg_hash); + __ONE_GPU_THREAD_WOSYNC_END__ #endif // TODO: is not 27 and 28, only? if (cgbn_compare_ui32(arith.env, v, 28) <= 0) { - __SHARED_MEMORY__ uint8_t output[32]; - size_t res = ecc::ec_recover(arith, constants, signature, signer); + __SHARED_MEMORY__ uint8_t *output[CGBN_IBP]; + __ONE_THREAD_PER_INSTANCE(output[INSTANCE_IDX_PER_BLOCK] = new uint8_t[32];); + size_t res = ecc::ec_recover(arith, constants, *signature[INSTANCE_IDX_PER_BLOCK], signer); #ifdef EIP_3155 + __ONE_GPU_THREAD_WOSYNC_BEGIN__ printf("ec recover %d\n", res); print_bnt(arith, signer); + __ONE_GPU_THREAD_WOSYNC_END__ #endif if (res == ERROR_SUCCESS) { - memory_from_cgbn(arith, output, signer); - *return_data = byte_array_t(output, 32); + memory_from_cgbn(arith, output[INSTANCE_IDX_PER_BLOCK], signer); + *return_data = byte_array_t(output[INSTANCE_IDX_PER_BLOCK], 32); error_code = ERROR_RETURN; } else { // TODO: do we consume all gas? // it happens by default because of the error code error_code = ERROR_PRECOMPILE_UNEXPECTED_INPUT; } + __ONE_THREAD_PER_INSTANCE(delete output[INSTANCE_IDX_PER_BLOCK];); } + __ONE_THREAD_PER_INSTANCE(delete signature[INSTANCE_IDX_PER_BLOCK];); return ERROR_RETURN; } return error_code; @@ -474,18 +488,20 @@ __host__ __device__ int32_t operation_ecAdd(ArithEnv &arith, CuEVM::EccConstants // printf("y1: %s\n", ecc::bnt_to_string(arith._env, y1)); // printf("x2: %s\n", ecc::bnt_to_string(arith._env, x2)); // printf("y2: %s\n", ecc::bnt_to_string(arith._env, y2)); - __SHARED_MEMORY__ uint8_t output[64]; + __SHARED_MEMORY__ uint8_t *output[CGBN_IBP]; + __ONE_THREAD_PER_INSTANCE(output[INSTANCE_IDX_PER_BLOCK] = new uint8_t[64];); int res = ecc::ec_add(arith, constants->alt_BN128, x1, y1, x1, y1, x2, y2); if (res == 0) { - memory_from_cgbn(arith, output, x1); - memory_from_cgbn(arith, output + 32, y1); + memory_from_cgbn(arith, output[INSTANCE_IDX_PER_BLOCK], x1); + memory_from_cgbn(arith, output[INSTANCE_IDX_PER_BLOCK] + 32, y1); // return_data.set(output, 64); - *return_data = byte_array_t(output, 64); + *return_data = byte_array_t(output[INSTANCE_IDX_PER_BLOCK], 64); error_code = ERROR_RETURN; } else { // consume all gas because it is an error error_code = ERROR_PRECOMPILE_UNEXPECTED_INPUT; } + __ONE_THREAD_PER_INSTANCE(delete output[INSTANCE_IDX_PER_BLOCK];); } return error_code; } @@ -508,21 +524,23 @@ __host__ __device__ int32_t operation_ecMul(ArithEnv &arith, CuEVM::EccConstants // printf("mul y: %s\n", ecc::bnt_to_string(arith._env, y)); // printf("k: %s\n", ecc::bnt_to_string(arith._env, k)); - __SHARED_MEMORY__ uint8_t output[64]; + __SHARED_MEMORY__ uint8_t *output[CGBN_IBP]; + __ONE_THREAD_PER_INSTANCE(output[INSTANCE_IDX_PER_BLOCK] = new uint8_t[64];); int res = ecc::ec_mul(arith, constants->alt_BN128, x, y, x, y, k); // print result // printf("xres: %s\n", ecc::bnt_to_string(arith._env, x)); // printf("yres: %s\n", ecc::bnt_to_string(arith._env, y)); if (res == 0) { - memory_from_cgbn(arith, output, x); - memory_from_cgbn(arith, output + 32, y); + memory_from_cgbn(arith, output[INSTANCE_IDX_PER_BLOCK], x); + memory_from_cgbn(arith, output[INSTANCE_IDX_PER_BLOCK] + 32, y); // return_data.set(output, 64); - *return_data = byte_array_t(output, 64); + *return_data = byte_array_t(output[INSTANCE_IDX_PER_BLOCK], 64); error_code = ERROR_RETURN; } else { // consume all gas because it is an error error_code = ERROR_PRECOMPILE_UNEXPECTED_INPUT; } + __ONE_THREAD_PER_INSTANCE(delete output[INSTANCE_IDX_PER_BLOCK];); } return error_code; } @@ -530,19 +548,19 @@ __host__ __device__ int32_t operation_ecMul(ArithEnv &arith, CuEVM::EccConstants __host__ __device__ int32_t operation_ecPairing(ArithEnv &arith, CuEVM::EccConstants *constants, bn_t &gas_limit, bn_t &gas_used, CuEVM::evm_return_data_t *return_data, CuEVM::evm_message_call_t *message) { - __ONE_THREAD_PER_INSTANCE(printf("ecPairing\n"); printf("input size %d\n", message->data.size);); + __ONE_THREAD_PER_INSTANCE(printf("ecPairing\n"); printf("input size %d\n", message->data->size);); // input = message.get_data(index, length, size); - CuEVM::byte_array_t input(message->get_data(), 0, message->data.size); - CuEVM::gas_cost::ecpairing_cost(arith, gas_used, message->data.size); + CuEVM::byte_array_t input(message->get_data(), 0, message->data->size); + CuEVM::gas_cost::ecpairing_cost(arith, gas_used, message->data->size); int32_t error_code = ERROR_SUCCESS; error_code |= CuEVM::gas_cost::has_gas(arith, gas_limit, gas_used); if (error_code == ERROR_SUCCESS) { - if (message->data.size % 192 != 0) { + if (message->data->size % 192 != 0) { error_code = ERROR_PRECOMPILE_UNEXPECTED_INPUT; } else { // 0 inputs is valid and returns 1. int res = - message->data.size == 0 ? 1 : ecc::pairing_multiple(arith, constants, input.data, message->data.size); + message->data->size == 0 ? 1 : ecc::pairing_multiple(arith, constants, input.data, message->data->size); #ifdef __CUDA_ARCH__ printf("res: %d, idx %d \n", res, threadIdx.x); #endif diff --git a/CuEVM/src/state/access_state.cu b/CuEVM/src/state/access_state.cu index 0caa700..43046c7 100644 --- a/CuEVM/src/state/access_state.cu +++ b/CuEVM/src/state/access_state.cu @@ -5,7 +5,7 @@ #include #include - +/* namespace CuEVM { __host__ __device__ int32_t AccessState::add_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t *&account_ptr, @@ -107,3 +107,5 @@ __host__ __device__ int32_t AccessState::get_storage(ArithEnv &arith, const bn_t return ERROR_SUCCESS; } } // namespace CuEVM + +*/ \ No newline at end of file diff --git a/CuEVM/src/state/account.cu b/CuEVM/src/state/account.cu index 32ab357..9e7bd5e 100644 --- a/CuEVM/src/state/account.cu +++ b/CuEVM/src/state/account.cu @@ -56,6 +56,14 @@ __host__ __device__ account_t::account_t(ArithEnv &arith, const bn_t &address) : cgbn_store(arith.env, &this->nonce, tmp); } +__host__ __device__ account_t::account_t(ArithEnv &arith, evm_word_t *address) : storage(), byte_code(0U) { + this->address = *address; + bn_t tmp; + cgbn_set_ui32(arith.env, tmp, 0); + cgbn_store(arith.env, &this->balance, tmp); + cgbn_store(arith.env, &this->nonce, tmp); +} + __host__ __device__ account_t::~account_t() { free(); } __host__ __device__ void account_t::free() { @@ -99,9 +107,6 @@ __host__ __device__ int32_t account_t::get_storage_value(ArithEnv &arith, const } __host__ __device__ int32_t account_t::set_storage_value(ArithEnv &arith, const bn_t &key, const bn_t &value) { - // #ifdef __CUDA_ARCH__ - // printf("account_t::set_storage_value %d account ptr %p storage ptr %p\n", threadIdx.x, this, &storage); - // #endif return storage.set_value(arith, key, value); } @@ -127,27 +132,15 @@ __host__ __device__ void account_t::set_balance(ArithEnv &arith, const bn_t &bal cgbn_store(arith.env, &this->balance, balance); } -__host__ __device__ void account_t::set_address(ArithEnv &arith, const bn_t &address) { - cgbn_store(arith.env, &this->address, address); +__host__ __device__ void account_t::set_address(ArithEnv &arith, const evm_word_t *address) { + // cgbn_store(arith.env, &this->address, address); + this->address = *address; } __host__ __device__ void account_t::set_byte_code(const byte_array_t &byte_code) { this->byte_code = byte_code; } -__host__ __device__ int32_t account_t::has_address(ArithEnv &arith, const bn_t &address) { - bn_t local_address; - // #ifdef __CUDA_ARCH__ - // printf("has_address, accounts[index] %p thread %d\n", &(this->address), threadIdx.x); - // #endif - cgbn_load(arith.env, local_address, &this->address); - - return (cgbn_compare(arith.env, local_address, address) == 0); -} - -__host__ __device__ int32_t account_t::has_address(ArithEnv &arith, const evm_word_t &address) { - bn_t local_address, target_address; - cgbn_load(arith.env, local_address, &this->address); - cgbn_load(arith.env, target_address, (cgbn_evm_word_t_ptr)&address); - return (cgbn_compare(arith.env, local_address, target_address) == 0); +__host__ __device__ int32_t account_t::has_address(ArithEnv &arith, const evm_word_t *address) { + return this->address == *address; } __host__ __device__ void account_t::update(ArithEnv &arith, const account_t &other, const account_flags_t &flags) { @@ -185,6 +178,7 @@ __host__ __device__ bool account_t::is_empty() { __host__ __device__ bool account_t::is_empty_create() { // Goethereum: nonce ==0 && code == 0, can have balance + return ((nonce == 0) && (byte_code.size == 0)) ? true : false; } @@ -218,11 +212,11 @@ __host__ void account_t::from_json(const cJSON *account_json, int32_t managed) { storage.from_json(cJSON_GetObjectItemCaseSensitive(account_json, "storage"), managed); #ifdef EIP_3155 - printf("byte_code.size %d\n", byte_code.size); - printf("byte_code.data %p\n", byte_code.data); - printf("storage.size %d\n", storage.size); - printf("storage.capacity %d\n", storage.capacity); - printf("storage.storage %p\n", storage.storage); +// printf("byte_code.size %d\n", byte_code.size); +// printf("byte_code.data %p\n", byte_code.data); +// printf("storage.size %d\n", storage.size); +// printf("storage.capacity %d\n", storage.capacity); +// printf("storage.storage %p\n", storage.storage); #endif } diff --git a/CuEVM/src/state/contract_storage.cu b/CuEVM/src/state/contract_storage.cu index 0dd5d86..cd15983 100644 --- a/CuEVM/src/state/contract_storage.cu +++ b/CuEVM/src/state/contract_storage.cu @@ -33,7 +33,7 @@ __host__ __device__ void contract_storage_t::clear() { } __host__ __device__ contract_storage_t &contract_storage_t::operator=(const contract_storage_t &other) { - __SHARED_MEMORY__ storage_element_t *tmp_storage; + __SHARED_MEMORY__ storage_element_t *tmp_storage[CGBN_IBP]; // __ONE_GPU_THREAD_WOSYNC_BEGIN__ if (this == &other) { return *this; @@ -47,10 +47,10 @@ __host__ __device__ contract_storage_t &contract_storage_t::operator=(const cont // #endif __ONE_GPU_THREAD_BEGIN__ if (capacity > 0) { - tmp_storage = new storage_element_t[capacity]; + tmp_storage[INSTANCE_IDX_PER_BLOCK] = new storage_element_t[capacity]; } __ONE_GPU_THREAD_END__ - storage = tmp_storage; + storage = tmp_storage[INSTANCE_IDX_PER_BLOCK]; } __ONE_GPU_THREAD_BEGIN__ if (other.size > 0) memcpy(storage, other.storage, other.size * sizeof(storage_element_t)); @@ -77,13 +77,15 @@ __host__ __device__ int32_t contract_storage_t::get_value(ArithEnv &arith, const __host__ __device__ int32_t contract_storage_t::set_value(ArithEnv &arith, const bn_t &key, const bn_t &value) { uint32_t idx; __SYNC_THREADS__ // ? why is this needed? + // todo : remove the loop for (idx = 0; idx < size; idx++) { if (storage[idx].has_key(arith, key)) { storage[idx].set_value(arith, value); return ERROR_SUCCESS; } } - __SHARED_MEMORY__ storage_element_t *new_storage; + + __SHARED_MEMORY__ storage_element_t *new_storage[CGBN_IBP]; // #ifdef __CUDA_ARCH__ // printf("contract_storage_t::set_value before allocateidx %d size %d capacity %d storage %p\n", threadIdx.x, // size, @@ -96,15 +98,14 @@ __host__ __device__ int32_t contract_storage_t::set_value(ArithEnv &arith, const capacity *= 2; } __ONE_GPU_THREAD_WOSYNC_BEGIN__ - new_storage = new storage_element_t[capacity]; + new_storage[INSTANCE_IDX_PER_BLOCK] = new storage_element_t[capacity]; // printf("allocate new storage %p, capacity %d\n", new_storage, capacity); if (size > 0) { - memcpy(new_storage, storage, size * sizeof(storage_element_t)); + memcpy(new_storage[INSTANCE_IDX_PER_BLOCK], storage, size * sizeof(storage_element_t)); } delete[] storage; __ONE_GPU_THREAD_END__ - - storage = new_storage; + storage = new_storage[INSTANCE_IDX_PER_BLOCK]; // printf("set storage size %d capacity %d storage %p, new_storage %p\n", size, capacity, storage, // new_storage); } diff --git a/CuEVM/src/state/logs.cu b/CuEVM/src/state/logs.cu index e58b387..9c2d3f2 100644 --- a/CuEVM/src/state/logs.cu +++ b/CuEVM/src/state/logs.cu @@ -9,21 +9,21 @@ namespace CuEVM { __host__ __device__ int32_t log_state_data_t::grow() { - __SHARED_MEMORY__ log_data_t *new_logs; + __SHARED_MEMORY__ log_data_t *new_logs[CGBN_IBP]; __ONE_GPU_THREAD_WOSYNC_BEGIN__ - new_logs = new log_data_t[capacity + log_page_size]; + new_logs[INSTANCE_IDX_PER_BLOCK] = new log_data_t[capacity + log_page_size]; // printf("allocate capacity %d for logpointer %p new_logs %p\n", capacity + log_page_size, this, new_logs); __ONE_GPU_THREAD_END__ - if (new_logs == nullptr) { + if (new_logs[INSTANCE_IDX_PER_BLOCK] == nullptr) { return ERROR_MEMORY_ALLOCATION_FAILED; } __ONE_GPU_THREAD_WOSYNC_BEGIN__ if (logs != nullptr && no_logs > 0) { - memcpy(new_logs, logs, no_logs * sizeof(log_data_t)); + memcpy(new_logs[INSTANCE_IDX_PER_BLOCK], logs, no_logs * sizeof(log_data_t)); delete[] logs; } __ONE_GPU_THREAD_END__ - logs = new_logs; + logs = new_logs[INSTANCE_IDX_PER_BLOCK]; capacity = capacity + log_page_size; return ERROR_SUCCESS; } diff --git a/CuEVM/src/state/state.cu b/CuEVM/src/state/state.cu index 32ec60a..890bd93 100644 --- a/CuEVM/src/state/state.cu +++ b/CuEVM/src/state/state.cu @@ -20,21 +20,21 @@ __host__ __device__ state_t &state_t::operator=(const state_t &other) { return *this; } __host__ __device__ void state_t::duplicate(const state_t &other) { - __SHARED_MEMORY__ CuEVM::account_t *tmp_accounts; + __SHARED_MEMORY__ CuEVM::account_t *tmp_accounts[CGBN_IBP]; free(); // free the current state no_accounts = other.no_accounts; if (no_accounts > 0) { __ONE_GPU_THREAD_BEGIN__ - tmp_accounts = (CuEVM::account_t *)malloc(no_accounts * sizeof(CuEVM::account_t)); + tmp_accounts[INSTANCE_IDX_PER_BLOCK] = (CuEVM::account_t *)malloc(no_accounts * sizeof(CuEVM::account_t)); __ONE_GPU_THREAD_END__ for (uint32_t idx = 0; idx < no_accounts; idx++) { - tmp_accounts[idx].clear(); - tmp_accounts[idx] = other.accounts[idx]; + tmp_accounts[INSTANCE_IDX_PER_BLOCK][idx].clear(); + tmp_accounts[INSTANCE_IDX_PER_BLOCK][idx] = other.accounts[idx]; } } else { - tmp_accounts = nullptr; + tmp_accounts[INSTANCE_IDX_PER_BLOCK] = nullptr; } - accounts = tmp_accounts; + accounts = tmp_accounts[INSTANCE_IDX_PER_BLOCK]; } __host__ __device__ state_t::~state_t() { free(); } @@ -63,7 +63,7 @@ __host__ __device__ void state_t::clear() { no_accounts = 0; } -__host__ __device__ int32_t state_t::get_account_index(ArithEnv &arith, const bn_t &address, uint32_t &index) { +__host__ __device__ int32_t state_t::get_account_index(ArithEnv &arith, const evm_word_t *address, uint32_t &index) { // #ifdef __CUDA_ARCH__ // printf("get_account_index, no_accounts %d thread %d\n", no_accounts, threadIdx.x); // print_bnt(arith, address); @@ -73,7 +73,7 @@ __host__ __device__ int32_t state_t::get_account_index(ArithEnv &arith, const bn // printf("get_account_index, %d , accounts[index] %p thread %d\n", index, &(accounts[index].address), // threadIdx.x); // #endif - if (accounts[index].has_address(arith, address)) { + if (accounts[index].address == *address) { return ERROR_SUCCESS; } } @@ -81,7 +81,8 @@ __host__ __device__ int32_t state_t::get_account_index(ArithEnv &arith, const bn return ERROR_STATE_ADDRESS_NOT_FOUND; } -__host__ __device__ int32_t state_t::get_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t &account) { +__host__ __device__ int32_t state_t::get_account(ArithEnv &arith, const evm_word_t *address, + CuEVM::account_t &account) { uint32_t index; if (get_account_index(arith, address, index) == ERROR_SUCCESS) { account = accounts[index]; @@ -90,7 +91,8 @@ __host__ __device__ int32_t state_t::get_account(ArithEnv &arith, const bn_t &ad return ERROR_STATE_ADDRESS_NOT_FOUND; } -__host__ __device__ int32_t state_t::get_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t *&account_ptr) { +__host__ __device__ int32_t state_t::get_account(ArithEnv &arith, const evm_word_t *address, + CuEVM::account_t *&account_ptr) { uint32_t index; if (get_account_index(arith, address, index) == ERROR_SUCCESS) { account_ptr = &accounts[index]; @@ -100,28 +102,31 @@ __host__ __device__ int32_t state_t::get_account(ArithEnv &arith, const bn_t &ad } __host__ __device__ int32_t state_t::add_account(const CuEVM::account_t &account) { - __SHARED_MEMORY__ CuEVM::account_t *tmp_accounts; + __SHARED_MEMORY__ CuEVM::account_t *tmp_accounts[CGBN_IBP]; __ONE_GPU_THREAD_BEGIN__ - tmp_accounts = (CuEVM::account_t *)malloc((no_accounts + 1) * sizeof(CuEVM::account_t)); - memcpy(tmp_accounts, accounts, no_accounts * sizeof(CuEVM::account_t)); + + tmp_accounts[INSTANCE_IDX_PER_BLOCK] = (CuEVM::account_t *)malloc((no_accounts + 1) * sizeof(CuEVM::account_t)); + // printf("state_t::add_account malloc, instance idx %d, no_accounts %d thread idx %d, account pointer %p\n", + // INSTANCE_IDX_PER_BLOCK, no_accounts, THREADIDX, tmp_accounts[INSTANCE_IDX_PER_BLOCK]); + memcpy(tmp_accounts[INSTANCE_IDX_PER_BLOCK], accounts, no_accounts * sizeof(CuEVM::account_t)); __ONE_GPU_THREAD_END__ - tmp_accounts[no_accounts].clear(); - tmp_accounts[no_accounts] = account; + tmp_accounts[INSTANCE_IDX_PER_BLOCK][no_accounts].clear(); + tmp_accounts[INSTANCE_IDX_PER_BLOCK][no_accounts] = account; if (accounts != nullptr) { + // printf("state_t::add_account free accounts, instance idx %d, account pointer %p \n", INSTANCE_IDX_PER_BLOCK, + // accounts); __ONE_GPU_THREAD_BEGIN__ std::free(accounts); __ONE_GPU_THREAD_END__ } - accounts = tmp_accounts; + accounts = tmp_accounts[INSTANCE_IDX_PER_BLOCK]; no_accounts++; return ERROR_SUCCESS; } __host__ __device__ int32_t state_t::set_account(ArithEnv &arith, const CuEVM::account_t &account) { - bn_t target_address; - cgbn_load(arith.env, target_address, (cgbn_evm_word_t_ptr) & (account.address)); for (uint32_t idx = 0; idx < no_accounts; idx++) { - if (accounts[idx].has_address(arith, target_address)) { + if (accounts[idx].has_address(arith, &(account.address))) { accounts[idx] = account; return ERROR_SUCCESS; } @@ -130,25 +135,28 @@ __host__ __device__ int32_t state_t::set_account(ArithEnv &arith, const CuEVM::a return add_account(account); } -__host__ __device__ int32_t state_t::has_account(ArithEnv &arith, const bn_t &address) { +__host__ __device__ int32_t state_t::update_account(ArithEnv &arith, const CuEVM::account_t &account, + const CuEVM::account_flags_t flag) { for (uint32_t idx = 0; idx < no_accounts; idx++) { - if (accounts[idx].has_address(arith, address)) { + if (accounts[idx].has_address(arith, &(account.address))) { + accounts[idx].update(arith, account, flag); return ERROR_SUCCESS; } } - return ERROR_STATE_ADDRESS_NOT_FOUND; + return add_account(account); } -__host__ __device__ int32_t state_t::update_account(ArithEnv &arith, const CuEVM::account_t &account) { - bn_t target_address; - cgbn_load(arith.env, target_address, (cgbn_evm_word_t_ptr) & (account.address)); - for (uint32_t idx = 0; idx < no_accounts; idx++) { - if (accounts[idx].has_address(arith, target_address)) { - accounts[idx].update(arith, account); - return ERROR_SUCCESS; +// __host__ __device__ int32_t update(ArithEnv &arith, CuEVM::account_t *accounts, CuEVM::account_flags_t *flags, +__host__ __device__ int32_t state_t::update(ArithEnv &arith, const CuEVM::account_t *_accounts, + const CuEVM::account_flags_t *_flags, uint32_t account_count) { + int32_t error_code = ERROR_SUCCESS; + for (uint32_t i = 0; i < account_count; i++) { + // if update failed (not exist), add the account + if (update_account(arith, _accounts[i], _flags[i]) != ERROR_SUCCESS) { + error_code |= add_account(_accounts[i]); } } - return add_account(account); + return error_code; } // __host__ __device__ int32_t state_t::is_empty_account(ArithEnv &arith, diff --git a/CuEVM/src/state/state_access.cu b/CuEVM/src/state/state_access.cu index d034f05..417e7f1 100644 --- a/CuEVM/src/state/state_access.cu +++ b/CuEVM/src/state/state_access.cu @@ -46,21 +46,22 @@ __host__ __device__ state_access_t &state_access_t::operator=(const state_access } __host__ __device__ void state_access_t::duplicate(const state_access_t &other) { - __SHARED_MEMORY__ CuEVM::account_flags_t *tmp_flags; + __SHARED_MEMORY__ CuEVM::account_flags_t *tmp_flags[CGBN_IBP]; state_t::duplicate(other); if (no_accounts > 0) { __ONE_GPU_THREAD_BEGIN__ - tmp_flags = (CuEVM::account_flags_t *)malloc(sizeof(CuEVM::account_flags_t) * no_accounts); - memcpy(tmp_flags, other.flags, no_accounts * sizeof(CuEVM::account_flags_t)); + tmp_flags[INSTANCE_IDX_PER_BLOCK] = + (CuEVM::account_flags_t *)malloc(sizeof(CuEVM::account_flags_t) * no_accounts); + memcpy(tmp_flags[INSTANCE_IDX_PER_BLOCK], other.flags, no_accounts * sizeof(CuEVM::account_flags_t)); __ONE_GPU_THREAD_END__ } else { - tmp_flags = nullptr; + tmp_flags[INSTANCE_IDX_PER_BLOCK] = nullptr; } - flags = tmp_flags; + flags = tmp_flags[INSTANCE_IDX_PER_BLOCK]; } -__host__ __device__ int32_t state_access_t::get_account(ArithEnv &arith, const bn_t &address, CuEVM::account_t &account, - const CuEVM::account_flags_t flag) { +__host__ __device__ int32_t state_access_t::get_account(ArithEnv &arith, const evm_word_t *address, + CuEVM::account_t &account, const CuEVM::account_flags_t flag) { uint32_t index = 0; if (state_t::get_account_index(arith, address, index) == ERROR_SUCCESS) { flags[index].update(flag); @@ -70,7 +71,7 @@ __host__ __device__ int32_t state_access_t::get_account(ArithEnv &arith, const b return ERROR_STATE_ADDRESS_NOT_FOUND; } -__host__ __device__ int32_t state_access_t::get_account(ArithEnv &arith, const bn_t &address, +__host__ __device__ int32_t state_access_t::get_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, const CuEVM::account_flags_t flag) { uint32_t index = 0; @@ -85,20 +86,22 @@ __host__ __device__ int32_t state_access_t::get_account(ArithEnv &arith, const b __host__ __device__ int32_t state_access_t::add_account(const CuEVM::account_t &account, const CuEVM::account_flags_t flag) { state_t::add_account(account); - + // #ifdef __CUDA_ARCH__ + // printf("after state_t::add_account(account); before malloc(account_flags_t; %d\n", threadIdx.x); + // #endif uint32_t index = no_accounts - 1; - __SHARED_MEMORY__ CuEVM::account_flags_t *tmp_flags; + __SHARED_MEMORY__ CuEVM::account_flags_t *tmp_flags[CGBN_IBP]; __ONE_GPU_THREAD_BEGIN__ // printf(" state_access_t::add_account no_accounts: %u\n", no_accounts); - tmp_flags = (CuEVM::account_flags_t *)malloc(sizeof(CuEVM::account_flags_t) * no_accounts); - memcpy(tmp_flags, flags, (no_accounts - 1) * sizeof(CuEVM::account_flags_t)); + tmp_flags[INSTANCE_IDX_PER_BLOCK] = (CuEVM::account_flags_t *)malloc(sizeof(CuEVM::account_flags_t) * no_accounts); + memcpy(tmp_flags[INSTANCE_IDX_PER_BLOCK], flags, (no_accounts - 1) * sizeof(CuEVM::account_flags_t)); if (flags != nullptr) { delete[] flags; } __ONE_GPU_THREAD_END__ - flags = tmp_flags; + flags = tmp_flags[INSTANCE_IDX_PER_BLOCK]; flags[index] = flag; // #ifdef __CUDA_ARCH__ @@ -113,18 +116,18 @@ __host__ __device__ int32_t state_access_t::add_duplicate_account(ArithEnv &arit const CuEVM::account_flags_t flag) { CuEVM::account_flags_t no_storage_copy(ACCOUNT_NON_STORAGE_FLAG); - __SHARED_MEMORY__ CuEVM::account_t *tmp_account_ptr; + __SHARED_MEMORY__ CuEVM::account_t *tmp_account_ptr[CGBN_IBP]; __ONE_GPU_THREAD_WOSYNC_BEGIN__ - tmp_account_ptr = new CuEVM::account_t(); + tmp_account_ptr[INSTANCE_IDX_PER_BLOCK] = new CuEVM::account_t(); // tmp_account_ptr = new CuEVM::account_t(src_account_ptr, no_storage_copy); __ONE_GPU_THREAD_END__ - tmp_account_ptr->update(arith, *src_account_ptr, no_storage_copy); + tmp_account_ptr[INSTANCE_IDX_PER_BLOCK]->update(arith, *src_account_ptr, no_storage_copy); // #ifdef __CUDA_ARCH__ // printf("TouchState::add_duplicate_account before add_account %d tmp_account_ptr %p storage %p\n", // threadIdx.x, // tmp_account_ptr, &tmp_account_ptr->storage); // #endif - int32_t error_code = add_account(*tmp_account_ptr, flag); + int32_t error_code = add_account(*tmp_account_ptr[INSTANCE_IDX_PER_BLOCK], flag); // #ifdef __CUDA_ARCH__ // printf("TouchState::add_duplicate_account after add_account %d\n" ,threadIdx.x); // #endif @@ -135,7 +138,7 @@ __host__ __device__ int32_t state_access_t::add_duplicate_account(ArithEnv &arit // account_ptr); // #endif __ONE_GPU_THREAD_WOSYNC_BEGIN__ - delete tmp_account_ptr; + delete tmp_account_ptr[INSTANCE_IDX_PER_BLOCK]; __ONE_GPU_THREAD_WOSYNC_END__ // #ifdef __CUDA_ARCH__ // printf("TouchState::add_duplicate_account delete tmp_account_ptr %d, account_ptr %p\n" ,threadIdx.x, @@ -145,35 +148,30 @@ __host__ __device__ int32_t state_access_t::add_duplicate_account(ArithEnv &arit return error_code; } -__host__ __device__ int32_t state_access_t::add_new_account(ArithEnv &arith, const bn_t &address, +__host__ __device__ int32_t state_access_t::add_new_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, const CuEVM::account_flags_t flag) { - __SHARED_MEMORY__ CuEVM::account_t *tmp_account_ptr; + __SHARED_MEMORY__ CuEVM::account_t *tmp_account_ptr[CGBN_IBP]; bn_t zero; cgbn_set_ui32(arith.env, zero, 0); // printf("before new CuEVM::account_t();\n"); - // #ifdef __CUDA_ARCH__ - // printf("state_access_t::add_new_account before new CuEVM::account_t() %d\n", threadIdx.x); - // #endif + __ONE_GPU_THREAD_WOSYNC_BEGIN__ - tmp_account_ptr = new CuEVM::account_t(); + tmp_account_ptr[INSTANCE_IDX_PER_BLOCK] = new CuEVM::account_t(); __ONE_GPU_THREAD_END__ - // #ifdef __CUDA_ARCH__ - // printf("state_access_t::add_new_account after new CuEVM::account_t() %d\n", threadIdx.x); - // #endif - tmp_account_ptr->set_address(arith, address); + + tmp_account_ptr[INSTANCE_IDX_PER_BLOCK]->set_address(arith, address); // default constructor did not set balance + nonce - tmp_account_ptr->set_balance(arith, zero); - tmp_account_ptr->set_nonce(arith, zero); + tmp_account_ptr[INSTANCE_IDX_PER_BLOCK]->set_balance(arith, zero); + tmp_account_ptr[INSTANCE_IDX_PER_BLOCK]->set_nonce(arith, zero); + + int32_t error_code = add_account(*tmp_account_ptr[INSTANCE_IDX_PER_BLOCK], flag); -#ifdef __CUDA_ARCH__ - // printf("before add_account(*tmp_account_ptr, flag); %d\n", threadIdx.x); -#endif - int32_t error_code = add_account(*tmp_account_ptr, flag); account_ptr = &accounts[no_accounts - 1]; __ONE_GPU_THREAD_WOSYNC_BEGIN__ - delete tmp_account_ptr; + delete tmp_account_ptr[INSTANCE_IDX_PER_BLOCK]; __ONE_GPU_THREAD_WOSYNC_END__ + return error_code; } @@ -188,10 +186,8 @@ __host__ __device__ int32_t state_access_t::set_account(ArithEnv &arith, const C __host__ __device__ int32_t state_access_t::update_account(ArithEnv &arith, const CuEVM::account_t &account, const CuEVM::account_flags_t flag) { - bn_t target_address; - cgbn_load(arith.env, target_address, (cgbn_evm_word_t_ptr) & (account.address)); uint32_t index = 0; - if (state_t::get_account_index(arith, target_address, index) == ERROR_SUCCESS) { + if (state_t::get_account_index(arith, &(account.address), index) == ERROR_SUCCESS) { accounts[index].update(arith, account, flag); flags[index].update(flag); return ERROR_SUCCESS; diff --git a/CuEVM/src/state/touch_state.cu b/CuEVM/src/state/touch_state.cu index 5f9d608..909816f 100644 --- a/CuEVM/src/state/touch_state.cu +++ b/CuEVM/src/state/touch_state.cu @@ -7,13 +7,14 @@ #include namespace CuEVM { -__host__ __device__ int32_t TouchState::add_account(ArithEnv &arith, const bn_t &address, +__host__ __device__ int32_t TouchState::add_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, const CuEVM::account_flags_t acces_state_flag) { CuEVM::account_t *tmp_account_ptr = nullptr; #ifdef EIP_3155 - __ONE_THREAD_PER_INSTANCE(printf("TouchState::add_account - account_ptr: %p\n", account_ptr);); - print_bnt(arith, address); + __ONE_THREAD_PER_INSTANCE(printf("TouchState::add_account - account_ptr: %p idx %d\n", account_ptr, THREADIDX);) + address->print(); + // print_bnt(arith, address); #endif // this->print(); @@ -32,8 +33,9 @@ __host__ __device__ int32_t TouchState::add_account(ArithEnv &arith, const bn_t // printf("TouchState::add_account account found in the current state %d acc index %d\n", // threadIdx.x, index); // #endif - print_bnt(arith, address); - _state->print(); + // print_bnt(arith, address); + // address->print(); + // _state->print(); _state->flags[index].update(acces_state_flag); } else return _state->add_duplicate_account(arith, account_ptr, tmp_account_ptr, acces_state_flag); @@ -42,26 +44,30 @@ __host__ __device__ int32_t TouchState::add_account(ArithEnv &arith, const bn_t return ERROR_SUCCESS; } -__host__ __device__ int32_t TouchState::get_account(ArithEnv &arith, const bn_t &address, +__host__ __device__ int32_t TouchState::get_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, const CuEVM::account_flags_t acces_state_flag, bool add_to_current_state) { _world_state->get_account(arith, address, account_ptr); + + // __ONE_THREAD_PER_INSTANCE(printf("\n\n_world_state->get_account %d\n", THREADIDX);); + // address->print(); + const TouchState *tmp = this; while ((tmp != nullptr) && (tmp->_state->get_account(arith, address, account_ptr, acces_state_flag))) tmp = tmp->parent; if (account_ptr == nullptr) { - // #ifdef __CUDA_ARCH__ - // printf("get_account not found, add to current state %d\n", threadIdx.x); - // #endif + // __ONE_THREAD_PER_INSTANCE(printf("get_account not found, add to current state %d\n", THREADIDX);); + _state->add_new_account(arith, address, account_ptr, acces_state_flag); return ERROR_STATE_ADDRESS_NOT_FOUND; // error code !+ ERROR_SUCCESS => just added } + return ERROR_SUCCESS; } -__host__ __device__ int32_t TouchState::poke_account(ArithEnv &arith, const bn_t &address, +__host__ __device__ int32_t TouchState::poke_account(ArithEnv &arith, const evm_word_t *address, CuEVM::account_t *&account_ptr, bool include_world_state) const { if (include_world_state) _world_state->get_account(arith, address, account_ptr); const TouchState *tmp = this; @@ -69,13 +75,14 @@ __host__ __device__ int32_t TouchState::poke_account(ArithEnv &arith, const bn_t return account_ptr != nullptr ? ERROR_SUCCESS : ERROR_STATE_ADDRESS_NOT_FOUND; } -__host__ __device__ int32_t TouchState::get_account_index(ArithEnv &arith, const bn_t &address, uint32_t &index) const { +__host__ __device__ int32_t TouchState::get_account_index(ArithEnv &arith, const evm_word_t *address, + uint32_t &index) const { index = 0; return _state->get_account_index(arith, address, index) == ERROR_SUCCESS ? ERROR_SUCCESS : ERROR_STATE_ADDRESS_NOT_FOUND; } -__host__ __device__ int32_t TouchState::get_balance(ArithEnv &arith, const bn_t &address, bn_t &balance) { +__host__ __device__ int32_t TouchState::get_balance(ArithEnv &arith, const evm_word_t *address, bn_t &balance) { account_t *account_ptr = nullptr; // set to 0 first cgbn_set_ui32(arith.env, balance, 0); @@ -91,7 +98,7 @@ __host__ __device__ int32_t TouchState::get_balance(ArithEnv &arith, const bn_t return error_code; } -__host__ __device__ int32_t TouchState::get_nonce(ArithEnv &arith, const bn_t &address, bn_t &nonce) { +__host__ __device__ int32_t TouchState::get_nonce(ArithEnv &arith, const evm_word_t *address, bn_t &nonce) { account_t *account_ptr = nullptr; // set to 0 first cgbn_set_ui32(arith.env, nonce, 0); @@ -102,7 +109,7 @@ __host__ __device__ int32_t TouchState::get_nonce(ArithEnv &arith, const bn_t &a return error_code; } -__host__ __device__ int32_t TouchState::get_code(ArithEnv &arith, const bn_t &address, byte_array_t &byte_code) { +__host__ __device__ int32_t TouchState::get_code(ArithEnv &arith, const evm_word_t *address, byte_array_t &byte_code) { account_t *account_ptr = nullptr; int32_t error_code = get_account(arith, address, account_ptr, ACCOUNT_BYTE_CODE_FLAG); if (error_code == ERROR_SUCCESS) { @@ -111,7 +118,8 @@ __host__ __device__ int32_t TouchState::get_code(ArithEnv &arith, const bn_t &ad return error_code; } -__host__ __device__ int32_t TouchState::get_value(ArithEnv &arith, const bn_t &address, const bn_t &key, bn_t &value) { +__host__ __device__ int32_t TouchState::get_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, + bn_t &value) { poke_value(arith, address, key, value); // #ifdef __CUDA_ARCH__ // printf("TouchState::get_value %d\n", threadIdx.x); @@ -122,7 +130,7 @@ __host__ __device__ int32_t TouchState::get_value(ArithEnv &arith, const bn_t &a return this->set_warm_key(arith, address, key, value); } -__host__ __device__ int32_t TouchState::poke_value(ArithEnv &arith, const bn_t &address, const bn_t &key, +__host__ __device__ int32_t TouchState::poke_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, bn_t &value) const { account_t *account_ptr = nullptr; const TouchState *tmp = this; @@ -136,12 +144,12 @@ __host__ __device__ int32_t TouchState::poke_value(ArithEnv &arith, const bn_t & return _world_state->get_value(arith, address, key, value); } -__host__ __device__ int32_t TouchState::poke_original_value(ArithEnv &arith, const bn_t &address, const bn_t &key, +__host__ __device__ int32_t TouchState::poke_original_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, bn_t &value) const { return _world_state->get_value(arith, address, key, value); } -__host__ __device__ int32_t TouchState::poke_balance(ArithEnv &arith, const bn_t &address, bn_t &balance) const { +__host__ __device__ int32_t TouchState::poke_balance(ArithEnv &arith, const evm_word_t *address, bn_t &balance) const { account_t *account_ptr = nullptr; const TouchState *tmp = this; @@ -164,12 +172,13 @@ __host__ __device__ int32_t TouchState::poke_balance(ArithEnv &arith, const bn_t return ERROR_SUCCESS; } -__host__ __device__ bool TouchState::is_warm_account(ArithEnv &arith, const bn_t &address) const { +__host__ __device__ bool TouchState::is_warm_account(ArithEnv &arith, const evm_word_t *address) const { + if (*address < EVM_PRECOMPILED_CONTRACTS + 1 && !(*address == 0)) return true; account_t *account_ptr = nullptr; return (poke_account(arith, address, account_ptr) == ERROR_SUCCESS); } -__host__ __device__ bool TouchState::is_warm_key(ArithEnv &arith, const bn_t &address, const bn_t &key) const { +__host__ __device__ bool TouchState::is_warm_key(ArithEnv &arith, const evm_word_t *address, const bn_t &key) const { account_t *account_ptr = nullptr; bn_t value; const TouchState *tmp = this; @@ -182,13 +191,13 @@ __host__ __device__ bool TouchState::is_warm_key(ArithEnv &arith, const bn_t &ad return false; } -__host__ __device__ bool TouchState::set_warm_account(ArithEnv &arith, const bn_t &address) { +__host__ __device__ bool TouchState::set_warm_account(ArithEnv &arith, const evm_word_t *address) { account_t *account_ptr = nullptr; if (poke_account(arith, address, account_ptr)) { add_account(arith, address, account_ptr, ACCOUNT_BALANCE_FLAG); } } -__host__ __device__ bool TouchState::set_warm_key(ArithEnv &arith, const bn_t &address, const bn_t &key, +__host__ __device__ bool TouchState::set_warm_key(ArithEnv &arith, const evm_word_t *address, const bn_t &key, const bn_t &value) { account_t *account_ptr = nullptr; if (_state->get_account(arith, address, account_ptr, ACCOUNT_STORAGE_FLAG) != ERROR_SUCCESS) { @@ -203,7 +212,7 @@ __host__ __device__ bool TouchState::set_warm_key(ArithEnv &arith, const bn_t &a // get_account(arith, address, account_ptr, ACCOUNT_STORAGE_FLAG, true); account_ptr->set_storage_value(arith, key, value); } -__host__ __device__ int32_t TouchState::set_balance(ArithEnv &arith, const bn_t &address, const bn_t &balance) { +__host__ __device__ int32_t TouchState::set_balance(ArithEnv &arith, const evm_word_t *address, const bn_t &balance) { account_t *account_ptr = nullptr; if (_state->get_account(arith, address, account_ptr, ACCOUNT_BALANCE_FLAG) != ERROR_SUCCESS) { // printf("TouchState::set_balance - get_account - account_ptr: %p\n", account_ptr); @@ -224,7 +233,7 @@ __host__ __device__ int32_t TouchState::set_balance(ArithEnv &arith, const bn_t return ERROR_SUCCESS; } -__host__ __device__ int32_t TouchState::set_nonce(ArithEnv &arith, const bn_t &address, const bn_t &nonce) { +__host__ __device__ int32_t TouchState::set_nonce(ArithEnv &arith, const evm_word_t *address, const bn_t &nonce) { account_t *account_ptr = nullptr; if (_state->get_account(arith, address, account_ptr, ACCOUNT_NONCE_FLAG) != ERROR_SUCCESS) { // printf("touch state cannot find account\n"); @@ -237,7 +246,8 @@ __host__ __device__ int32_t TouchState::set_nonce(ArithEnv &arith, const bn_t &a return ERROR_SUCCESS; } -__host__ __device__ int32_t TouchState::set_code(ArithEnv &arith, const bn_t &address, const byte_array_t &byte_code) { +__host__ __device__ int32_t TouchState::set_code(ArithEnv &arith, const evm_word_t *address, + const byte_array_t &byte_code) { account_t *account_ptr = nullptr; if (_state->get_account(arith, address, account_ptr, ACCOUNT_BYTE_CODE_FLAG) != ERROR_SUCCESS) { add_account(arith, address, account_ptr, ACCOUNT_BYTE_CODE_FLAG); @@ -247,7 +257,7 @@ __host__ __device__ int32_t TouchState::set_code(ArithEnv &arith, const bn_t &ad return ERROR_SUCCESS; } -__host__ __device__ int32_t TouchState::set_storage_value(ArithEnv &arith, const bn_t &address, const bn_t &key, +__host__ __device__ int32_t TouchState::set_storage_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, const bn_t &value) { account_t *account_ptr = nullptr; _world_state->get_account(arith, address, account_ptr); @@ -255,9 +265,7 @@ __host__ __device__ int32_t TouchState::set_storage_value(ArithEnv &arith, const add_account(arith, address, account_ptr, ACCOUNT_STORAGE_FLAG); } __SYNC_THREADS__ - // #ifdef __CUDA_ARCH__ - // printf("TouchState::set_storage_value after add account %d %p\n" ,threadIdx.x, account_ptr); - // #endif + // __ONE_THREAD_PER_INSTANCE(printf("Set storage value %p %d\n", account_ptr, THREADIDX);); account_ptr->set_storage_value(arith, key, value); return ERROR_SUCCESS; } @@ -321,21 +329,21 @@ __host__ __device__ int32_t TouchState::update(ArithEnv &arith, TouchState *othe return _state->update(arith, *(other->_state)); } -__host__ __device__ bool TouchState::is_empty_account(ArithEnv &arith, const bn_t &address) { +__host__ __device__ bool TouchState::is_empty_account(ArithEnv &arith, const evm_word_t *address) { account_t *account_ptr = nullptr; poke_account(arith, address, account_ptr, true); uint32_t result = account_ptr != nullptr ? account_ptr->is_empty() : 1; return result; } -__host__ __device__ bool TouchState::is_empty_account_create(ArithEnv &arith, const bn_t &address) { +__host__ __device__ bool TouchState::is_empty_account_create(ArithEnv &arith, const evm_word_t *address) { account_t *account_ptr = nullptr; poke_account(arith, address, account_ptr, true); uint32_t result = account_ptr != nullptr ? account_ptr->is_empty_create() : 1; return result; } -__host__ __device__ int32_t TouchState::is_deleted_account(ArithEnv &arith, const bn_t &address) { +__host__ __device__ int32_t TouchState::is_deleted_account(ArithEnv &arith, const evm_word_t *address) { return ERROR_SUCCESS; } @@ -344,7 +352,8 @@ __host__ __device__ CuEVM::contract_storage_t TouchState::get_entire_storage(Ari return _state->accounts[account_index].storage; } -__host__ __device__ int32_t TouchState::transfer(ArithEnv &arith, const bn_t &from, const bn_t &to, const bn_t &value) { +__host__ __device__ int32_t TouchState::transfer(ArithEnv &arith, const evm_word_t *from, const evm_word_t *to, + const bn_t &value) { bn_t from_balance, to_balance; // #ifdef __CUDA_ARCH__ // printf("TouchState::transfer %d\n", threadIdx.x); diff --git a/CuEVM/src/state/world_state.cu b/CuEVM/src/state/world_state.cu index ab9ca01..27a503b 100644 --- a/CuEVM/src/state/world_state.cu +++ b/CuEVM/src/state/world_state.cu @@ -7,19 +7,54 @@ #include namespace CuEVM { -__host__ __device__ int32_t -WorldState::get_account(ArithEnv &arith, const bn_t &address, - CuEVM::account_t *&account_ptr) { +__host__ __device__ int32_t WorldState::get_account(ArithEnv &arith, const evm_word_t *address, + CuEVM::account_t *&account_ptr) { return _state->get_account(arith, address, account_ptr); } -__host__ __device__ int32_t WorldState::get_value(ArithEnv &arith, - const bn_t &address, - const bn_t &key, +__host__ __device__ int32_t WorldState::get_value(ArithEnv &arith, const evm_word_t *address, const bn_t &key, bn_t &value) { account_t *account_ptr = nullptr; cgbn_set_ui32(arith.env, value, 0); - return (_state->get_account(arith, address, account_ptr) || - account_ptr->get_storage_value(arith, key, value)); + return (_state->get_account(arith, address, account_ptr) || account_ptr->get_storage_value(arith, key, value)); +} + +__host__ __device__ int32_t WorldState::update(ArithEnv &arith, const CuEVM::state_access_t *other) { + return _state->update(arith, other->accounts, other->flags, other->no_accounts); +} + +__host__ __device__ void WorldState::serialize_data(ArithEnv &arith, serialized_worldstate_data *data) { + data->no_accounts = _state->no_accounts; + for (uint32_t idx = 0; idx < _state->no_accounts; idx++) { + account_t *account_ptr = &_state->accounts[idx]; + account_ptr->address.address_to_hex(data->addresses[idx]); + account_ptr->balance.to_hex(data->balance[idx]); + data->nonce[idx] = account_ptr->nonce._limbs[0]; // check if limbs 0 + if (account_ptr->storage.size > 0) { + for (uint32_t idx_storage = 0; idx_storage < account_ptr->storage.size; idx_storage++) { + account_ptr->storage.storage[idx_storage].key.to_hex( + data->storage_keys[data->no_storage_elements + idx_storage]); + account_ptr->storage.storage[idx_storage].value.to_hex( + data->storage_values[data->no_storage_elements + idx_storage]); + data->storage_indexes[data->no_storage_elements + idx_storage] = idx; + } + } + data->no_storage_elements += account_ptr->storage.size; + } +} +__host__ void serialized_worldstate_data::print() { + printf("\nPrinting serialized worldstate data\n"); + printf("no_accounts: %d\n", no_accounts); + printf("no_storage_elements: %d\n", no_storage_elements); + for (uint32_t idx = 0; idx < no_accounts; idx++) { + printf("address: %s\n", addresses[idx]); + printf("balance: %s\n", balance[idx]); + printf("nonce: %d\n", nonce[idx]); + } + for (uint32_t idx = 0; idx < no_storage_elements; idx++) { + printf("storage_key: %s\n", storage_keys[idx]); + printf("storage_value: %s\n", storage_values[idx]); + printf("storage_index: %d\n", storage_indexes[idx]); + } } } // namespace CuEVM diff --git a/CuEVM/src/tracer.cu b/CuEVM/src/tracer.cu index 4dda068..e09d562 100644 --- a/CuEVM/src/tracer.cu +++ b/CuEVM/src/tracer.cu @@ -5,10 +5,109 @@ #include #include +#include #include #include namespace CuEVM::utils { + +__host__ __device__ void simplified_trace_data::start_operation(const uint32_t pc, const uint8_t op, + const CuEVM::evm_stack_t &stack_ptr) { + if (no_events >= MAX_TRACE_EVENTS) return; + events[no_events].pc = pc; + events[no_events].op = op; + if (op != OP_INVALID && op != OP_SELFDESTRUCT) { + // printf("add new operation, src data %d \n", THREADIDX); + // printf("stack size %d\n", stack_ptr.size()); + + events[no_events].operand_1 = *stack_ptr.get_address_at_index(1); + events[no_events].operand_2 = *stack_ptr.get_address_at_index(2); + } +} + +__host__ __device__ void simplified_trace_data::record_branch(uint32_t pc_src, uint32_t pc_dst, uint32_t pc_missed) { + if (no_branches >= MAX_BRANCHES_TRACING) no_branches = 0; + branches[no_branches].pc_src = pc_src; + branches[no_branches].pc_dst = pc_dst; + branches[no_branches].pc_missed = pc_missed; + branches[no_branches].distance = last_distance; + // printf("record branch pc_src %u pc_dst %u distance %s\n", pc_src, pc_dst, + // branches[no_branches].distance.to_hex()); + no_branches++; +} + +__host__ __device__ void simplified_trace_data::record_distance(ArithEnv &arith, uint8_t op, + const CuEVM::evm_stack_t &stack_ptr) { + bn_t distance, op1, op2; + uint32_t stack_size = stack_ptr.size(); + + cgbn_load(arith.env, op1, stack_ptr.get_address_at_index(1)); + cgbn_load(arith.env, op2, stack_ptr.get_address_at_index(2)); + + if (cgbn_compare(arith.env, op1, op2) >= 1) + cgbn_sub(arith.env, distance, op1, op2); + else + cgbn_sub(arith.env, distance, op2, op1); + + if (op != OP_EQ) cgbn_add_ui32(arith.env, distance, distance, 1); + + cgbn_store(arith.env, &last_distance, distance); +} + +__host__ __device__ void simplified_trace_data::finish_operation(const CuEVM::evm_stack_t &stack_ptr, + uint32_t error_code) { + if (no_events >= MAX_TRACE_EVENTS) return; + if (events[no_events].op < OP_REVERT && events[no_events].op != OP_SSTORE) + events[no_events].res = *stack_ptr.get_address_at_index(1); + no_events++; +} +__host__ __device__ void simplified_trace_data::start_call(uint32_t pc, evm_message_call_t *message_call_ptr) { + if (no_calls >= MAX_CALLS_TRACING) return; + // add address and increment current_address_idx + // addresses[current_address_idx] = cached_call_state->addresses[cached_call_state->current_address_idx]; + // printf("start call simplified trace data pc %d op %d\n", pc, message_call_ptr->call_type); + calls[no_calls].sender = message_call_ptr->sender; + calls[no_calls].receiver = message_call_ptr->recipient; + calls[no_calls].pc = pc; + calls[no_calls].op = message_call_ptr->call_type; + calls[no_calls].value = message_call_ptr->value; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + no_calls++; + __ONE_GPU_THREAD_END__ +} +__host__ __device__ void simplified_trace_data::finish_call(uint8_t success) { + if (no_calls > MAX_CALLS_TRACING) return; + __ONE_GPU_THREAD_WOSYNC_BEGIN__ + + // printf("no_calls %u \n", no_calls); + for (int i = no_calls - 1; i >= 0; i--) { + if (calls[i].success == UINT8_MAX) { + calls[i].success = success; + break; + } + } + __ONE_GPU_THREAD_END__ +} +__host__ __device__ void simplified_trace_data::print() { + printf("no_events %u\n", no_events); + printf("no_calls %u\n", no_calls); + printf("events\n"); + for (uint32_t i = 0; i < no_events; i++) { + printf("pc %u op %u operand_1 %s operand_2 %s res %s\n", events[i].pc, events[i].op, + events[i].operand_1.to_hex(), events[i].operand_2.to_hex(), events[i].res.to_hex()); + } + printf("calls\n"); + for (uint32_t i = 0; i < no_calls; i++) { + printf("pc %u op %u sender %s receiver %s value %s success %u\n", calls[i].pc, calls[i].op, + calls[i].sender.to_hex(), calls[i].receiver.to_hex(), calls[i].value.to_hex(), calls[i].success); + } + printf("branches\n"); + for (uint32_t i = 0; i < no_branches; i++) { + printf("pc_src %u pc_dst %u distance %s\n", branches[i].pc_src, branches[i].pc_dst, + branches[i].distance.to_hex()); + } +} + __host__ cJSON *trace_data_t::to_json() { char *hex_string_ptr = new char[CuEVM::word_size * 2 + 3]; cJSON *json = cJSON_CreateObject(); @@ -109,15 +208,15 @@ __host__ __device__ tracer_t::~tracer_t() { } __host__ __device__ void tracer_t::grow() { - trace_data_t *new_data; + __SHARED_MEMORY__ trace_data_t *new_data[CGBN_IBP]; __ONE_GPU_THREAD_WOSYNC_BEGIN__ - new_data = new trace_data_t[capacity + 128]; + new_data[INSTANCE_IDX_PER_BLOCK] = new trace_data_t[capacity + 128]; if (data != nullptr) { - memcpy(new_data, data, sizeof(trace_data_t) * size); + memcpy(new_data[INSTANCE_IDX_PER_BLOCK], data, sizeof(trace_data_t) * size); delete[] data; } __ONE_GPU_THREAD_END__ - data = new_data; + data = new_data[INSTANCE_IDX_PER_BLOCK]; __SYNC_THREADS__ capacity += 128; } @@ -130,13 +229,13 @@ __host__ __device__ uint32_t tracer_t::start_operation(ArithEnv &arith, const ui if (size == capacity) { grow(); } - // #ifdef __CUDA_ARCH__ - // printf("tracer op %d idx %d after grow\n", op, threadIdx.x); - // #endif + + // printf("tracer op %d idx %d size %d after grow\n", op, THREADIDX, size); + __ONE_GPU_THREAD_WOSYNC_BEGIN__ data[size].pc = pc; data[size].op = op; - data[size].mem_size = memory.get_size(); + data[size].mem_size = memory.size; __ONE_GPU_THREAD_END__ bn_t gas; cgbn_sub(arith.env, gas, gas_limit, gas_used); @@ -149,8 +248,9 @@ __host__ __device__ uint32_t tracer_t::start_operation(ArithEnv &arith, const ui data[size].stack_size = stack.size(); if (data[size].stack_size > 0) { data[size].stack = new evm_word_t[data[size].stack_size]; - // std::copy(stack.stack_base, stack.stack_base + stack.size(), data[size].stack); - memcpy(data[size].stack, stack.stack_base, sizeof(evm_word_t) * data[size].stack_size); + stack.extract_data(data[size].stack); + // // std::copy(stack.stack_base, stack.stack_base + stack.size(), data[size].stack); + // memcpy(data[size].stack, stack.stack_base, sizeof(evm_word_t) * data[size].stack_size); } data[size].depth = depth; diff --git a/CuEVM/src/utils/arith.cu b/CuEVM/src/utils/arith.cu index 3a494f4..9da6535 100644 --- a/CuEVM/src/utils/arith.cu +++ b/CuEVM/src/utils/arith.cu @@ -62,6 +62,7 @@ __host__ __device__ int32_t cgbn_get_uint32_t(env_t env, uint32_t &dst, const bn return cgbn_compare(env, tmp, src) == 0 ? ERROR_SUCCESS : ERROR_VALUE_OVERFLOW; } +// deprecated, todo fix this __host__ __device__ int32_t cgbn_set_byte_array_t(env_t env, bn_t &out, const byte_array_t &byte_array) { uint32_t word_size = env_t::BITS / 8; if (byte_array.size != word_size) return ERROR_INVALID_WORD_SIZE; @@ -131,8 +132,8 @@ __host__ __device__ void evm_address_conversion(ArithEnv &arith, bn_t &address) cgbn_bitwise_mask_and(arith.env, address, address, CuEVM::address_bits); } __host__ __device__ void print_bnt(ArithEnv &arith, const bn_t &bn) { - __SHARED_MEMORY__ evm_word_t tmp_word; - cgbn_store(arith.env, &tmp_word, bn); - tmp_word.print(); + __SHARED_MEMORY__ evm_word_t tmp_word[CGBN_IBP]; + cgbn_store(arith.env, &tmp_word[INSTANCE_IDX_PER_BLOCK], bn); + tmp_word[INSTANCE_IDX_PER_BLOCK].print(); } } // namespace CuEVM \ No newline at end of file diff --git a/CuEVM/src/utils/evm_utils.cu b/CuEVM/src/utils/evm_utils.cu index df8a922..aeb21bd 100644 --- a/CuEVM/src/utils/evm_utils.cu +++ b/CuEVM/src/utils/evm_utils.cu @@ -1,19 +1,75 @@ -#include #include #include #include namespace CuEVM::utils { +__host__ __device__ int32_t get_contract_address_create_word(ArithEnv &arith, evm_word_t *contract_address, + evm_word_t *sender_address, evm_word_t *sender_nonce) { + CuEVM::byte_array_t sender_address_bytes, sender_nonce_bytes; + sender_address->to_byte_array_t(sender_address_bytes); + sender_nonce->to_byte_array_t(sender_nonce_bytes); + + uint32_t nonce_bytes; + for (nonce_bytes = CuEVM::word_size; nonce_bytes > 0; nonce_bytes--) { + if (sender_nonce_bytes.data[CuEVM::word_size - nonce_bytes] != 0) { + break; + } + } + + uint8_t rlp_list[1 + 1 + CuEVM::address_size + 1 + CuEVM::word_size]; + rlp_list[1] = 0x80 + CuEVM::address_size; + for (uint32_t idx = 0; idx < CuEVM::address_size; idx++) { + rlp_list[2 + idx] = sender_address_bytes.data[CuEVM::word_size - CuEVM::address_size + idx]; + } + + uint32_t rlp_list_length; + // 21 is from the address the 20 bytes is the length of the address + // and the 1 byte is the 0x80 + length of the address (20) + // if (cgbn_compare_ui32(arith.env, sender_nonce, 128) < 0) { + if (sender_nonce->_limbs[0] < 128) { + rlp_list_length = 1 + CuEVM::address_size + 1; + if (sender_nonce->_limbs[0] == 0) { + rlp_list[2 + CuEVM::address_size] = 0x80; // special case for nonce 0 + } else { + rlp_list[2 + CuEVM::address_size] = sender_nonce_bytes.data[CuEVM::word_size - 1]; + } + } else { + // 1 byte for the length of the nonce + // 0x80 + length of the nonce + rlp_list_length = 21 + 1 + nonce_bytes; + rlp_list[2 + CuEVM::address_size] = 0x80 + nonce_bytes; + for (uint8_t idx = 0; idx < nonce_bytes; idx++) { + rlp_list[2 + CuEVM::address_size + 1 + idx] = sender_nonce_bytes.data[CuEVM::word_size - nonce_bytes + idx]; + } + } + rlp_list[0] = 0xc0 + rlp_list_length; + + CuEVM::byte_array_t hash_address_bytes(CuEVM::hash_size); + CuCrypto::keccak::sha3(&(rlp_list[0]), rlp_list_length + 1, hash_address_bytes.data, CuEVM::hash_size); + + // cgbn_set_byte_array_t(arith.env, contract_address, hash_address_bytes); + // cgbn_bitwise_mask_and(arith.env, contract_address, contract_address, CuEVM::address_bits); + // todo check replacement + // __ONE_THREAD_PER_INSTANCE(printf("\n\nhash_address_bytes\n");); + hash_address_bytes.print(); + contract_address->from_byte_array_t_loop(hash_address_bytes, BIG_ENDIAN); + for (uint32_t idx = CuEVM::cgbn_limbs - 3; idx < CuEVM::cgbn_limbs; idx++) { + contract_address->_limbs[idx] = 0; + } + + return ERROR_SUCCESS; +} + __host__ __device__ int32_t get_contract_address_create(ArithEnv &arith, bn_t &contract_address, const bn_t &sender_address, const bn_t &sender_nonce) { - __SHARED_MEMORY__ evm_word_t sender_address_word; - cgbn_store(arith.env, (cgbn_evm_word_t_ptr)(&sender_address_word), sender_address); - __SHARED_MEMORY__ evm_word_t sender_nonce_word; - cgbn_store(arith.env, &sender_nonce_word, sender_nonce); + __SHARED_MEMORY__ evm_word_t sender_address_word[CGBN_IBP]; + cgbn_store(arith.env, (cgbn_evm_word_t_ptr)(&sender_address_word[INSTANCE_IDX_PER_BLOCK]), sender_address); + __SHARED_MEMORY__ evm_word_t sender_nonce_word[CGBN_IBP]; + cgbn_store(arith.env, &sender_nonce_word[INSTANCE_IDX_PER_BLOCK], sender_nonce); CuEVM::byte_array_t sender_address_bytes, sender_nonce_bytes; - sender_address_word.to_byte_array_t(sender_address_bytes); - sender_nonce_word.to_byte_array_t(sender_nonce_bytes); + sender_address_word[INSTANCE_IDX_PER_BLOCK].to_byte_array_t(sender_address_bytes); + sender_nonce_word[INSTANCE_IDX_PER_BLOCK].to_byte_array_t(sender_nonce_bytes); uint32_t nonce_bytes; for (nonce_bytes = CuEVM::word_size; nonce_bytes > 0; nonce_bytes--) { @@ -23,6 +79,11 @@ __host__ __device__ int32_t get_contract_address_create(ArithEnv &arith, bn_t &c } // TODO: this might work only for CuEVM::word_size == 32 + // printf("get contract address create\n"); + // sender_address_word[INSTANCE_IDX_PER_BLOCK].print(); + // printf("sender nonce\n"); + // sender_nonce_word[INSTANCE_IDX_PER_BLOCK].print(); + uint8_t rlp_list[1 + 1 + CuEVM::address_size + 1 + CuEVM::word_size]; rlp_list[1] = 0x80 + CuEVM::address_size; for (uint32_t idx = 0; idx < CuEVM::address_size; idx++) { @@ -53,25 +114,29 @@ __host__ __device__ int32_t get_contract_address_create(ArithEnv &arith, bn_t &c CuEVM::byte_array_t hash_address_bytes(CuEVM::hash_size); CuCrypto::keccak::sha3(&(rlp_list[0]), rlp_list_length + 1, hash_address_bytes.data, CuEVM::hash_size); - cgbn_set_byte_array_t(arith.env, contract_address, hash_address_bytes); - cgbn_bitwise_mask_and(arith.env, contract_address, contract_address, CuEVM::address_bits); -#ifdef __CUDA_ARCH__ - printf("contract_address: thread id %d ", threadIdx.x); - print_bnt(arith, contract_address); -#endif + // cgbn_set_byte_array_t(arith.env, contract_address, hash_address_bytes); + // cgbn_bitwise_mask_and(arith.env, contract_address, contract_address, CuEVM::address_bits); + // todo check replacement + // __ONE_THREAD_PER_INSTANCE(printf("\n\nhash_address_bytes\n");); + // hash_address_bytes.print(); + sender_address_word[INSTANCE_IDX_PER_BLOCK].from_byte_array_t(hash_address_bytes, BIG_ENDIAN); + if (THREAD_IDX_PER_INSTANCE >= CuEVM::cgbn_limbs - 3 && THREAD_IDX_PER_INSTANCE < CuEVM::cgbn_limbs) + sender_address_word[INSTANCE_IDX_PER_BLOCK]._limbs[THREAD_IDX_PER_INSTANCE] = 0; + cgbn_load(arith.env, contract_address, &sender_address_word[INSTANCE_IDX_PER_BLOCK]); + return ERROR_SUCCESS; } __host__ __device__ int32_t get_contract_address_create2(ArithEnv &arith, bn_t &contract_address, const bn_t &sender_address, const bn_t &salt, const CuEVM::byte_array_t &init_code) { - __SHARED_MEMORY__ evm_word_t sender_address_word; - cgbn_store(arith.env, &sender_address_word, sender_address); - __SHARED_MEMORY__ evm_word_t salt_word; - cgbn_store(arith.env, &salt_word, salt); + __SHARED_MEMORY__ evm_word_t sender_address_word[CGBN_IBP]; + cgbn_store(arith.env, &sender_address_word[INSTANCE_IDX_PER_BLOCK], sender_address); + __SHARED_MEMORY__ evm_word_t salt_word[CGBN_IBP]; + cgbn_store(arith.env, &salt_word[INSTANCE_IDX_PER_BLOCK], salt); CuEVM::byte_array_t sender_address_bytes, salt_bytes; - sender_address_word.to_byte_array_t(sender_address_bytes); - salt_word.to_byte_array_t(salt_bytes); + sender_address_word[INSTANCE_IDX_PER_BLOCK].to_byte_array_t(sender_address_bytes); + salt_word[INSTANCE_IDX_PER_BLOCK].to_byte_array_t(salt_bytes); uint32_t total_bytes = 1 + CuEVM::address_size + CuEVM::word_size + CuEVM::hash_size; @@ -93,8 +158,12 @@ __host__ __device__ int32_t get_contract_address_create2(ArithEnv &arith, bn_t & CuEVM::byte_array_t hash_input_data(CuEVM::hash_size); CuCrypto::keccak::sha3(input_data.data, total_bytes, hash_input_data.data, CuEVM::hash_size); - cgbn_set_byte_array_t(arith.env, contract_address, hash_input_data); - cgbn_bitwise_mask_and(arith.env, contract_address, contract_address, CuEVM::address_bits); + sender_address_word[INSTANCE_IDX_PER_BLOCK].from_byte_array_t(hash_input_data, BIG_ENDIAN); + if (THREAD_IDX_PER_INSTANCE >= CuEVM::cgbn_limbs - 3 && THREAD_IDX_PER_INSTANCE < CuEVM::cgbn_limbs) + sender_address_word[INSTANCE_IDX_PER_BLOCK]._limbs[THREAD_IDX_PER_INSTANCE] = 0; + cgbn_load(arith.env, contract_address, &sender_address_word[INSTANCE_IDX_PER_BLOCK]); + // cgbn_set_byte_array_t(arith.env, contract_address, hash_input_data); + // cgbn_bitwise_mask_and(arith.env, contract_address, contract_address, CuEVM::address_bits); return ERROR_SUCCESS; } diff --git a/samples/README.md b/fuzzing/README.md similarity index 100% rename from samples/README.md rename to fuzzing/README.md diff --git a/fuzzing/binary/binary_v1/libcuevm.so b/fuzzing/binary/binary_v1/libcuevm.so new file mode 120000 index 0000000..a736a31 --- /dev/null +++ b/fuzzing/binary/binary_v1/libcuevm.so @@ -0,0 +1 @@ +libcuevm.so_gpu \ No newline at end of file diff --git a/fuzzing/binary/binary_v1/libcuevm.so_colabt4_cpu b/fuzzing/binary/binary_v1/libcuevm.so_colabt4_cpu new file mode 100644 index 0000000..607f19f Binary files /dev/null and b/fuzzing/binary/binary_v1/libcuevm.so_colabt4_cpu differ diff --git a/fuzzing/binary/binary_v1/libcuevm.so_colabt4_gpu b/fuzzing/binary/binary_v1/libcuevm.so_colabt4_gpu new file mode 100644 index 0000000..ff8bef4 Binary files /dev/null and b/fuzzing/binary/binary_v1/libcuevm.so_colabt4_gpu differ diff --git a/fuzzing/binary/binary_v1/libcuevm.so_cpu b/fuzzing/binary/binary_v1/libcuevm.so_cpu new file mode 100755 index 0000000..e9463ed Binary files /dev/null and b/fuzzing/binary/binary_v1/libcuevm.so_cpu differ diff --git a/fuzzing/binary/binary_v1/libcuevm.so_gpu b/fuzzing/binary/binary_v1/libcuevm.so_gpu new file mode 100755 index 0000000..34de505 Binary files /dev/null and b/fuzzing/binary/binary_v1/libcuevm.so_gpu differ diff --git a/fuzzing/binary/libcuevm.so b/fuzzing/binary/libcuevm.so new file mode 100755 index 0000000..d002861 Binary files /dev/null and b/fuzzing/binary/libcuevm.so differ diff --git a/fuzzing/configurations/call_add.json b/fuzzing/configurations/call_add.json new file mode 100644 index 0000000..9aa5277 --- /dev/null +++ b/fuzzing/configurations/call_add.json @@ -0,0 +1,72 @@ +{ + "env": { + "currentBaseFee": "0x0a", + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty": "0x020000", + "currentGasLimit": "0x05f5e100", + "currentNumber": "0x01", + "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", + "currentTimestamp": "0x03e8", + "previousHash": "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre": { + "0x0000000000000000000000000000000000000100": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160005500", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000101": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x60047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160005500", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000102": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160005500", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000103": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x600060000160005500", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000104": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60010160005500", + "nonce": "0x00", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x", + "nonce": "0x00", + "storage": {} + }, + "0xcccccccccccccccccccccccccccccccccccccccc": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x600060006000600060006004356101000162fffffff100", + "nonce": "0x00", + "storage": {} + } + }, + "transaction": { + "data": [ + "0x693c61390000000000000000000000000000000000000000000000000000000000000000" + ], + "gasLimit": [ + "0x04c4b400" + ], + "gasPrice": "0x0a", + "nonce": "0x00", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to": "0xcccccccccccccccccccccccccccccccccccccccc", + "value": [ + "0x01" + ] + } +} \ No newline at end of file diff --git a/fuzzing/configurations/calldata_load.json b/fuzzing/configurations/calldata_load.json new file mode 100644 index 0000000..b4c2dd3 --- /dev/null +++ b/fuzzing/configurations/calldata_load.json @@ -0,0 +1,93 @@ +{ + "_info": { + "comment": "Ori Pomerantz qbzzt1@gmail.com", + "filling-rpc-server": "evm version 1.11.4-unstable-e14043db-20230308", + "filling-tool-version": "retesteth-0.3.0-shanghai+commit.fd2c0a83.Linux.g++", + "generatedTestHash": "ddf6a0e4a488da02438f8b2cc9f5a05ae5f23713731c08e33fa2643c2cf47932", + "labels": { + "0": "two_bytes", + "1": "word_n_byte", + "2": "34_bytes" + }, + "lllcversion": "Version: 0.5.14-develop.2022.7.30+commit.a096d7a9.Linux.g++", + "solidity": "Version: 0.8.17+commit.8df45f5f.Linux.g++", + "source": "src/GeneralStateTestsFiller/VMTests/vmTests/calldataloadFiller.yml", + "sourceHash": "dcb723a4856753fadfe51482dd3f64a559e317456761ee7c739d1b6ca02ad9cf" + }, + "env": { + "currentBaseFee": "0x0a", + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty": "0x020000", + "currentGasLimit": "0x05f5e100", + "currentNumber": "0x01", + "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", + "currentTimestamp": "0x03e8", + "previousHash": "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre": { + "0x0000000000000000000000000000000000000100": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x602560005360606001536000600060026000600061020062fffffff100", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000101": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260236020536000600060216000600061020162fffffff100", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000102": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x7f123456789abcdef0000000000000000000000000000000000000000000000000600052600060205360246021536000600060226000600061020562fffffff100", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000200": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x60003560005500", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000201": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x60013560005500", + "nonce": "0x00", + "storage": {} + }, + "0x0000000000000000000000000000000000000205": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x60053560005500", + "nonce": "0x00", + "storage": {} + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x", + "nonce": "0x00", + "storage": {} + }, + "0xcccccccccccccccccccccccccccccccccccccccc": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x600060006000600060006004356101000162fffffff100", + "nonce": "0x00", + "storage": {} + } + }, + "transaction": { + "data": [ + "0x693c61390000000000000000000000000000000000000000000000000000000000000000" + ], + "gasLimit": [ + "0x04c4b400" + ], + "gasPrice": "0x0a", + "nonce": "0x00", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to": "0xcccccccccccccccccccccccccccccccccccccccc", + "value": [ + "0x01" + ] + } +} \ No newline at end of file diff --git a/samples/configurations/cross_contract.json b/fuzzing/configurations/cross_contract.json similarity index 100% rename from samples/configurations/cross_contract.json rename to fuzzing/configurations/cross_contract.json diff --git a/samples/configurations/default.json b/fuzzing/configurations/default.json similarity index 70% rename from samples/configurations/default.json rename to fuzzing/configurations/default.json index 6e3e18e..c687ff5 100644 --- a/samples/configurations/default.json +++ b/fuzzing/configurations/default.json @@ -2,7 +2,7 @@ "env": { "currentBaseFee": "0x0a", "currentBeaconRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", - "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentCoinbase": "0x0000000000000000000000000000000000c0ffee", "currentDifficulty": "0x020000", "currentGasLimit": "0x02540be400", "currentNumber": "0x01", @@ -13,27 +13,33 @@ }, "target_address": "0xcccccccccccccccccccccccccccccccccccccccc", "pre": { - "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0x0ba1a9ce0ba1a9ce", + "0x1111111111111111111111111111111111111111": { + "balance": "0x100000000000000000000000000000000000000000000000000", "code": "0x", "nonce": "0x00", "storage": {} }, "0xcccccccccccccccccccccccccccccccccccccccc": { - "balance": "0x0ba1a9ce0ba1a9ce", + "balance": "0x100000000000000000000000000000000000000000000000000", "code": "0x", "nonce": "0x00", "storage": {} } }, "transaction": { - "data": ["0x00"], - "gasLimit": ["0x04c4b400"], + "data": [ + "0x00" + ], + "gasLimit": [ + "0x04c4b400" + ], "gasPrice": "0x0a", "nonce": "0x00", "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "sender": "0x1111111111111111111111111111111111111111", "to": "0xcccccccccccccccccccccccccccccccccccccccc", - "value": ["0x00"] + "value": [ + "0x00" + ] } -} +} \ No newline at end of file diff --git a/samples/configurations/erc20.json b/fuzzing/configurations/erc20.json similarity index 100% rename from samples/configurations/erc20.json rename to fuzzing/configurations/erc20.json diff --git a/samples/configurations/overflow.json b/fuzzing/configurations/overflow.json similarity index 100% rename from samples/configurations/overflow.json rename to fuzzing/configurations/overflow.json diff --git a/fuzzing/configurations/sample_config.json b/fuzzing/configurations/sample_config.json new file mode 100644 index 0000000..31a27fc --- /dev/null +++ b/fuzzing/configurations/sample_config.json @@ -0,0 +1,7 @@ +{ + "contract_name": "Test", + "storage" : { + }, + "test_cases": [ + ] +} \ No newline at end of file diff --git a/samples/configurations/state_change.json b/fuzzing/configurations/state_change.json similarity index 100% rename from samples/configurations/state_change.json rename to fuzzing/configurations/state_change.json diff --git a/fuzzing/configurations/system_operation.json b/fuzzing/configurations/system_operation.json new file mode 100644 index 0000000..47d9504 --- /dev/null +++ b/fuzzing/configurations/system_operation.json @@ -0,0 +1,29 @@ +{ + "contract_name": "TestCrossContract", + "storage": {}, + "pre": { + "0x1000000000000000000000000000000000000000": { + "balance": "0x0ba1a9ce0ba1a9ce", + "code": "0x6011602201600460110260005560015561123460015561ffff60ff5500", + "nonce": "0x00", + "storage": {} + } + }, + "test_cases": [ + { + "function": "underflow", + "type": "exec", + "input_types": [ + "address", + "uint256" + ], + "input": [ + "0x1000000000000000000000000000000000000000", + "0x1234" + ], + "value": 300, + "sender": 0, + "receiver": "0x1000000000000000000000000000000000000000" + } + ] +} \ No newline at end of file diff --git a/fuzzing/configurations/test_branching.json b/fuzzing/configurations/test_branching.json new file mode 100644 index 0000000..13ab6f2 --- /dev/null +++ b/fuzzing/configurations/test_branching.json @@ -0,0 +1,30 @@ +{ + "contract_name": "TestBranching", + "storage": { + "0x00": "0x10" + }, + "test_cases": [ + { + "function": "test_branch", + "type": "exec", + "input_types": [ + "uint256" + ], + "input": [ + 10000 + ], + "sender": 0 + }, + { + "function": "test_branch", + "type": "exec", + "input_types": [ + "uint256" + ], + "input": [ + 12345 + ], + "sender": 0 + } + ] +} \ No newline at end of file diff --git a/fuzzing/contracts/branching.sol b/fuzzing/contracts/branching.sol new file mode 100644 index 0000000..beabd7b --- /dev/null +++ b/fuzzing/contracts/branching.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.7.0; +contract TestBranching { + uint public branch = 0; + function test_branch(uint input) public { + if (input < 10) branch = 1; + else { + if (input > 500) { + if (input == 2345) branch = 3; + else branch = 4; + } else branch = 2; + } + } + // function test_branch_1() public { + // branch = 1; + // } + + // function test_branch_2(uint input) public { + // if (input == 4567){ + // branch = 2; + // selfdestruct(msg.sender); + // } + // } + function test_branch_3(uint input) public { + if (input == 45678) { + branch = 2; + msg.sender.send(1 ether); + } + } +} diff --git a/samples/contracts/cross_contract.sol b/fuzzing/contracts/cross_contract.sol similarity index 100% rename from samples/contracts/cross_contract.sol rename to fuzzing/contracts/cross_contract.sol diff --git a/samples/contracts/erc20.sol b/fuzzing/contracts/erc20.sol similarity index 90% rename from samples/contracts/erc20.sol rename to fuzzing/contracts/erc20.sol index e70a20e..f542c70 100644 --- a/samples/contracts/erc20.sol +++ b/fuzzing/contracts/erc20.sol @@ -11,7 +11,10 @@ interface IERC20 { function transfer(address recipient, uint amount) external returns (bool); - function allowance(address owner, address spender) external view returns (uint); + function allowance( + address owner, + address spender + ) external view returns (uint); function approve(address spender, uint amount) external returns (bool); @@ -46,7 +49,11 @@ contract ERC20 is IERC20 { emit Approval(msg.sender, spender, amount); return true; } - function approve_from(address owner, address spender, uint amount) internal { + function approve_from( + address owner, + address spender, + uint amount + ) internal { allowance[owner][spender] = amount; } @@ -64,7 +71,7 @@ contract ERC20 is IERC20 { return true; } - function mint() external payable{ + function mint() external payable { // simple mint for testing purpose unchecked { balanceOf[msg.sender] += msg.value; @@ -88,5 +95,5 @@ contract ERC20 is IERC20 { } emit Transfer(msg.sender, address(0), amount); } - receive() external payable{} -} \ No newline at end of file + receive() external payable {} +} diff --git a/samples/contracts/overflow.sol b/fuzzing/contracts/overflow.sol similarity index 100% rename from samples/contracts/overflow.sol rename to fuzzing/contracts/overflow.sol diff --git a/samples/contracts/state_change.sol b/fuzzing/contracts/state_change.sol similarity index 100% rename from samples/contracts/state_change.sol rename to fuzzing/contracts/state_change.sol diff --git a/fuzzing/contracts/system_operations.sol b/fuzzing/contracts/system_operations.sol new file mode 100644 index 0000000..adf328b --- /dev/null +++ b/fuzzing/contracts/system_operations.sol @@ -0,0 +1,27 @@ +pragma solidity ^0.7.0; +// SPDX-License-Identifier: MIT +// for demonstration purpose + +contract TestCrossContract { + function test_call(address addr, uint condition) public payable { + bool res; + // if (condition == 0x1111) { + // (res, ) = addr.call{value: 1 ether}( + // abi.encodeWithSignature("increase()") + // ); + // } + // if (condition == 0x2222) { + // (res, ) = addr.delegatecall(abi.encodeWithSignature("increase()")); + // } + // if (condition == 0x3333) { + // //selfdestruct address addr + // selfdestruct(payable(addr)); + // } + //call address addr + (res, ) = addr.call(abi.encodeWithSignature("increase()")); + //call address addr with value 1 ether + + //delegatecall address addr + // (res, ) = addr.delegatecall(abi.encodeWithSignature("increase()")); + } +} diff --git a/fuzzing/contracts/test_bugs.sol b/fuzzing/contracts/test_bugs.sol new file mode 100644 index 0000000..69c2b38 --- /dev/null +++ b/fuzzing/contracts/test_bugs.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.7.0; +contract TestBug { + uint public branch = 0; + address test; + function bug_selfdestruct(uint input) public { + require(input == 4567); + branch = 2; + selfdestruct(msg.sender); + } + + function bug_unauthorized_send(uint input) public { + // msg.sender.transfer(1 ether); + // input = 40000 triggers the bug + if (input + 5678 == 45678) msg.sender.transfer(1 ether); + } + + function bug_txorigin(uint input) public { + if (input > 20000) test = tx.origin; + } + + function bug_overflow(uint input1, uint input2) public returns (uint) { + // overflow if input1%2 == 0 and input2%2 == 0 and input1 + input2 > 10000 + if (input1 % 2 == 0 && input2 % 2 == 0) + return input1 + input2 + (2 ** 256 - 10000); + } + function bug_underflow(uint input) public { + if (input < 100) branch = 0 - input; + } +} diff --git a/fuzzing/contracts/test_bugs_simple.sol b/fuzzing/contracts/test_bugs_simple.sol new file mode 100644 index 0000000..a3b3002 --- /dev/null +++ b/fuzzing/contracts/test_bugs_simple.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.7.0; +contract TestBug { + address test; + uint test_value; + function bug_selfdestruct() public { + test_value = 1; + selfdestruct(msg.sender); + } + + function bug_unauthorized_send() public { + test_value = 2; + msg.sender.transfer(1 ether); + } + + function bug_txorigin() public { + test_value = 3; + test = tx.origin; + } + + function bug_overflow(uint input) public returns (uint) { + test_value = 4; + uint res = input + (2 ** 256 - 1000); // overflow if input > 1000 + return res; + } + + function bug_underflow(uint input) public returns (uint) { + test_value = 5; + uint res = input - 10 ** 18; + return res; + } + + function bug_combined() public { + bug_overflow(10001); + bug_underflow(10001); + bug_txorigin(); + bug_unauthorized_send(); + // bug_selfdestruct(); + } +} diff --git a/samples/eth-tests/arith_loop.json b/fuzzing/eth-tests/arith_loop.json similarity index 100% rename from samples/eth-tests/arith_loop.json rename to fuzzing/eth-tests/arith_loop.json diff --git a/samples/eth-tests/arith_loop_write_mapping.json b/fuzzing/eth-tests/arith_loop_write_mapping.json similarity index 100% rename from samples/eth-tests/arith_loop_write_mapping.json rename to fuzzing/eth-tests/arith_loop_write_mapping.json diff --git a/samples/eth-tests/arith_loop_write_storage.json b/fuzzing/eth-tests/arith_loop_write_storage.json similarity index 100% rename from samples/eth-tests/arith_loop_write_storage.json rename to fuzzing/eth-tests/arith_loop_write_storage.json diff --git a/fuzzing/eth-tests/erc20_mint.json b/fuzzing/eth-tests/erc20_mint.json new file mode 100644 index 0000000..50e9e13 --- /dev/null +++ b/fuzzing/eth-tests/erc20_mint.json @@ -0,0 +1,60 @@ +{ + "erc20_mint": { + "env": { + "currentBaseFee": "0x0a", + "currentBeaconRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "currentCoinbase": "0x0000000000000000000000000000000000c0ffee", + "currentDifficulty": "0x020000", + "currentGasLimit": "0x02540be400", + "currentNumber": "0x01", + "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", + "currentTimestamp": "0x03e8", + "currentWithdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "previousHash": "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "post": { + "Shanghai": [ + { + "hash": "0xdec322e23f1e9e2193720a0aeaaa5273400f89f4f1106ced072906b45a116e7c", + "indexes": { + "data": 0, + "gas": 0, + "value": 0 + }, + "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "txbytes": "0xf861800a8404c4b40094cccccccccccccccccccccccccccccccccccccccc01001ca06939410fcd80efd44b8d819c37a4e460b38e39f37d99e1f09ccd9c25753ef79aa017a79fccc1ede0aae2dbb9f810acc5d6ece485338b3d695742b607a3b886a2b1" + } + ] + }, + "pre": { + "0x1111111111111111111111111111111111111111": { + "balance": "0x100000000000000000000000000000000000000000000000000", + "code": "0x", + "nonce": "0x00", + "storage": {} + }, + "0xcccccccccccccccccccccccccccccccccccccccc": { + "balance": "0x100000000000000000000000000000000000000000000000000", + "code": "0x6080604052600436106100a05760003560e01c8063313ce56711610064578063313ce5671461018657806342966c68146101b157806370a08231146101da57806395d89b4114610217578063a9059cbb14610242578063dd62ed3e1461027f576100a7565b806306fdde03146100ac578063095ea7b3146100d75780631249c58b1461011457806318160ddd1461011e57806323b872dd14610149576100a7565b366100a757005b600080fd5b3480156100b857600080fd5b506100c16102bc565b6040516100ce91906109da565b60405180910390f35b3480156100e357600080fd5b506100fe60048036038101906100f99190610a95565b61034a565b60405161010b9190610af0565b60405180910390f35b61011c61043c565b005b34801561012a57600080fd5b50610133610500565b6040516101409190610b1a565b60405180910390f35b34801561015557600080fd5b50610170600480360381019061016b9190610b35565b610506565b60405161017d9190610af0565b60405180910390f35b34801561019257600080fd5b5061019b61069c565b6040516101a89190610ba4565b60405180910390f35b3480156101bd57600080fd5b506101d860048036038101906101d39190610bbf565b6106af565b005b3480156101e657600080fd5b5061020160048036038101906101fc9190610bec565b610774565b60405161020e9190610b1a565b60405180910390f35b34801561022357600080fd5b5061022c61078c565b60405161023991906109da565b60405180910390f35b34801561024e57600080fd5b5061026960048036038101906102649190610a95565b61081a565b6040516102769190610af0565b60405180910390f35b34801561028b57600080fd5b506102a660048036038101906102a19190610c19565b610925565b6040516102b39190610b1a565b60405180910390f35b600380546102c990610c88565b80601f01602080910402602001604051908101604052809291908181526020018280546102f590610c88565b80156103425780601f1061031757610100808354040283529160200191610342565b820191906000526020600020905b81548152906001019060200180831161032557829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161042a9190610b1a565b60405180910390a36001905092915050565b34600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503460008082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef346040516104f69190610b1a565b60405180910390a3565b60005481565b600081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516106899190610b1a565b60405180910390a3600190509392505050565b600560009054906101000a900460ff1681565b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550806000808282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516107699190610b1a565b60405180910390a350565b60016020528060005260406000206000915090505481565b6004805461079990610c88565b80601f01602080910402602001604051908101604052809291908181526020018280546107c590610c88565b80156108125780601f106107e757610100808354040283529160200191610812565b820191906000526020600020905b8154815290600101906020018083116107f557829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516109139190610b1a565b60405180910390a36001905092915050565b6002602052816000526040600020602052806000526040600020600091509150505481565b600081519050919050565b600082825260208201905092915050565b60005b83811015610984578082015181840152602081019050610969565b60008484015250505050565b6000601f19601f8301169050919050565b60006109ac8261094a565b6109b68185610955565b93506109c6818560208601610966565b6109cf81610990565b840191505092915050565b600060208201905081810360008301526109f481846109a1565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610a2c82610a01565b9050919050565b610a3c81610a21565b8114610a4757600080fd5b50565b600081359050610a5981610a33565b92915050565b6000819050919050565b610a7281610a5f565b8114610a7d57600080fd5b50565b600081359050610a8f81610a69565b92915050565b60008060408385031215610aac57610aab6109fc565b5b6000610aba85828601610a4a565b9250506020610acb85828601610a80565b9150509250929050565b60008115159050919050565b610aea81610ad5565b82525050565b6000602082019050610b056000830184610ae1565b92915050565b610b1481610a5f565b82525050565b6000602082019050610b2f6000830184610b0b565b92915050565b600080600060608486031215610b4e57610b4d6109fc565b5b6000610b5c86828701610a4a565b9350506020610b6d86828701610a4a565b9250506040610b7e86828701610a80565b9150509250925092565b600060ff82169050919050565b610b9e81610b88565b82525050565b6000602082019050610bb96000830184610b95565b92915050565b600060208284031215610bd557610bd46109fc565b5b6000610be384828501610a80565b91505092915050565b600060208284031215610c0257610c016109fc565b5b6000610c1084828501610a4a565b91505092915050565b60008060408385031215610c3057610c2f6109fc565b5b6000610c3e85828601610a4a565b9250506020610c4f85828601610a4a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610ca057607f821691505b602082108103610cb357610cb2610c59565b5b5091905056fea2646970667358221220de3e75f39ece59e11de492394b0e52b51dcffa666beada6fb5db9c7ec45f681764736f6c63430008130033", + "nonce": "0x00", + "storage": {} + } + }, + "transaction": { + "data": [ + "0x1249c58b" + ], + "gasLimit": [ + "0x04c4b400" + ], + "gasPrice": "0x0a", + "nonce": "0x00", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "sender": "0x1111111111111111111111111111111111111111", + "to": "0xcccccccccccccccccccccccccccccccccccccccc", + "value": [ + "0x0" + ] + } + } +} \ No newline at end of file diff --git a/fuzzing/eth-tests/erc20_transfer.json b/fuzzing/eth-tests/erc20_transfer.json new file mode 100644 index 0000000..8e64d39 --- /dev/null +++ b/fuzzing/eth-tests/erc20_transfer.json @@ -0,0 +1,60 @@ +{ + "erc20_transfer": { + "env": { + "currentBaseFee": "0x0a", + "currentBeaconRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "currentCoinbase": "0x0000000000000000000000000000000000c0ffee", + "currentDifficulty": "0x020000", + "currentGasLimit": "0x02540be400", + "currentNumber": "0x01", + "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", + "currentTimestamp": "0x03e8", + "currentWithdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "previousHash": "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "post": { + "Shanghai": [ + { + "hash": "0x4c6e15a60aaab17fd64cdb35d269c1a4035566d57a8f9f29a88271b703d94132", + "indexes": { + "data": 0, + "gas": 0, + "value": 0 + }, + "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "txbytes": "0xf861800a8404c4b40094cccccccccccccccccccccccccccccccccccccccc01001ca06939410fcd80efd44b8d819c37a4e460b38e39f37d99e1f09ccd9c25753ef79aa017a79fccc1ede0aae2dbb9f810acc5d6ece485338b3d695742b607a3b886a2b1" + } + ] + }, + "pre": { + "0x1111111111111111111111111111111111111111": { + "balance": "0x100000000000000000000000000000000000000000000000000", + "code": "0x", + "nonce": "0x00", + "storage": {} + }, + "0xcccccccccccccccccccccccccccccccccccccccc": { + "balance": "0x100000000000000000000000000000000000000000000000000", + "code": "0x6080604052600436106100a05760003560e01c8063313ce56711610064578063313ce5671461018657806342966c68146101b157806370a08231146101da57806395d89b4114610217578063a9059cbb14610242578063dd62ed3e1461027f576100a7565b806306fdde03146100ac578063095ea7b3146100d75780631249c58b1461011457806318160ddd1461011e57806323b872dd14610149576100a7565b366100a757005b600080fd5b3480156100b857600080fd5b506100c16102bc565b6040516100ce91906109da565b60405180910390f35b3480156100e357600080fd5b506100fe60048036038101906100f99190610a95565b61034a565b60405161010b9190610af0565b60405180910390f35b61011c61043c565b005b34801561012a57600080fd5b50610133610500565b6040516101409190610b1a565b60405180910390f35b34801561015557600080fd5b50610170600480360381019061016b9190610b35565b610506565b60405161017d9190610af0565b60405180910390f35b34801561019257600080fd5b5061019b61069c565b6040516101a89190610ba4565b60405180910390f35b3480156101bd57600080fd5b506101d860048036038101906101d39190610bbf565b6106af565b005b3480156101e657600080fd5b5061020160048036038101906101fc9190610bec565b610774565b60405161020e9190610b1a565b60405180910390f35b34801561022357600080fd5b5061022c61078c565b60405161023991906109da565b60405180910390f35b34801561024e57600080fd5b5061026960048036038101906102649190610a95565b61081a565b6040516102769190610af0565b60405180910390f35b34801561028b57600080fd5b506102a660048036038101906102a19190610c19565b610925565b6040516102b39190610b1a565b60405180910390f35b600380546102c990610c88565b80601f01602080910402602001604051908101604052809291908181526020018280546102f590610c88565b80156103425780601f1061031757610100808354040283529160200191610342565b820191906000526020600020905b81548152906001019060200180831161032557829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161042a9190610b1a565b60405180910390a36001905092915050565b34600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503460008082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef346040516104f69190610b1a565b60405180910390a3565b60005481565b600081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516106899190610b1a565b60405180910390a3600190509392505050565b600560009054906101000a900460ff1681565b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550806000808282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516107699190610b1a565b60405180910390a350565b60016020528060005260406000206000915090505481565b6004805461079990610c88565b80601f01602080910402602001604051908101604052809291908181526020018280546107c590610c88565b80156108125780601f106107e757610100808354040283529160200191610812565b820191906000526020600020905b8154815290600101906020018083116107f557829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516109139190610b1a565b60405180910390a36001905092915050565b6002602052816000526040600020602052806000526040600020600091509150505481565b600081519050919050565b600082825260208201905092915050565b60005b83811015610984578082015181840152602081019050610969565b60008484015250505050565b6000601f19601f8301169050919050565b60006109ac8261094a565b6109b68185610955565b93506109c6818560208601610966565b6109cf81610990565b840191505092915050565b600060208201905081810360008301526109f481846109a1565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610a2c82610a01565b9050919050565b610a3c81610a21565b8114610a4757600080fd5b50565b600081359050610a5981610a33565b92915050565b6000819050919050565b610a7281610a5f565b8114610a7d57600080fd5b50565b600081359050610a8f81610a69565b92915050565b60008060408385031215610aac57610aab6109fc565b5b6000610aba85828601610a4a565b9250506020610acb85828601610a80565b9150509250929050565b60008115159050919050565b610aea81610ad5565b82525050565b6000602082019050610b056000830184610ae1565b92915050565b610b1481610a5f565b82525050565b6000602082019050610b2f6000830184610b0b565b92915050565b600080600060608486031215610b4e57610b4d6109fc565b5b6000610b5c86828701610a4a565b9350506020610b6d86828701610a4a565b9250506040610b7e86828701610a80565b9150509250925092565b600060ff82169050919050565b610b9e81610b88565b82525050565b6000602082019050610bb96000830184610b95565b92915050565b600060208284031215610bd557610bd46109fc565b5b6000610be384828501610a80565b91505092915050565b600060208284031215610c0257610c016109fc565b5b6000610c1084828501610a4a565b91505092915050565b60008060408385031215610c3057610c2f6109fc565b5b6000610c3e85828601610a4a565b9250506020610c4f85828601610a4a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610ca057607f821691505b602082108103610cb357610cb2610c59565b5b5091905056fea2646970667358221220de3e75f39ece59e11de492394b0e52b51dcffa666beada6fb5db9c7ec45f681764736f6c63430008130033", + "nonce": "0x00", + "storage": {} + } + }, + "transaction": { + "data": [ + "0xa9059cbb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200" + ], + "gasLimit": [ + "0x04c4b400" + ], + "gasPrice": "0x0a", + "nonce": "0x00", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "sender": "0x1111111111111111111111111111111111111111", + "to": "0xcccccccccccccccccccccccccccccccccccccccc", + "value": [ + "0x0" + ] + } + } +} \ No newline at end of file diff --git a/fuzzing/fuzzer.py b/fuzzing/fuzzer.py new file mode 100644 index 0000000..74416ee --- /dev/null +++ b/fuzzing/fuzzer.py @@ -0,0 +1,379 @@ +import library_wrapper +from library_wrapper import CuEVMLib +import json +import time +import argparse +import random + +import copy +from collections import deque +from utils import * +import os +BRANCH_POPULATION = 3 + +SMALL_DELTA = 16 + +MAXIMUM_INT = int(os.environ.get("MAXIMUM_INT", 2**16)) +DEBUG = os.environ.get("DEBUG_MODE", "NA") + + +class SimpleMutator: + def __init__(self, literal_values, maximum_int = MAXIMUM_INT): + self.literal_values = literal_values + self.maximum_int = maximum_int + + def generate_random_input(self, type_): + if "int" in type_: + return random.randint(0, self.maximum_int) + if "string" in type_: + return "test string" + if "bool" in type_: + return random.choice([True, False]) + if "list" in type_: + return [] + def random_int(self, input): + return random.randint(0, self.maximum_int) + def small_delta(self, input): + diff = random.randint(0, SMALL_DELTA) + return random.choice([input+diff, max(0,input-diff)]) + + def flip_random_bit(self, input): + # flip a random bit in 256-bit representation + return input ^ (1 << random.randint(0, 255)) + def flip_random_byte(self, input): + # flip a random byte in 256-bit representation + byte = random.randint(0, 31) + return input ^ (0xff << (byte*8)) + def integer_mutator(self, input): + # avaliable_mutators = [self.random_int, self.small_delta, self.flip_random_bit, self.flip_random_byte] + avaliable_mutators = [self.random_int, self.small_delta, self.flip_random_bit] + return random.choice(avaliable_mutators)(input) + + def mutate(self, value): + if type(value) == int: + return self.integer_mutator(value) + + if type(value) == str: + return "test string" + if type(value) == bool: + return random.choice([True, False]) + if type(value) == list: + return [self.mutate(val) for val in value] + else: + return value +@dataclass +class Seed: + function: str + inputs: list + distance: int + +@dataclass +class DetectedBug: + pc: int + bug_type: str + input: dict + line_info: list + +class Fuzzer: + + def __init__(self, contract_source, num_instances=2, timeout=10, \ + config="configurations/default.json", contract_name=None, output=None, test_case_file = None, random_seed = 0, branch_heuristic=False) -> None: + random.seed(random_seed) + self.library = CuEVMLib(contract_source, num_instances, config, contract_name=contract_name, detect_bug=True) + self.branch_heuristic = branch_heuristic + self.num_instances = num_instances + self.ast_parser = self.library.ast_parser + self.contract_name = self.library.contract_name + self.timeout = timeout # in seconds + self.parse_fuzzing_confg(config) + self.abi_list = {} # mapping from function to input types for abi encoding + if test_case_file: + self.run_test_case(test_case_file) + + self.function_list = self.ast_parser.functions_in_contract_by_name(self.contract_name, name_only=True) + self.literal_values = self.ast_parser.get_literals(self.contract_name, only_value=True) + self.fuzzer = SimpleMutator(self.literal_values) + # self.abi_list = self.ast_parser.original_compilation_output + for k_, v_ in self.ast_parser.original_compilation_output.items(): + if k_.split(":")[1] == self.contract_name: + self.prepare_abi(v_["abi"]) + break + + self.covered_branches = set() + self.missed_branches = set() + self.population = {} # store the population for each branch + self.detected_bugs = {} + self.raw_inputs = [] + self.branch_source_mapping = {} + self.run_seed_round() + + + + def prepare_abi(self, abi): + print("prepare_abi") + for item in abi: + if item.get("type") == "function": + print(item.get("name")) + print(item.get("inputs")) + print(item.get("outputs")) + print(item.get("stateMutability")) + if item.get("stateMutability") != "view": + input_list = [] + for input_ in item.get("inputs"): + input_list.append(input_.get("type")) + self.abi_list[item.get("name")] = { + "input_types" : input_list, + "4byte" : function_abi_to_4byte_selector(item).hex() + } + + print ("after processing") + print (self.abi_list) + def get_branch_source_mapping(self, branch, branch_id): + if not self.branch_heuristic: + return + try: + frag = self.library.ast_parser.source_by_pc(self.contract_name, branch.pc_src, deploy=False) + print(f"find source code: {branch_id} { frag.get('fragment')}") + lines = frag.get("linenums",[0,0]) + print(f"lines: {lines}") + if lines[1]<= lines[0]+1: + self.branch_source_mapping[branch_id] = frag.get('fragment') + return True + else: + self.branch_source_mapping[branch_id] = "NA" + except: + self.branch_source_mapping[branch_id] = "NA" + return False + + def process_tx_trace(self, tx_trace): + # print (self.raw_inputs) + # class EVMBranch: + # pc_src: int + # pc_dst: int + # pc_missed: int + # distance: int + for idx,trace in enumerate(tx_trace): + for branch in trace.get("branches", []): + covered_branch = f"{branch.pc_src},{branch.pc_dst}" + if covered_branch not in self.covered_branches: + self.covered_branches.add(covered_branch) + if covered_branch not in self.population: + self.population[covered_branch] = Seed(self.raw_inputs[idx].get("function"), self.raw_inputs[idx].get("inputs"), 0) + missed_branch = f"{branch.pc_src},{branch.pc_missed}" + if missed_branch not in self.branch_source_mapping: + self.get_branch_source_mapping(branch, missed_branch) + if self.branch_heuristic and self.branch_source_mapping[missed_branch] == "NA": + continue + if missed_branch not in self.covered_branches: + self.missed_branches.add(missed_branch) + if missed_branch in self.population: + if self.population[missed_branch].distance > branch.distance: + self.population[missed_branch] = Seed(self.raw_inputs[idx].get("function"), self.raw_inputs[idx].get("inputs"), branch.distance) + else: + self.population[missed_branch] = Seed(self.raw_inputs[idx].get("function"), self.raw_inputs[idx].get("inputs"), branch.distance) + + # for branch in trace.get("missed_branches", []): + # # print ("missed branch ", branch) + # if branch[0] not in self.covered_branches: + # self.missed_branches.add(branch[0]) + # if branch[0] in self.population: + # if self.population[branch[0]].distance > branch[1]: + # self.population[branch[0]] = Seed(self.raw_inputs[idx].get("function"), self.raw_inputs[idx].get("inputs"), branch[1]) + # else: + # self.population[branch[0]] = Seed(self.raw_inputs[idx].get("function"), self.raw_inputs[idx].get("inputs"), branch[1]) + # for branch in trace.get("covered_branches", []): + # # print ("covered branch ", branch) + # self.covered_branches.add(branch[0]) + # if branch[0] not in self.population: + # self.population[branch[0]] = Seed(self.raw_inputs[idx].get("function"), self.raw_inputs[idx].get("inputs"), 0) + # elif self.population[branch[0]].distance != 0 : + # self.population[branch[0]] = Seed(self.raw_inputs[idx].get("function"), self.raw_inputs[idx].get("inputs"), 0) + # if branch[0] in self.missed_branches: + # self.missed_branches.remove(branch[0]) + + for bug in trace.get("bugs", []): + bug_id = str(bug.pc) + "_" + str(bug.bug_type) + if bug_id not in self.detected_bugs: + self.detected_bugs[bug_id] = DetectedBug(bug.pc, bug.bug_type, self.raw_inputs[idx],[]) + + + def print_population(self): + print("Printing Population") + for k,v in self.population.items(): + print("\n\n ==========") + print(f"Branch {k} : ") + pprint(v) + if k in self.branch_source_mapping: + print(f"Source code: {self.branch_source_mapping[k]}") + print("Missed branches: ", self.missed_branches) + def mutate(self, inputs, function, generate_random=False): + if (generate_random): + return [self.fuzzer.generate_random_input(input_) for input_ in self.abi_list[function].get("input_types")] + else: + return [self.fuzzer.mutate(input) for input in inputs] + + def post_process_input(self, tx_data, inputs, function): + self.raw_inputs.append({ + "function": function, + "inputs": copy.deepcopy(inputs) + }) + + tx_data.append({ + "data": get_transaction_data_from_processed_abi(self.abi_list, function, inputs), + "value": [hex(0)] + }) + + def run_seed_round(self): + + for function in self.function_list: + print("running seed round on function ", function) + tx_data = [] + self.raw_inputs = [] + for idx in range(self.num_instances): + # inputs = [] + # for input_ in self.abi_list[function].get("input_types"): + # inputs.append(self.fuzzer.generate_random_input(input_)) + inputs = self.mutate([], function, generate_random=True) + # print(f"Function {function} : {inputs}") + self.post_process_input(tx_data, inputs, function) + + + tx_trace = self.library.run_transactions(tx_data) + # print(f"Seed round {function} : {tx_data}") + # print(f"Trace result : ") + # pprint(tx_trace) + self.process_tx_trace(tx_trace) + print ("Seed round completed") + + self.print_population() + + def select_next_branch(self): + # debug : + # return "141,142" + # return random.choice(list(self.missed_branches)) + return random.choice(list(self.population.keys())) + + def select_next_input(self): + next_branch = self.select_next_branch() + seed = self.population[next_branch] + return seed.inputs, seed.function + # return random.choice(self.population[next_branch]) + + + def run_test_case(self, test_case_file): + with open(test_case_file) as f: + data = json.load(f) + test_cases = data.get("test_cases") + for (idx, test_case) in enumerate(test_cases): + + tx_data = self.prepare_tx(test_case) + + print(f"Test case {idx} : {test_case}") + print(f"Transaction data : {tx_data}") + + # self.library.build_instance_data(tx_data) + trace_res = self.library.run_transactions(tx_data) + + print(f"Trace result : ") + pprint(trace_res) + + def prepare_tx(self, test_case): + tx = [] + temp_val = test_case.get("value", 0) + if type(temp_val) == int: + temp_val = hex(temp_val) + tx.append({ + "data": get_transaction_data_from_config(test_case, self.library.contract_instance), + "value": [temp_val] + }) + # print ("testcase" , test_case) + return tx + + def parse_fuzzing_confg(self, config): + ... + + def run(self, num_iterations=10): + for i in range(num_iterations): + if DEBUG[0] == "v": + print ("\n" + "-"*80) + print(f"Iteration {i}\n") + tx_data = [] + self.raw_inputs = [] + for idx in range(self.num_instances): + input, function = self.select_next_input() + new_input = self.mutate(input, function) + if DEBUG[0] == "v": + print(f"Function {function} : {new_input}") + self.post_process_input(tx_data, new_input, function) + + tx_trace = self.library.run_transactions(tx_data) + self.process_tx_trace(tx_trace) + if len(DEBUG) > 1 and DEBUG[1] == "v": + print(f"Iteration {i} : {tx_data}") + pprint(tx_trace) + + print ("\n\n Final Population \n\n") + self.print_population() + + + + def finalize_report(self): + for k_, bug in self.detected_bugs.items(): + print ("\n") + print ("-"*80) + # print(bug) + print (f" 🚨 Bug Detected: {bug.bug_type} PC: {bug.pc}") + try: + frag = self.library.ast_parser.source_by_pc(self.contract_name, int(bug.pc), deploy=False) + lines = frag.get("linenums",[0,0]) + self.detected_bugs[k_].line_info = lines + if lines[0] == lines[1]: + print (f" Line: {lines[0]} \n Function: {bug.input.get('function')} \n Inputs: {bug.input.get('inputs')} \n Source code:\n \t {frag.get('fragment')}") + else: + print (f" Line: {lines[0]} - {lines[1]} \n Function: {bug.input.get('function')} \n Inputs: {bug.input.get('inputs')} \n Source code:\n \t {frag.get('fragment')}") + # print (frag) + except: + print (f"Failed to get solidity source line") + pass + + + +# python fuzzer.py --input sample.sol --config sample_config.json --timeout 10 --contract_name Test --output report.json \ +# --test_case test_case.json --num_instaces 10 --num_iterations 100 --random_seed 0 +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Run EVM fuzzer") + parser.add_argument( + "--input", default="contracts/overflow.sol", help="source file" + ) + parser.add_argument( + "--config", default="configurations/default.json", help="config file" + ) + parser.add_argument( + "--timeout", default=10, help="timeout in seconds" + ) + parser.add_argument( + "--contract_name", help="contract name" + ) + parser.add_argument( + "--output", help="output file" + ) + parser.add_argument( + "--test_case", help="test case file" + ) + parser.add_argument( + "--num_instances", default=2, help="number of instances" + ) + parser.add_argument( + "--num_iterations", default=100, help="number of iterations" + ) + parser.add_argument( + "--random_seed", default=0, help="random seed" + ) + parser.add_argument( + "--branch_heuristic", action="store_true", help="branch heuristic" + ) + args = parser.parse_args() + fuzzer = Fuzzer(args.input, int(args.num_instances), args.timeout, args.config, contract_name= args.contract_name + , output=args.output, test_case_file=args.test_case, random_seed= int(args.random_seed), branch_heuristic=args.branch_heuristic) + fuzzer.run(num_iterations=int(args.num_iterations)) + fuzzer.finalize_report() \ No newline at end of file diff --git a/fuzzing/library_wrapper.py b/fuzzing/library_wrapper.py new file mode 100644 index 0000000..45d9c7f --- /dev/null +++ b/fuzzing/library_wrapper.py @@ -0,0 +1,564 @@ +""" +library wrapper to maintain state of EVM instances and run tx on them +""" + +import sys +import ctypes +import json +import copy +from pprint import pprint +import time +from utils import * + +# Add the directory containing your .so file to the Python path +# sys.path.append("../build/") +sys.path.append("./binary/") + +import libcuevm # Now you can import your module as usual + + +class CuEVMLib: + def __init__( + self, + source_file, + num_instances, + config=None, + contract_name=None, + detect_bug=False, + sender="0x1111111111111111111111111111111111111111", + contract_bin_runtime=None, + run_eth_tests=False, + ): + self.initiate_instance_data( + source_file, + num_instances, + config, + contract_name, + detect_bug, + contract_bin_runtime, + run_eth_tests, + ) + self.sender = sender + + def update_persistent_state(self, json_result): + trace_values = json_result + # print ("trace value result") + # pprint(json_result) + + if trace_values is None or trace_values.get("post") is None: + print("Skipping updating state") + return + for i in range(len(trace_values.get("post"))): + post_state = trace_values.get("post")[i].get("state") + if post_state is None: + # print(f"Skipping updating state for instance {i}") + continue + # print("\n\n post_state %d \n\n" % i) + # pprint(post_state) + # self.instances[i]["pre"] = copy.deepcopy(post_state) + # Nov update: copy nonce balance storage and not code + for key, value in post_state.items(): + if key in self.instances[i]["pre"]: + self.instances[i]["pre"][key].update(value) + else: + self.instances[i]["pre"][key] = value + self.instances[i]["pre"][key]["code"] = "0x" + self.instances[i]["pre"][key]["nonce"] = hex( + self.instances[i]["pre"][key]["nonce"] + ) + + # self.instances[i]["pre"][key]["storage"] = value.get("storage") + + # sender = next_config["transaction"]["sender"] + + self.instances[i]["transaction"]["nonce"] = hex( + post_state.get(self.sender, {}).get("nonce", 0) + ) + def run_eth_tests(self): + result_state = libcuevm.run_dict(self.instances) + return result_state + ## 1. run transactions on the EVM instances + ## 2. update the persistent state of the EVM instances + ## 3. return the simplified trace during execution + def run_transactions(self, tx_data, skip_trace_parsing=False, measure_performance=False): + self.build_instance_data(tx_data) + # self.print_instance_data() + # print ("before running") + if measure_performance: + time_start = time.time() + result_state = libcuevm.run_dict(self.instances, skip_trace_parsing) + if measure_performance: + time_end = time.time() + print(f"Time taken: {time_end - time_start} seconds") + self.update_persistent_state(result_state) + return self.post_process_trace(result_state) + + # post process the trace to detect integer bugs and simplify the distance + def post_process_trace(self, json_result): + if json_result is None or json_result.get("post") is None: + print("Skipping post processing") + return [] + final_trace = [] + # print("\ntrace\n") + # pprint(trace) + for i in range(len(json_result.get("post"))): + tx_trace = json_result.get("post")[i].get("trace") + # print("tx trace") + # pprint(tx_trace) + branches = [] + events = [] + storage_write = [] + bugs = [] + for branch in tx_trace.get("branches", [])[3:]: + branches.append( + EVMBranch( + pc_src=branch.get("pc_src"), + pc_dst=branch.get("pc_dst"), + pc_missed=branch.get("pc_missed"), + distance=int(branch.get("distance"), 16), + ) + ) + + for event in tx_trace.get("events", []): + if event.get("opcode") == OP_SSTORE: + storage_write.append( + EVMStorageWrite( + pc=event.get("pc"), + key=event.get("operand_1"), + value=event.get("operand_2"), + ) + ) + else: + events.append( + TraceEvent( + pc=event.get("pc"), + opcode=event.get("op"), + operand_1=int(event.get("operand_1"), 16), + operand_2=int(event.get("operand_2"), 16), + result=int(event.get("res"), 16), + ) + ) + if self.detect_bug: + current_event = events[-1] + if (current_event.opcode == OPADD and current_event.operand_1 + current_event.operand_2 >= 2**256): + bugs.append(EVMBug(current_event.pc, current_event.opcode, "integer overflow")) + elif (current_event.opcode == OPMUL and current_event.operand_1 * current_event.operand_2 >= 2**256): + bugs.append(EVMBug(current_event.pc, current_event.opcode, "integer overflow")) + elif (current_event.opcode == OPSUB and current_event.operand_1 < current_event.operand_2): + bugs.append(EVMBug(current_event.pc, current_event.opcode, "integer underflow")) + elif (current_event.opcode == OPEXP and current_event.operand_1 ** current_event.operand_2 >= 2**256): + bugs.append(EVMBug(current_event.pc, current_event.opcode, "integer overflow")) + elif current_event.opcode == OP_SELFDESTRUCT: + bugs.append(EVMBug(current_event.pc, current_event.opcode, "selfdestruct")) + + all_call = [] + for call in tx_trace.get("calls", []): + all_call.append( + EVMCall( + pc=call.get("pc"), + opcode=call.get("op"), + _from=call.get("sender"), + _to=call.get("receiver"), + value=int(call.get("value"), 16), + result=call.get("success") + ) + ) + if self.detect_bug: + if all_call[-1].value > 0 and all_call[-1].pc != 0: + bugs.append( + EVMBug( + pc=all_call[-1].pc, + opcode=all_call[-1].opcode, + bug_type="Leaking Ether", + ) + ) + + final_trace.append( + { + "branches": branches, + "events": events, + "calls": all_call, + "storage_write": storage_write, + "bugs": bugs, + } + ) + + + return final_trace + + ## initiate num_instances clones of the initial state + def initiate_instance_data( + self, + source_file, + num_instances, + config=None, + contract_name=None, + detect_bug=False, + contract_bin_runtime=None, + run_eth_tests=False + ): + + default_config = json.loads(open("configurations/default.json").read()) + # print(default_config) + self.detect_bug = detect_bug + # tx_sequence_list + tx_sequence_config = json.loads(open(config).read()) + if run_eth_tests: + self.instances = [copy.deepcopy(tx_sequence_config) for _ in range(num_instances)] + return + if contract_name is None: + self.contract_name = tx_sequence_config.get("contract_name") + else: + self.contract_name = contract_name + # print(f" source file {source_file} contract_name {self.contract_name} \n\n") + self.contract_instance, self.ast_parser = compile_file( + source_file, self.contract_name + ) + if self.contract_instance is None: + print("Error in compiling the contract {self.contract_name} {source_file}") + return + if contract_bin_runtime is None: + contract_bin_runtime = self.contract_instance.get("binary_runtime") + # the merged config fields : "env", "pre" (populated with code), "transaction" (populated with tx data and value) + pre_env = tx_sequence_config.get("pre", {}) + + new_test = {} + new_test["env"] = default_config["env"].copy() + new_test["pre"] = default_config["pre"].copy() + + + new_test["pre"].update(pre_env) + + target_address = default_config["target_address"] + + new_test["pre"][target_address]["code"] = contract_bin_runtime + + new_test["pre"][target_address]["storage"] = tx_sequence_config.get( + "storage", {} + ) + + new_test["transaction"] = default_config["transaction"].copy() + + new_test["transaction"]["to"] = target_address + new_test["transaction"]["data"] = ["0x00"] + new_test["transaction"]["value"] = [0] + new_test["transaction"]["nonce"] = "0x00" + + self.instances = [copy.deepcopy(new_test) for _ in range(num_instances)] + + def print_instance_data(self): + for idx, instance in enumerate(self.instances): + print(f"\n\n Instance data {idx}\n\n") + pprint(instance) + + ## build instances data from new tx data + ## tx_data is a list of tx data + def build_instance_data(self, tx_data): + if len(tx_data) < len(self.instances): + tx_data = tx_data + [tx_data[-1]] * (len(self.instances) - len(tx_data)) + if len(tx_data) > len(self.instances): + tx_data = tx_data[: len(self.instances)] + # print (f"tx_data_rebuilt {tx_data}") + for i in range(len(tx_data)): + self.instances[i]["transaction"]["data"] = tx_data[i]["data"] + self.instances[i]["transaction"]["value"] = tx_data[i]["value"] + if tx_data[i].get("sender"): + self.instances[i]["transaction"]["sender"] = tx_data[i]["sender"] + + # TODO: add other fuzz-able fields + + +def test_state_change(): + my_lib = CuEVMLib( + "contracts/state_change.sol", + 3, + "configurations/state_change.json", + # contract_bin_runtime="6011602201600460110260005560015561123460015561ffff60ff5500", + # contract_bin_runtime="6042611234621234567F123456789101112131415161718192021000" + ) + test_case = { + "function": "increase", + "type": "exec", + "input_types": [], + "input": [], + "sender": 0, + } + + tx_1 = { + "data": get_transaction_data_from_config( + test_case, my_lib.contract_instance + ), # must return an array + "value": [hex(0)], + } + tx_2 = { + "data": get_transaction_data_from_config( + test_case, my_lib.contract_instance + ), # must return an array + "value": [hex(0)], + } + + # for debugging, altering tx2 data + tx_2["data"] = ["0x12"] + tx_2["value"] = [hex(10)] + # for debugging, altering the state 2 + my_lib.instances[1]["pre"]["0xcccccccccccccccccccccccccccccccccccccccc"]["storage"][ + "0x00" + ] = "0x2000" + # my_lib.instances[1]["pre"]["0xcccccccccccccccccccccccccccccccccccccccc"][ + # "balance" + # ] = "0x00" + my_lib.instances[2]["pre"]["0xcccccccccccccccccccccccccccccccccccccccc"]["storage"][ + "0x00" + ] = "0x30" + + trace_res = my_lib.run_transactions([tx_1],) + # trace_res = my_lib.run_transactions([tx_1]) + # print("\n\n trace res \n\n") + # pprint(trace_res) + print("\n\n Updated instance data \n\n") + my_lib.print_instance_data() + + trace_res = my_lib.run_transactions([tx_1, tx_2, tx_1]) + + # trace_res = my_lib.run_transactions([tx_2, tx_1, tx_2]) + # # trace_res = my_lib.run_transactions([tx_1, tx_1]) + # print("\n\n trace res \n\n") + # pprint(trace_res) + print("\n\n Updated instance data \n\n") + my_lib.print_instance_data() + + + +def test_erc20(): + my_lib = CuEVMLib( + "contracts/erc20.sol", + 5000, + "configurations/erc20.json", + contract_name="ERC20", + detect_bug=False, + ) + test_case = { + "function": "transfer", + "type": "exec", + "input_types": ["address", "uint256"], + "input": ["0x0000000000000000000000000000000000000001", 512], + "sender": 0, + } + + tx_1 = { + "data": get_transaction_data_from_config( + test_case, my_lib.contract_instance + ), # must return an array + "value": [hex(512)], + } + tx_2 = { + "data": get_transaction_data_from_config( + test_case, my_lib.contract_instance + ), # must return an array + "value": [hex(512)], + } + trace_res = my_lib.run_transactions([tx_1, tx_2], skip_trace_parsing=True) + # print("\n\n trace res \n\n") + # pprint(trace_res) + + +def test_branching(): + my_lib = CuEVMLib( + "contracts/branching.sol", + 2, + "configurations/test_branching.json", + ) + test_case_1 = { + "function": "test_branch", + "type": "exec", + "input_types": ["uint256"], + "input": [12345], + "sender": 0, + } + test_case_2 = { + "function": "test_branch", + "type": "exec", + "input_types": ["uint256"], + "input": [50], + "sender": 0, + } + + tx_1 = { + "data": get_transaction_data_from_config(test_case_1, my_lib.contract_instance), + "value": [hex(0)], + } + + tx_2 = { + "data": get_transaction_data_from_config(test_case_2, my_lib.contract_instance), + "value": [hex(0)], + } + trace_res = my_lib.run_transactions([tx_1, tx_2]) + print("\n\n trace res \n\n") + pprint(trace_res) + + +def test_system_operation(): + my_lib = CuEVMLib( + "contracts/system_operations.sol", + 2, + "configurations/system_operation.json", + ) + test_case = { + "function": "test_call", + "type": "exec", + "input_types": ["address", "uint256"], + "input": ["0x1000000000000000000000000000000000000000", 0x1], + "sender": 0, + } + + tx_1 = { + "data": get_transaction_data_from_config(test_case, my_lib.contract_instance), + "value": [hex(1234)], + } + print("instance data") + pprint(my_lib.instances) + print("tx_1") + pprint(tx_1) + trace_res = my_lib.run_transactions([tx_1]) + print("\n\n trace res \n\n") + pprint(trace_res) + +def test_bugs_simple(): + my_lib = CuEVMLib( + "contracts/test_bugs_simple.sol", + 2, + "configurations/default.json", + contract_name="TestBug", + detect_bug=True, + ) + test_case = { + "function": "bug_combined", + "type": "exec", + "input_types": [], + "input": [], + "sender": 0, + + } + # print("instance data") + # pprint(my_lib.instances) + + tx_1 = { + "data": get_transaction_data_from_config(test_case, my_lib.contract_instance), + "value": [hex(0)], + } + + trace_res = my_lib.run_transactions([tx_1], measure_performance=True, skip_trace_parsing=False) + print("\n\n trace res \n\n") + if trace_res is not None and len(trace_res) > 0: + pprint(trace_res[0]) + +def test_run_eth_tests(): + my_lib = CuEVMLib( + "contracts/test_bugs_simple.sol", + 2, + "configurations/calldata_load.json", + run_eth_tests=True, + ) + # print("\n\n instance data \n\n") + # pprint(my_lib.instances) + + trace_res = my_lib.run_eth_tests() + print("\n\n trace res \n\n") + pprint(trace_res) +# def test_erc20(): +# my_lib = CuEVMLib( +# "contracts/erc20.sol", +# 1, +# "configurations/erc20.json", +# contract_name="ERC20", +# detect_bug=False, +# ) +# test_case = { +# "function": "mint", +# "type": "exec", +# "input_types": [], +# "input": [], +# "sender": 0, +# } +# test_case_2 = { +# "function": "transfer", +# "type": "exec", +# "input_types": ["address", "uint256"], +# "input": ["0x0000000000000000000000000000000000000001", 512], +# "sender": 0, +# } +# # print("instance data") +# # pprint(my_lib.instances) + +# tx_1 = { +# "data": get_transaction_data_from_config(test_case, my_lib.contract_instance), +# "value": [hex(0)], +# } +# tx_2 = { +# "data": get_transaction_data_from_config(test_case_2, my_lib.contract_instance), +# "value": [hex(0)], +# } +# trace_res = my_lib.run_transactions([tx_1], measure_performance=True, skip_trace_parsing=True) +# # trace_res_2 = my_lib.run_transactions([tx_2], measure_performance=True, skip_trace_parsing=True) +# print("\n\n trace res \n\n") +# if trace_res is not None and len(trace_res) > 0: +# pprint(trace_res[0]) + +def test_cross_contract(): + my_lib = CuEVMLib( + "contracts/cross_contract.sol", + 1, + "configurations/cross_contract.json", + detect_bug=True, + ) + test_case = { + "function": "underflow", + "type": "exec", + "input_types": ["address", "address"], + "input": [ + "0x1000000000000000000000000000000000000000", + "0x2000000000000000000000000000000000000000", + ], + "value": 300, + "sender": 0, + "receiver": "0x1000000000000000000000000000000000000000", + } + + tx_1 = { + "data": get_transaction_data_from_config(test_case, my_lib.contract_instance), + "value": [hex(300)], + } + + trace_res = my_lib.run_transactions([tx_1]) + print("\n\n trace res \n\n") + pprint(trace_res) + +if __name__ == "__main__": + + # test_system_operation() + # test_cross_contract() + # test_erc20() + + def run_test_case(test_case_name): + if test_case_name == "system_operation": + test_system_operation() + elif test_case_name == "cross_contract": + test_cross_contract() + elif test_case_name == "erc20": + test_erc20() + elif test_case_name == "state_change": + test_state_change() + elif test_case_name == "bugs_simple": + test_bugs_simple() + elif test_case_name == "branching": + test_branching() + elif test_case_name == "run_eth_tests": + test_run_eth_tests() + else: + print(f"Unknown test case: {test_case_name}") + + if len(sys.argv) > 1: + run_test_case(sys.argv[1]) + else: + print("Please provide a test case name as a command line argument.") + # test_state_change() diff --git a/samples/requirements.txt b/fuzzing/requirements.txt similarity index 100% rename from samples/requirements.txt rename to fuzzing/requirements.txt diff --git a/samples/sample.ipynb b/fuzzing/sample.ipynb similarity index 100% rename from samples/sample.ipynb rename to fuzzing/sample.ipynb diff --git a/samples/test_evm.py b/fuzzing/test_evm.py similarity index 53% rename from samples/test_evm.py rename to fuzzing/test_evm.py index 948a3b5..61be96e 100644 --- a/samples/test_evm.py +++ b/fuzzing/test_evm.py @@ -7,103 +7,6 @@ from eth_abi import encode from eth_utils import function_abi_to_4byte_selector -SAMPLE_OPCODES = {1 : "+", 2 : "*", 3 : "-"} # samples for testing of overflow, underflow -def parse_trace_and_detect_bug(trace_file, contract_name, ast_parser = None): - evm_output = json.loads(open(trace_file).read()) - traces = list(evm_output.values())[0].get("post",[])[0].get("traces", []) - all_bugs = [] - for idx,item in enumerate(traces): - if item.get("opcode") in SAMPLE_OPCODES: - if idx <2: # skip the first two items - continue - prev_stack = traces[idx-1].get("stack").get("data") - curr_stack = item.get("stack").get("data") - # print (prev_stack, curr_stack) - a, b = int(prev_stack[-1],16), int(prev_stack[-2],16) - res = int(curr_stack[-1],16) - print ("-"*80) - print (f"found operation {a} {SAMPLE_OPCODES[item.get('opcode')]} {b} = {res}") - bug_pc = None - if item.get("opcode") in [1,2]: - if res < a or res < b: - print (f"overflow detected at program counter {item.get('pc')}") - all_bugs.append({"overflow": item.get("pc")}) - bug_pc = item.get("pc") - if item.get("opcode") == 3: - if res > a and res > b: - print (f"underflow detected at program counter {item.get('pc')}") - all_bugs.append({"underflow": item.get("pc")}) - bug_pc = item.get("pc") - if bug_pc and ast_parser : - try: - frag = ast_parser.source_by_pc(contract_name, bug_pc, deploy=False) - lines = frag.get("linenums",[0,0]) - if lines[0] == lines[1]: - print (f"Line: {lines[0]} : Source {frag.get('fragment')}") - else: - print (f"Line: {lines[0]} - {lines[1]} : Source {frag.get('fragment')}") - # print (frag) - except: - pass - print ("-"*80) - return all_bugs - -def decode_abi_bin_from_compiled_json(compiled_sol): - m = {} - for contract_name in compiled_sol.keys(): - abi = compiled_sol.get(contract_name).get("abi") - binary = compiled_sol.get(contract_name).get("bin") - binary_runtime = compiled_sol.get(contract_name).get("bin-runtime") - storage_layout = compiled_sol.get(contract_name).get("storage-layout") - m[contract_name] = dict( - abi=abi, - binary_runtime=binary_runtime, - binary=binary, - contract=contract_name, - storage_layout=storage_layout, - ) - return m - - -def compile_file( - file_path="contracts/state_change.sol", contract_name="TestStateChange" -): - print ("compile file ", file_path, contract_name) - # The input can be a file path or source code - parser = CombinedJsonParser(file_path, try_install_solc=True) - compiler_output = parser.original_compilation_output - # print (compiler_output) - compiled_sol = {k.split(":")[-1]: v for k, v in compiler_output.items()} - - m_contracts = decode_abi_bin_from_compiled_json(compiled_sol) - contract_instance = m_contracts.get(contract_name) - contract_bin_runtime = contract_instance.get("binary_runtime") - return contract_instance, parser - - -def get_transaction_data_from_config(item, contract_instance): - print(item) - # print (contract_instance) - target_function = item["function"] - inputs = item["input"] - print("Target function inputs ", target_function, inputs) - # print (contract_instance['abi']) - function_abi = [ - i - for i in contract_instance["abi"] - if i.get("name") == target_function and i.get("type") == "function" - ] - input_types = item["input_types"] - # print (function_abi[0]) - function_abi = function_abi[0] - four_byte = "0x" + function_abi_to_4byte_selector(function_abi).hex() - print(four_byte) - if len(inputs) > 0: - encoded_data = encode(input_types, inputs).hex() - else: - encoded_data = "" - - return [four_byte + encoded_data] def contruct_next_test_case(config_file, next_config): diff --git a/fuzzing/test_library.py b/fuzzing/test_library.py new file mode 100755 index 0000000..81f58bd --- /dev/null +++ b/fuzzing/test_library.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +import sys +import ctypes +import json + +# Add the directory containing your .so file to the Python path +sys.path.append("../build/") + +import libcuevm # Now you can import your module as usual + + +def process_json(input_data, output_file): + # Convert Python dictionary to JSON string + # input_json_string = json.dumps(input_data).encode('utf-8') + + temp_input_data = input_data[list(input_data.keys())[0]] # extract first value + # Call the library function with the JSON string + # print ("input data") + # print (input_data) + # result_json = libcuevm.print_dict(input_data) + result_json = libcuevm.run_dict([input_data]) + # result_json = libcuevm.run_dict(temp_input_data) + + # input_data[list(input_data.keys())[0]]["post"] = result_json["post"] + # json.dump(input_data, open(output_file, "w"), indent=4) + + +import argparse + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="Process some integers.") + parser.add_argument("--input", type=str, help="path to json file") + parser.add_argument("--output", type=str, help="path to output json file") + parser.add_argument( + "--num_instances", type=int, default=1, help="number of instances" + ) + args = parser.parse_args() + + json_file = args.input + num_instances = args.num_instances + output_file = args.output + + input_data = json.loads(open(json_file).read()) + instance_data = input_data[list(input_data.keys())[0]] + + if len(instance_data["transaction"]["data"]) < num_instances: + instance_data["transaction"]["data"] = instance_data["transaction"]["data"] * ( + num_instances // len(instance_data["transaction"]["data"]) + ) + if len(instance_data["transaction"]["gasPrice"]) < num_instances: + instance_data["transaction"]["gasPrice"] = instance_data["transaction"][ + "gasPrice" + ] * (num_instances // len(instance_data["transaction"]["gasPrice"])) + if len(instance_data["transaction"]["gasLimit"]) < num_instances: + instance_data["transaction"]["gasLimit"] = instance_data["transaction"][ + "gasLimit" + ] * (num_instances // len(instance_data["transaction"]["gasLimit"])) + print(f'generated {len(instance_data["transaction"]["data"])} instances') + + process_json(instance_data, output_file) diff --git a/fuzzing/utils.py b/fuzzing/utils.py new file mode 100644 index 0000000..2434106 --- /dev/null +++ b/fuzzing/utils.py @@ -0,0 +1,193 @@ +from dataclasses import dataclass +import json +import argparse +import os +import subprocess +from pprint import pprint +from solc_json_parser.combined_json_parser import CombinedJsonParser +from eth_abi import encode +from eth_utils import function_abi_to_4byte_selector + +SAMPLE_OPCODES = {1: "+", 2: "*", 3: "-"} # samples for testing of overflow, underflow + +OPADD = 0x01 +OPMUL = 0x02 +OPSUB = 0x03 +OPEXP = 0x0A + +OP_SSTORE = 0x55 + +OP_CALL = 0xF1 +OP_CALLCODE = 0xF2 +OP_DELEGATECALL = 0xF4 +OP_STATICCALL = 0xFA + +OP_REVERT = 0xFD +OP_INVALID = 0xFE +OP_SELFDESTRUCT = 0xFF + +OP_ORIGIN = 0x32 + +arith_ops = [OPADD, OPMUL, OPSUB, OPEXP] +# define OP_SSTORE 0x55 + + +@dataclass +class EVMCall: + pc: int + opcode: int + _from: str + _to: str + value: int + result: bool +@dataclass +class EVMStorageWrite: + pc: int + key: int + value: int + +@dataclass +class EVMBranch: + pc_src: int + pc_dst: int + pc_missed: int + distance: int + +@dataclass +class TraceEvent: + pc: int + opcode: int + operand_1: int + operand_2: int + result: int + +@dataclass +class EVMBug: + pc: int + opcode: int + bug_type: str + source: str = "" + line: int = 0 + +@dataclass +class EVMStore: + pc: int + key: int + value: int + + +def parse_trace_and_detect_bug(trace_file, contract_name, ast_parser=None): + evm_output = json.loads(open(trace_file).read()) + traces = list(evm_output.values())[0].get("post", [])[0].get("traces", []) + all_bugs = [] + for idx, item in enumerate(traces): + if item.get("opcode") in SAMPLE_OPCODES: + if idx < 2: # skip the first two items + continue + prev_stack = traces[idx - 1].get("stack").get("data") + curr_stack = item.get("stack").get("data") + # print (prev_stack, curr_stack) + a, b = int(prev_stack[-1], 16), int(prev_stack[-2], 16) + res = int(curr_stack[-1], 16) + print("-" * 80) + print( + f"found operation {a} {SAMPLE_OPCODES[item.get('opcode')]} {b} = {res}" + ) + bug_pc = None + if item.get("opcode") in [1, 2]: + if res < a or res < b: + print(f"overflow detected at program counter {item.get('pc')}") + all_bugs.append({"overflow": item.get("pc")}) + bug_pc = item.get("pc") + if item.get("opcode") == 3: + if res > a and res > b: + print(f"underflow detected at program counter {item.get('pc')}") + all_bugs.append({"underflow": item.get("pc")}) + bug_pc = item.get("pc") + if bug_pc and ast_parser: + try: + frag = ast_parser.source_by_pc(contract_name, bug_pc, deploy=False) + lines = frag.get("linenums", [0, 0]) + if lines[0] == lines[1]: + print(f"Line: {lines[0]} : Source {frag.get('fragment')}") + else: + print( + f"Line: {lines[0]} - {lines[1]} : Source {frag.get('fragment')}" + ) + # print (frag) + except: + pass + print("-" * 80) + return all_bugs + + +def get_transaction_data_from_config(item, contract_instance): + print(item) + # print (contract_instance) + target_function = item["function"] + inputs = item["input"] + # print("Target function inputs ", target_function, inputs) + # print (contract_instance['abi']) + function_abi = [ + i + for i in contract_instance["abi"] + if i.get("name") == target_function and i.get("type") == "function" + ] + input_types = item["input_types"] + # print (function_abi[0]) + function_abi = function_abi[0] + four_byte = "0x" + function_abi_to_4byte_selector(function_abi).hex() + print(four_byte) + if len(inputs) > 0: + encoded_data = encode(input_types, inputs).hex() + else: + encoded_data = "" + + return [four_byte + encoded_data] + + +def get_transaction_data_from_processed_abi(processed_abi, function_name, inputs): + # print("Target function inputs ", function_name, inputs) + entry = processed_abi.get(function_name) + if entry: + input_types = entry.get("input_types") + four_byte = "0x" + entry.get("4byte") + if len(inputs) > 0: + encoded_data = encode(input_types, inputs).hex() + else: + encoded_data = "" + return [four_byte + encoded_data] + else: + return [""] + + +def decode_abi_bin_from_compiled_json(compiled_sol): + m = {} + for contract_name in compiled_sol.keys(): + abi = compiled_sol.get(contract_name).get("abi") + binary = compiled_sol.get(contract_name).get("bin") + binary_runtime = compiled_sol.get(contract_name).get("bin-runtime") + storage_layout = compiled_sol.get(contract_name).get("storage-layout") + m[contract_name] = dict( + abi=abi, + binary_runtime=binary_runtime, + binary=binary, + contract=contract_name, + storage_layout=storage_layout, + ) + return m + + +def compile_file( + file_path="contracts/state_change.sol", contract_name="TestStateChange" +): + print("compile file ", file_path, contract_name) + # The input can be a file path or source code + parser = CombinedJsonParser(file_path, try_install_solc=True) + compiler_output = parser.original_compilation_output + compiled_sol = {k.split(":")[-1]: v for k, v in compiler_output.items()} + + m_contracts = decode_abi_bin_from_compiled_json(compiled_sol) + contract_instance = m_contracts.get(contract_name) + contract_bin_runtime = contract_instance.get("binary_runtime") + return contract_instance, parser diff --git a/interpreter/interpreter.cu b/interpreter/interpreter.cu index 41cf536..d2af4bf 100644 --- a/interpreter/interpreter.cu +++ b/interpreter/interpreter.cu @@ -1,8 +1,10 @@ -#include + #include #include +#include #include +#include #include #include #include @@ -11,42 +13,6 @@ #include #include -// define the kernel function -__global__ void kernel_evm(cgbn_error_report_t *report, CuEVM::evm_instance_t *instances, uint32_t count) { - int32_t instance = (blockIdx.x * blockDim.x + threadIdx.x) / CuEVM::cgbn_tpi; - if (instance >= count) return; - CuEVM::ArithEnv arith(cgbn_no_checks, report, instance); - CuEVM::bn_t test; - -// printf("new instance %d\n", instance); -#ifdef EIP_3155 - __ONE_GPU_THREAD_WOSYNC_BEGIN__ - printf("instance %d\n", instance); - printf("world state\n"); - instances[instance].world_state_data_ptr->print(); - printf("touch state\n"); - instances[instance].touch_state_data_ptr->print(); - printf("instance %d\n", instance); - printf("transaction\n"); - instances[instance].transaction_ptr->print(); - __ONE_GPU_THREAD_WOSYNC_END__ -#endif - CuEVM::evm_t *evm = new CuEVM::evm_t(arith, instances[instance]); - // printf("\nevm->run(arith) instance %d\n", instance); - __SYNC_THREADS__ - evm->run(arith); -#ifdef EIP_3155 - if (instance == 0) { - __ONE_GPU_THREAD_BEGIN__ - // instances[0].tracer_ptr->print(arith); - instances[0].tracer_ptr->print_err(); - __ONE_GPU_THREAD_WOSYNC_END__ - } -#endif - // delete evm; - // evm = nullptr; -} - void run_interpreter(char *read_json_filename, char *write_json_filename, size_t clones, bool verbose = false) { CuEVM::evm_instance_t *instances_data; CuEVM::ArithEnv arith(cgbn_no_checks, 0); @@ -60,14 +26,16 @@ void run_interpreter(char *read_json_filename, char *write_json_filename, size_t cudaEvent_t start, stop; float milliseconds = 0; - size_t stack_size; - cudaDeviceGetLimit(&stack_size, cudaLimitStackSize); - printf("current stack size %zu\n", stack_size); - size_t heap_size = (size_t(2) << 30); // 2GB + size_t size_value; + cudaDeviceGetLimit(&size_value, cudaLimitStackSize); + printf("current stack size %zu\n", size_value); + cudaDeviceGetLimit(&size_value, cudaLimitStackSize); + printf("current heap size %zu\n", size_value); + size_t heap_size = (size_t(500) << 20); // 500MB CUDA_CHECK(cudaDeviceSetLimit(cudaLimitMallocHeapSize, heap_size)); - CUDA_CHECK(cudaDeviceSetLimit(cudaLimitStackSize, 90 * 1024)); - cudaDeviceGetLimit(&stack_size, cudaLimitStackSize); - printf("current stack size %zu\n", stack_size); + CUDA_CHECK(cudaDeviceSetLimit(cudaLimitStackSize, 4 * 1024)); + cudaDeviceGetLimit(&size_value, cudaLimitStackSize); + printf("current stack size %zu\n", size_value); CUDA_CHECK(cudaDeviceSynchronize()); // CUDA_CHECK(cudaEventCreate(&start)); // CUDA_CHECK(cudaEventCreate(&stop)); @@ -98,7 +66,7 @@ void run_interpreter(char *read_json_filename, char *write_json_filename, size_t // num_instances = 1; printf("Running on GPU %d %d\n", num_instances, CuEVM::cgbn_tpi); // run the evm - kernel_evm<<>>(report, instances_data, num_instances); + CuEVM::kernel_evm_multiple_instances<<>>(report, instances_data, num_instances); CUDA_CHECK(cudaDeviceSynchronize()); CUDA_CHECK(cudaGetLastError()); printf("GPU kernel finished\n"); @@ -150,6 +118,8 @@ void run_interpreter(char *read_json_filename, char *write_json_filename, size_t std::chrono::duration cpu_duration = cpu_end - cpu_start; printf("CPU EVM execution took %f ms\n", cpu_duration.count()); #endif + break; + // run only one test } printf("Freeing the memory ...\n"); diff --git a/interpreter/libcuevm.cu b/interpreter/libcuevm.cu new file mode 100644 index 0000000..8e1f8a7 --- /dev/null +++ b/interpreter/libcuevm.cu @@ -0,0 +1,148 @@ +#include +#include +#include + +#include +#include +#include + +using namespace python_utils; + +PyObject* run_interpreter_pyobject(PyObject* read_roots, uint32_t skip_trace_parsing) { + CuEVM::evm_instance_t* instances_data; + CuEVM::ArithEnv arith(cgbn_no_checks, 0); + // printf("Running the interpreter\n"); +#ifndef GPU + printf("CPU libcuevm is not supported at the moment\n"); + return NULL; +#endif + CUDA_CHECK(cudaSetDevice(0)); + CUDA_CHECK(cudaDeviceReset()); + // printf("Running on GPU\n"); + cgbn_error_report_t* report = nullptr; + // CUDA_CHECK(cgbn_error_report_alloc(&report)); + cudaEvent_t start, stop; + float milliseconds = 0; + + size_t size_value; + cudaDeviceGetLimit(&size_value, cudaLimitStackSize); + // printf("current stack size %zu\n", size_value); + cudaDeviceGetLimit(&size_value, cudaLimitStackSize); + // printf("current heap size %zu\n", size_value); + size_t heap_size = (size_t(500) << 20); // 500MB + CUDA_CHECK(cudaDeviceSetLimit(cudaLimitMallocHeapSize, heap_size)); + CUDA_CHECK(cudaDeviceSetLimit(cudaLimitStackSize, 2 * 1024)); + cudaDeviceGetLimit(&size_value, cudaLimitStackSize); + // printf("current stack size %zu\n", size_value); + CUDA_CHECK(cudaDeviceSynchronize()); + // CUDA_CHECK(cudaEventCreate(&start)); + // CUDA_CHECK(cudaEventCreate(&stop)); + + // read the json file with the global state + + uint32_t num_instances = 0; + uint32_t managed = 1; + + if (!PyList_Check(read_roots)) { + PyErr_SetString(PyExc_TypeError, "Argument must be a list of dictionaries."); + return NULL; + } + + Py_ssize_t count = PyList_Size(read_roots); + + python_utils::get_evm_instances_from_PyObject(instances_data, read_roots, num_instances); + // printf("print simplified trace data host\n"); + // instances_data[0].simplified_trace_data_ptr->print(); + + uint32_t num_blocks = (num_instances + CGBN_IBP - 1) / (CGBN_IBP); + // printf("Running %d instances on GPU, num blocks %d, threads per block %d\n", num_instances, num_blocks, + // CGBN_TPI * CGBN_IBP); + // run the evm + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord(start); + + CuEVM::kernel_evm_multiple_instances<<>>(report, instances_data, num_instances); + + cudaEventRecord(stop); + cudaEventSynchronize(stop); + cudaEventElapsedTime(&milliseconds, start, stop); + printf("Kernel execution time: %f milliseconds\n", milliseconds); + + cudaEventDestroy(start); + cudaEventDestroy(stop); + // CUDA_CHECK(cudaDeviceSynchronize()); + + CUDA_CHECK(cudaGetLastError()); + // printf("GPU kernel finished\n"); + // CGBN_CHECK(report); + + // printf("\n\ntesting world state printing on host\n\n"); + // instances_data[0].serialized_worldstate_data_ptr->print(); + // printf("print simplified trace data host\n"); + // for (uint32_t i = 0; i < num_instances; i++) { + // printf("\n\ninstance %d\n", i); + // instances_data[i].simplified_trace_data_ptr->print(); + // } + PyObject* write_root; + if (!skip_trace_parsing) { + write_root = python_utils::pyobject_from_evm_instances(instances_data, num_instances); + } else { + write_root = PyDict_New(); + } + + CuEVM::free_evm_instances(instances_data, num_instances, managed); + + CUDA_CHECK(cgbn_error_report_free(report)); + CUDA_CHECK(cudaDeviceReset()); + return write_root; +} + +static PyObject* run_dict(PyObject* self, PyObject* args) { + PyObject* read_root; + uint32_t skip_trace_parsing = 0; + // Parse the input PyObject* to get the Python object (dictionary) + // if (!PyArg_ParseTuple(args, "O", &read_root)) { + // return NULL; // If parsing fails, return NULL + // } + // Parse the input PyObject* to get the Python object (dictionary) and optionally the boolean flag + if (!PyArg_ParseTuple(args, "O|i", &read_root, &skip_trace_parsing)) { + return NULL; // If parsing fails, return NULL + } + + PyObject* write_root = run_interpreter_pyobject(read_root, skip_trace_parsing); + // Return the resulting PyObject* (no need for manual memory management on Python side) + return write_root; +} + +static PyObject* print_dict(PyObject* self, PyObject* args) { + PyObject* dict; + + // Parse the Python argument (a dictionary) + if (!PyArg_ParseTuple(args, "O", &dict)) return nullptr; + + // Ensure the object is a dictionary + if (!PyDict_Check(dict)) { + PyErr_SetString(PyExc_TypeError, "Argument must be a dictionary."); + return nullptr; + } + // Start recursive printing with no indent + print_dict_recursive(dict, 0); + + Py_RETURN_NONE; +} + +// Method definition +static PyMethodDef ExampleMethods[] = {{"print_dict", print_dict, METH_VARARGS, "Print dictionary keys and values."}, + {"run_dict", run_dict, METH_VARARGS, "Run the interpreter with a JSON object."}, + {nullptr, nullptr, 0, nullptr}}; + +// Module definition +static PyModuleDef examplemodule = {PyModuleDef_HEAD_INIT, + "libcuevm", // Module name + nullptr, // Module documentation + -1, // Size of per-interpreter state of the module + ExampleMethods}; + +// Initialization function +PyMODINIT_FUNC PyInit_libcuevm(void) { return PyModule_Create(&examplemodule); } diff --git a/interpreter/python_utils.cu b/interpreter/python_utils.cu new file mode 100644 index 0000000..ceeaf39 --- /dev/null +++ b/interpreter/python_utils.cu @@ -0,0 +1,493 @@ + +#include + +void copy_dict_recursive(PyObject* read_root, PyObject* write_root); +static PyObject* print_dict(PyObject* self, PyObject* args); + +namespace python_utils { +using namespace CuEVM; +CuEVM::block_info_t* getBlockDataFromPyObject(PyObject* data) { + // construct blockt_t + + block_info_t* block_data; + + CUDA_CHECK(cudaMallocManaged((void**)&(block_data), sizeof(block_info_t))); + + const char* base_fee = GET_STR_FROM_DICT_WITH_DEFAULT(data, "currentBaseFee", DefaultBlock::BaseFee); + const char* coin_base = GET_STR_FROM_DICT_WITH_DEFAULT(data, "currentCoinbase", DefaultBlock::CoinBase); + const char* difficulty = GET_STR_FROM_DICT_WITH_DEFAULT(data, "currentDifficulty", DefaultBlock::Difficulty); + const char* block_number = GET_STR_FROM_DICT_WITH_DEFAULT(data, "currentNumber", DefaultBlock::BlockNumber); + const char* gas_limit = GET_STR_FROM_DICT_WITH_DEFAULT(data, "currentGasLimit", DefaultBlock::GasLimit); + const char* time_stamp = GET_STR_FROM_DICT_WITH_DEFAULT(data, "currentTimestamp", DefaultBlock::TimeStamp); + const char* previous_hash = GET_STR_FROM_DICT_WITH_DEFAULT(data, "previousHash", DefaultBlock::PreviousHash); + block_data->coin_base.from_hex(coin_base); + block_data->difficulty.from_hex(difficulty); + block_data->number.from_hex(block_number); + block_data->gas_limit.from_hex(gas_limit); + block_data->time_stamp.from_hex(time_stamp); + block_data->base_fee.from_hex(base_fee); + block_data->chain_id.from_hex("0x01"); + block_data->previous_blocks[0].hash.from_hex(previous_hash); + return block_data; +} + +void print_dict_recursive(PyObject* dict, int indent_level) { + PyObject *key, *value; + Py_ssize_t pos = 0; + + // Iterate over dictionary items + while (PyDict_Next(dict, &pos, &key, &value)) { + // Print indent + for (int i = 0; i < indent_level; ++i) { + printf(" "); // 4 spaces for each indent level + } + + // Convert key to string and print + PyObject* keyStrObj = PyObject_Str(key); + const char* keyStr = PyUnicode_AsUTF8(keyStrObj); + printf("%s: ", keyStr); + Py_DECREF(keyStrObj); + + // Check if value is a dictionary + if (PyDict_Check(value)) { + printf("\n"); + print_dict_recursive(value, indent_level + 1); // Recursively print nested dictionary + } else if (PyList_Check(value)) { + // Handle list of items + printf("[\n"); + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) { + PyObject* item = PyList_GetItem(value, i); // Borrowed reference, no need to DECREF + // Print list item with additional indent + for (int j = 0; j <= indent_level; ++j) { + printf(" "); + } + PyObject* itemStrObj = PyObject_Str(item); + const char* itemStr = PyUnicode_AsUTF8(itemStrObj); + printf("%s\n", itemStr); + Py_DECREF(itemStrObj); + } + // Print closing bracket with indent + for (int i = 0; i < indent_level; ++i) { + printf(" "); + } + printf("]\n"); + } else { + // For other types, convert to string and print + PyObject* valueStrObj = PyObject_Str(value); + const char* valueStr = PyUnicode_AsUTF8(valueStrObj); + printf("%s\n", valueStr); + Py_DECREF(valueStrObj); + } + } +} +const char* adjust_hex_string(const char* hex_string) { + if (strlen(hex_string) >= 2 && (hex_string[0] == '0' && (hex_string[1] == 'x' || hex_string[1] == 'X'))) + hex_string += 2; // Skip the "0x" prefix + if (strlen(hex_string) % 2 != 0) { + printf("Invalid hex_string length\n"); + return NULL; + } + return hex_string; +} +void hex_to_bytes(const char* hex_string, uint8_t* byte_array, size_t length) { + for (size_t idx = 0; idx < length; idx += 2) { + sscanf(&hex_string[idx], "%2hhx", &byte_array[idx / 2]); + } +} +CuEVM::evm_transaction_t* getTransactionDataFromListofPyObject(PyObject* read_roots) { + Py_ssize_t count = PyList_Size(read_roots); + CuEVM::evm_transaction_t* transactions; + + CUDA_CHECK(cudaMallocManaged((void**)&(transactions), count * sizeof(CuEVM::evm_transaction_t))); + + for (Py_ssize_t idx = 0; idx < count; idx++) { + PyObject* read_root = PyList_GetItem(read_roots, idx); + if (!PyDict_Check(read_root)) { + PyErr_SetString(PyExc_TypeError, "Each item in the list must be a dictionary."); + return NULL; + } + + PyObject* data = PyDict_GetItemString(read_root, "transaction"); + // get data size + PyObject* tx_data = PyDict_GetItemString(data, "data"); + PyObject* tx_gas_limit = PyDict_GetItemString(data, "gasLimit"); + PyObject* tx_value = PyDict_GetItemString(data, "value"); + if (tx_data == NULL || !PyList_Check(tx_data)) { + printf("Invalid transaction data\n"); + return NULL; + } + + // printf("Transaction count: %d\n", count); + + CuEVM::evm_transaction_t* template_transaction = new evm_transaction_t(); + memset(template_transaction, 0, sizeof(CuEVM::evm_transaction_t)); + + uint8_t type; + + type = 0; + template_transaction->nonce.from_hex(PyUnicode_AsUTF8(PyDict_GetItemString(data, "nonce"))); + template_transaction->to.from_hex(PyUnicode_AsUTF8(PyDict_GetItemString(data, "to"))); + template_transaction->sender.from_hex(PyUnicode_AsUTF8(PyDict_GetItemString(data, "sender"))); + template_transaction->max_fee_per_gas = 0; + template_transaction->max_priority_fee_per_gas = 0; + template_transaction->gas_price.from_hex("0x0a"); + + template_transaction->type = type; + + // char *bytes_string = NULL; + memcpy(&(transactions[idx]), template_transaction, sizeof(CuEVM::evm_transaction_t)); + transactions[idx].gas_limit.from_hex(PyUnicode_AsUTF8(PyList_GetItem(tx_gas_limit, 0))); + transactions[idx].value.from_hex(PyUnicode_AsUTF8(PyList_GetItem(tx_value, 0))); + + const char* bytes_string = PyUnicode_AsUTF8(PyList_GetItem(tx_data, 0)); + + bytes_string = adjust_hex_string(bytes_string); + transactions[idx].data_init.size = strlen(bytes_string) / 2; + if (transactions[idx].data_init.size > 0) { + CUDA_CHECK(cudaMallocManaged((void**)&(transactions[idx].data_init.data), + transactions[idx].data_init.size * sizeof(uint8_t))); + hex_to_bytes(bytes_string, transactions[idx].data_init.data, 2 * transactions[idx].data_init.size); + } else { + transactions[idx].data_init.data = NULL; + } + + delete template_transaction; + } + + return transactions; +} + +CuEVM::evm_transaction_t* getTransactionDataFromPyObject(PyObject* data, size_t& instances_count) { + // get data size + PyObject* tx_data = PyDict_GetItemString(data, "data"); + PyObject* tx_gas_limit = PyDict_GetItemString(data, "gasLimit"); + PyObject* tx_value = PyDict_GetItemString(data, "value"); + if (tx_data == NULL || !PyList_Check(tx_data)) { + printf("Invalid transaction data\n"); + return NULL; + } + size_t tx_data_count = PyList_Size(tx_data); + size_t gas_limit_count = PyList_Size(tx_gas_limit); + size_t value_count = PyList_Size(tx_value); + size_t count = max(max(tx_data_count, gas_limit_count), value_count); + instances_count = count; + // printf("Transaction count: %d\n", count); + CuEVM::evm_transaction_t* transactions; + + CUDA_CHECK(cudaMallocManaged((void**)&(transactions), count * sizeof(CuEVM::evm_transaction_t))); + + evm_transaction_t* template_transaction = new evm_transaction_t(); + memset(template_transaction, 0, sizeof(evm_transaction_t)); + + uint8_t type; + size_t idx = 0; + + type = 0; + + template_transaction->nonce.from_hex(PyUnicode_AsUTF8(PyDict_GetItemString(data, "nonce"))); + template_transaction->to.from_hex(PyUnicode_AsUTF8(PyDict_GetItemString(data, "to"))); + template_transaction->sender.from_hex(PyUnicode_AsUTF8(PyDict_GetItemString(data, "sender"))); + + template_transaction->max_fee_per_gas = 0; + template_transaction->max_priority_fee_per_gas = 0; + template_transaction->gas_price.from_hex("0x0a"); + + template_transaction->type = type; + + size_t index; + // char *bytes_string = NULL; + for (idx = 0; idx < count; idx++) { + memcpy(&(transactions[idx]), template_transaction, sizeof(evm_transaction_t)); + + transactions[idx].gas_limit.from_hex( + PyUnicode_AsUTF8(PyList_GetItem(tx_gas_limit, idx < gas_limit_count ? idx : 0))); + transactions[idx].value.from_hex(PyUnicode_AsUTF8(PyList_GetItem(tx_value, idx < value_count ? idx : 0))); + + const char* bytes_string = PyUnicode_AsUTF8(PyList_GetItem(tx_data, idx < tx_data_count ? idx : 0)); + + bytes_string = adjust_hex_string(bytes_string); + transactions[idx].data_init.size = strlen(bytes_string) / 2; + if (transactions[idx].data_init.size > 0) { + CUDA_CHECK(cudaMallocManaged((void**)&(transactions[idx].data_init.data), + transactions[idx].data_init.size * sizeof(uint8_t))); + + hex_to_bytes(bytes_string, transactions[idx].data_init.data, 2 * transactions[idx].data_init.size); + } else { + transactions[idx].data_init.data = NULL; + } + } + delete template_transaction; + return transactions; +} + +CuEVM::state_t* getStateDataFromPyObject(PyObject* data) { + PyObject *key, *value; + Py_ssize_t pos = 0; + CuEVM::state_t* state_data; + + CUDA_CHECK(cudaMallocManaged((void**)&(state_data), sizeof(CuEVM::state_t))); + + state_data->no_accounts = PyDict_Size(data); + + CUDA_CHECK(cudaMallocManaged((void**)&(state_data->accounts), state_data->no_accounts * sizeof(CuEVM::account_t))); + + while (PyDict_Next(data, &pos, &key, &value)) { + int account_index = pos - 1; // Adjust index since PyDict_Next increments pos + const char* address_str = PyUnicode_AsUTF8(key); + + // Extract balance, nonce, and code + const char* balance = GET_STR_FROM_DICT_WITH_DEFAULT(value, "balance", "0x0"); + const char* nonce = GET_STR_FROM_DICT_WITH_DEFAULT(value, "nonce", "0x0"); + const char* code = GET_STR_FROM_DICT_WITH_DEFAULT(value, "code", ""); + + // Initialize account details + state_data->accounts[account_index].address.from_hex(address_str); + state_data->accounts[account_index].balance.from_hex(balance); + state_data->accounts[account_index].nonce.from_hex(nonce); + // arith.cgbn_memory_from_hex_string(state_data->accounts[account_index].balance, balance); + // arith.cgbn_memory_from_hex_string(state_data->accounts[account_index].nonce, nonce); + // printf("Account %d: %s\n", account_index, address_str); + // Bytecode handling + // code = adjust_hex_string(code); + state_data->accounts[account_index].byte_code.from_hex(code, LITTLE_ENDIAN, NO_PADDING, 1); + + // Storage handling (assuming a function to handle storage initialization) + PyObject* storage_dict = PyDict_GetItemString(value, "storage"); + uint32_t storage_size = PyDict_Size(storage_dict); + if (storage_dict && storage_size > 0) { + // Assuming you have a function to handle storage initialization + // initialize_storage(&state_data->accounts[account_index], storage_dict); + + uint32_t capacity = CuEVM::initial_storage_capacity / 2; + do { + capacity *= 2; + } while (capacity < storage_size); + + CUDA_CHECK(cudaMallocManaged(&state_data->accounts[account_index].storage.storage, + capacity * sizeof(storage_element_t))); + state_data->accounts[account_index].storage.capacity = capacity; + state_data->accounts[account_index].storage.size = storage_size; + PyObject *key_storage, *value_storage; + + Py_ssize_t pos_storage = 0; + Py_ssize_t idx_storage = 0; + // allocate the storage + size_t idx = 0; + // Iterate through the dictionary + while (PyDict_Next(storage_dict, &pos_storage, &key_storage, &value_storage)) { + // Increase reference count for key and value before storing them + Py_INCREF(key_storage); + Py_INCREF(value_storage); + + PyObject* keyStrObj = PyObject_Str(key_storage); + const char* keyStr = PyUnicode_AsUTF8(keyStrObj); + state_data->accounts[account_index].storage.storage[idx].key.from_hex(keyStr); + Py_DECREF(keyStrObj); + + PyObject* valueStrObj = PyObject_Str(value_storage); + const char* valueStr = PyUnicode_AsUTF8(valueStrObj); + state_data->accounts[account_index].storage.storage[idx].value.from_hex(valueStr); + Py_DECREF(valueStrObj); + idx++; + } + + } else { + state_data->accounts[account_index].storage.capacity = 0; + state_data->accounts[account_index].storage.size = 0; + state_data->accounts[account_index].storage.storage = nullptr; + } + } + + return state_data; +} + +void get_evm_instances_from_PyObject(CuEVM::evm_instance_t*& evm_instances, PyObject* read_roots, + uint32_t& num_instances) { + uint32_t num_transactions = PyList_Size(read_roots); + // CuEVM::transaction::get_transactions(arith, transactions_ptr, test_json, num_transactions, managed, + // world_state_data_ptr); + + evm_transaction_t* all_transactions = getTransactionDataFromListofPyObject(read_roots); + + // share world state data + CuEVM::state_t* shared_world_state_data = nullptr; + // generate the evm instances + + CUDA_CHECK(cudaMallocManaged(&evm_instances, num_transactions * sizeof(evm_instance_t))); + for (Py_ssize_t index = 0; index < num_transactions; index++) { + PyObject* read_root = PyList_GetItem(read_roots, index); + if (!PyDict_Check(read_root)) { + PyErr_SetString(PyExc_TypeError, "Each item in the list must be a dictionary."); + return; + } + + evm_instances[index].world_state_data_ptr = getStateDataFromPyObject(PyDict_GetItemString(read_root, "pre")); + // if (shared_world_state_data == nullptr) { + // shared_world_state_data = getStateDataFromPyObject(PyDict_GetItemString(read_root, "pre")); + // } + // evm_instances[index].world_state_data_ptr = shared_world_state_data; + + evm_instances[index].block_info_ptr = getBlockDataFromPyObject(PyDict_GetItemString(read_root, "env")); + evm_instances[index].transaction_ptr = &all_transactions[index]; + + CuEVM::state_access_t* access_state = new CuEVM::state_access_t(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].touch_state_data_ptr, sizeof(CuEVM::state_access_t))); + memcpy(evm_instances[index].touch_state_data_ptr, access_state, sizeof(CuEVM::state_access_t)); + delete access_state; + CuEVM::log_state_data_t* log_state = new CuEVM::log_state_data_t(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].log_state_ptr, sizeof(CuEVM::log_state_data_t))); + memcpy(evm_instances[index].log_state_ptr, log_state, sizeof(CuEVM::log_state_data_t)); + delete log_state; + CuEVM::evm_return_data_t* return_data = new CuEVM::evm_return_data_t(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].return_data_ptr, sizeof(CuEVM::evm_return_data_t))); + memcpy(evm_instances[index].return_data_ptr, return_data, sizeof(CuEVM::evm_return_data_t)); + delete return_data; + + CuEVM::EccConstants* ecc_constants_ptr = new CuEVM::EccConstants(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].ecc_constants_ptr, sizeof(CuEVM::EccConstants))); + memcpy(evm_instances[index].ecc_constants_ptr, ecc_constants_ptr, sizeof(CuEVM::EccConstants)); + delete ecc_constants_ptr; +#ifdef EIP_3155 + CuEVM::utils::tracer_t* tracer = new CuEVM::utils::tracer_t(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].tracer_ptr, sizeof(CuEVM::utils::tracer_t))); + memcpy(evm_instances[index].tracer_ptr, tracer, sizeof(CuEVM::utils::tracer_t)); + delete tracer; +#endif + + CuEVM::serialized_worldstate_data* serialized_worldstate_data = new CuEVM::serialized_worldstate_data(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].serialized_worldstate_data_ptr, + sizeof(CuEVM::serialized_worldstate_data))); + memcpy(evm_instances[index].serialized_worldstate_data_ptr, serialized_worldstate_data, + sizeof(CuEVM::serialized_worldstate_data)); + delete serialized_worldstate_data; + + CuEVM::utils::simplified_trace_data* simplified_trace_data = new CuEVM::utils::simplified_trace_data(); + CUDA_CHECK(cudaMallocManaged(&evm_instances[index].simplified_trace_data_ptr, + sizeof(CuEVM::utils::simplified_trace_data))); + memcpy(evm_instances[index].simplified_trace_data_ptr, simplified_trace_data, + sizeof(CuEVM::utils::simplified_trace_data)); + delete simplified_trace_data; + // printf("size of serialized worldstate data %u\n", sizeof(CuEVM::serialized_worldstate_data)); + // printf("size of simplified trace data %u\n", sizeof(CuEVM::utils::simplified_trace_data)); + } + + num_instances = num_transactions; +} + +static PyObject* pyobject_from_simplified_trace(CuEVM::utils::simplified_trace_data trace_data) { + PyObject* tracer_root = PyDict_New(); + + PyObject* branches = PyList_New(0); + PyObject* events = PyList_New(0); + PyObject* calls = PyList_New(0); + char hex_string[43]; + // process call + for (size_t idx = 0; idx < trace_data.no_calls; idx++) { + PyObject* call_item = PyDict_New(); + PyDict_SetItemString(call_item, "sender", + PyUnicode_FromString(trace_data.calls[idx].sender.address_to_hex(hex_string))); + PyDict_SetItemString(call_item, "receiver", + PyUnicode_FromString(trace_data.calls[idx].receiver.address_to_hex(hex_string))); + + PyDict_SetItemString(call_item, "pc", PyLong_FromSize_t(trace_data.calls[idx].pc)); + PyDict_SetItemString(call_item, "op", PyLong_FromSize_t(trace_data.calls[idx].op)); + PyDict_SetItemString(call_item, "value", PyUnicode_FromString(trace_data.calls[idx].value.to_hex())); + PyDict_SetItemString(call_item, "success", PyLong_FromSize_t(trace_data.calls[idx].success)); + PyList_Append(calls, call_item); + Py_DECREF(call_item); + } + + for (size_t idx = 0; idx < trace_data.no_events; idx++) { + PyObject* event_item = PyDict_New(); + PyDict_SetItemString(event_item, "pc", PyLong_FromSize_t(trace_data.events[idx].pc)); + PyDict_SetItemString(event_item, "op", PyLong_FromSize_t(trace_data.events[idx].op)); + PyDict_SetItemString(event_item, "operand_1", PyUnicode_FromString(trace_data.events[idx].operand_1.to_hex())); + PyDict_SetItemString(event_item, "operand_2", PyUnicode_FromString(trace_data.events[idx].operand_2.to_hex())); + PyDict_SetItemString(event_item, "res", PyUnicode_FromString(trace_data.events[idx].res.to_hex())); + PyList_Append(events, event_item); + Py_DECREF(event_item); + } + + for (size_t idx = 0; idx < trace_data.no_branches; idx++) { + PyObject* branch_item = PyDict_New(); + PyDict_SetItemString(branch_item, "pc_src", PyLong_FromSize_t(trace_data.branches[idx].pc_src)); + PyDict_SetItemString(branch_item, "pc_dst", PyLong_FromSize_t(trace_data.branches[idx].pc_dst)); + PyDict_SetItemString(branch_item, "pc_missed", PyLong_FromSize_t(trace_data.branches[idx].pc_missed)); + PyDict_SetItemString(branch_item, "distance", PyUnicode_FromString(trace_data.branches[idx].distance.to_hex())); + PyList_Append(branches, branch_item); + Py_DECREF(branch_item); + } + + PyDict_SetItemString(tracer_root, "events", events); + PyDict_SetItemString(tracer_root, "branches", branches); + PyDict_SetItemString(tracer_root, "calls", calls); + + return tracer_root; +} + +PyObject* pyobject_from_serialized_state(CuEVM::serialized_worldstate_data* serialized_worldstate_instance) { + PyObject* state_dict = PyDict_New(); + + // Add accounts and storage elements + // PyObject* accounts_list = PyList_New(0); + uint32_t account_idx = 0; + uint32_t storage_idx = 0; + for (uint32_t i = 0; i < serialized_worldstate_instance->no_accounts; i++) { + PyObject* account_dict = PyDict_New(); + + PyDict_SetItemString(account_dict, "balance", PyUnicode_FromString(serialized_worldstate_instance->balance[i])); + PyDict_SetItemString(account_dict, "nonce", PyLong_FromUnsignedLong(serialized_worldstate_instance->nonce[i])); + + // Add storage elements for the account if they exist + PyObject* storage_dict = PyDict_New(); + while (storage_idx < serialized_worldstate_instance->no_storage_elements && + serialized_worldstate_instance->storage_indexes[storage_idx] == i) { + PyObject* storage_key_value = PyDict_New(); + + PyDict_SetItem(storage_dict, + PyUnicode_FromString(serialized_worldstate_instance->storage_keys[storage_idx]), + PyUnicode_FromString(serialized_worldstate_instance->storage_values[storage_idx])); + Py_DECREF(storage_key_value); + storage_idx++; + } + + PyDict_SetItemString(account_dict, "storage", storage_dict); + // PyList_Append(accounts_list, account_dict); + PyDict_SetItemString(state_dict, serialized_worldstate_instance->addresses[i], account_dict); + Py_DECREF(account_dict); + } + return state_dict; +} + +PyObject* pyobject_from_evm_instances(CuEVM::evm_instance_t* instances, uint32_t num_instances) { + PyObject* root = PyDict_New(); + // PyObject* world_state_json = pyobject_from_state_data_t(arith, instances.world_state_data); + // PyDict_SetItemString(root, "pre", world_state_json); + // Py_DECREF(world_state_json); + PyObject* instances_json = PyList_New(0); + PyDict_SetItemString(root, "post", instances_json); + Py_DECREF(instances_json); // Decrement here because PyDict_SetItemString increases the ref count + + for (uint32_t idx = 0; idx < num_instances; idx++) { + CuEVM::state_t* world_state_instance = instances[idx].world_state_data_ptr; // update on this + CuEVM::serialized_worldstate_data* serialized_worldstate = instances[idx].serialized_worldstate_data_ptr; + + PyObject* instance_json = PyDict_New(); + + // TODO: Print resultant state. to check with state_root branch + PyObject* state_json = pyobject_from_serialized_state(serialized_worldstate); // PyList_New(0); + + PyDict_SetItemString(instance_json, "state", state_json); + PyObject* tracer_json = pyobject_from_simplified_trace(*instances[idx].simplified_trace_data_ptr); + PyDict_SetItemString(instance_json, "trace", tracer_json); + // printf("state json result\n"); + // print_dict_recursive(state_json, 0); + // printf("tracer json result\n"); + // print_dict_recursive(tracer_json, 0); + PyList_Append(instances_json, instance_json); // Appends and steals the reference, so no need to DECREF + } + + return root; +} + +} // namespace python_utils