From 991c31f42bd4a9f32870d34310afb8c0ecc87df3 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 25 Aug 2023 11:29:39 +0200 Subject: [PATCH] add helpers for processing transactions to `libnimbus_lc.a` (#5269) It is useful to verify transactions data against `transactionsRoot`. Add corresponding functionality to the light client library. --- beacon_chain/libnimbus_lc/libnimbus_lc.h | 418 +++++++++- beacon_chain/libnimbus_lc/libnimbus_lc.nim | 738 ++++++++++++++++-- .../libnimbus_lc/test_files/transactions.json | 249 ++++++ beacon_chain/libnimbus_lc/test_libnimbus_lc.c | 130 +++ beacon_chain/spec/helpers.nim | 1 + 5 files changed, 1484 insertions(+), 52 deletions(-) create mode 100644 beacon_chain/libnimbus_lc/test_files/transactions.json diff --git a/beacon_chain/libnimbus_lc/libnimbus_lc.h b/beacon_chain/libnimbus_lc/libnimbus_lc.h index 01661b6a3..8167ef312 100644 --- a/beacon_chain/libnimbus_lc/libnimbus_lc.h +++ b/beacon_chain/libnimbus_lc/libnimbus_lc.h @@ -1002,22 +1002,22 @@ const ETHUInt256 *ETHExecutionPayloadHeaderGetBaseFeePerGas( const ETHExecutionPayloadHeader *execution); /** - * Obtains the data gas used of a given execution payload header. + * Obtains the blob gas used of a given execution payload header. * * @param execution Execution payload header. * - * @return Data gas used. + * @return Blob gas used. */ ETH_RESULT_USE_CHECK int ETHExecutionPayloadHeaderGetBlobGasUsed( const ETHExecutionPayloadHeader *execution); /** - * Obtains the excess data gas of a given execution payload header. + * Obtains the excess blob gas of a given execution payload header. * * @param execution Execution payload header. * - * @return Excess data gas. + * @return Excess blob gas. */ ETH_RESULT_USE_CHECK int ETHExecutionPayloadHeaderGetExcessBlobGas( @@ -1034,7 +1034,7 @@ typedef struct ETHExecutionBlockHeader ETHExecutionBlockHeader; * * - The JSON-RPC `eth_getBlockByHash` with params `[executionHash, false]` * may be used to obtain execution block header data for a given execution - * block hash. Pass the response's `result` property to `blockHeaderJson`. + * block hash. Pass the response's `result` property as `blockHeaderJson`. * * - The execution block header must be destroyed with * `ETHExecutionBlockHeaderDestroy` once no longer needed, @@ -1092,6 +1092,414 @@ ETH_RESULT_USE_CHECK const ETHRoot *ETHExecutionBlockHeaderGetWithdrawalsRoot( const ETHExecutionBlockHeader *executionBlockHeader); +/** + * Transaction sequence. + */ +typedef struct ETHTransactions ETHTransactions; + +/** + * Verifies that JSON transactions data is valid and that it matches + * the given `transactionsRoot`. + * + * - The JSON-RPC `eth_getBlockByHash` with params `[executionHash, true]` + * may be used to obtain transactions data for a given execution + * block hash. Pass `result.transactions` as `transactionsJson`. + * + * - The transaction sequence must be destroyed with + * `ETHTransactionsDestroy` once no longer needed, + * to release memory. + * + * @param transactionsRoot Execution transactions root. + * @param transactionsJson Buffer with JSON transactions list. NULL-terminated. + * + * @return Pointer to an initialized transaction sequence - If successful. + * @return `NULL` - If the given `transactionsJson` is malformed or incompatible. + * + * @see https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash + */ +ETH_RESULT_USE_CHECK +ETHTransactions *ETHTransactionsCreateFromJson( + const ETHRoot *transactionsRoot, + const char *transactionsJson); + +/** + * Destroys a transaction sequence. + * + * - The transaction sequence must no longer be used after destruction. + * + * @param transactions Transaction sequence. + */ +void ETHTransactionsDestroy(ETHTransactions *transactions); + +/** + * Indicates the total number of transactions in a transaction sequence. + * + * - Individual transactions may be investigated using `ETHTransactionsGet`. + * + * @param transactions Transaction sequence. + * + * @return Number of available transactions. + */ +ETH_RESULT_USE_CHECK +int ETHTransactionsGetCount(const ETHTransactions *transactions); + +/** + * Transaction. + */ +typedef struct ETHTransaction ETHTransaction; + +/** + * Obtains an individual transaction by sequential index + * in a transaction sequence. + * + * - The returned value is allocated in the given transaction sequence. + * It must neither be released nor written to, and the transaction + * sequence must not be released while the returned value is in use. + * + * @param transactions Transaction sequence. + * @param transactionIndex Sequential transaction index. + * + * @return Transaction. + */ +ETH_RESULT_USE_CHECK +const ETHTransaction *ETHTransactionsGet( + const ETHTransactions *transactions, + int transactionIndex); + +/** + * Obtains the transaction hash of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Transaction hash. + */ +ETH_RESULT_USE_CHECK +const ETHRoot *ETHTransactionGetHash(const ETHTransaction *transaction); + +/** + * Obtains the chain ID of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Chain ID. + */ +ETH_RESULT_USE_CHECK +const ETHUInt256 *ETHTransactionGetChainId(const ETHTransaction *transaction); + +/** + * Obtains the from address of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return From execution address. + */ +ETH_RESULT_USE_CHECK +const ETHExecutionAddress *ETHTransactionGetFrom(const ETHTransaction *transaction); + +/** + * Obtains the nonce of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Nonce. + */ +ETH_RESULT_USE_CHECK +const uint64_t *ETHTransactionGetNonce(const ETHTransaction *transaction); + +/** + * Obtains the max priority fee per gas of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Max priority fee per gas. + */ +ETH_RESULT_USE_CHECK +const uint64_t *ETHTransactionGetMaxPriorityFeePerGas(const ETHTransaction *transaction); + +/** + * Obtains the max fee per gas of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Max fee per gas. + */ +ETH_RESULT_USE_CHECK +const uint64_t *ETHTransactionGetMaxFeePerGas(const ETHTransaction *transaction); + +/** + * Obtains the gas of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Gas. + */ +ETH_RESULT_USE_CHECK +const uint64_t *ETHTransactionGetGas(const ETHTransaction *transaction); + +/** + * Indicates whether or not a transaction is creating a contract. + * + * @param transaction Transaction. + * + * @return Whether or not the transaction is creating a contract. + */ +ETH_RESULT_USE_CHECK +bool ETHTransactionIsCreatingContract(const ETHTransaction *transaction); + +/** + * Obtains the to address of a transaction. + * + * - If the transaction is creating a contract, this function returns + * the address of the new contract. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return To execution address. + */ +ETH_RESULT_USE_CHECK +const ETHExecutionAddress *ETHTransactionGetTo(const ETHTransaction *transaction); + +/** + * Obtains the value of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Value. + */ +ETH_RESULT_USE_CHECK +const ETHUInt256 *ETHTransactionGetValue(const ETHTransaction *transaction); + +/** + * Obtains the input of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * @param[out] numBytes Length of buffer. + * + * @return Buffer with input. + */ +ETH_RESULT_USE_CHECK +const void *ETHTransactionGetInputBytes( + const ETHTransaction *transaction, + int *numBytes); + +/** + * Transaction access list. + */ +typedef struct ETHAccessList ETHAccessList; + +/** + * Obtains the access list of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Transaction access list. + */ +ETH_RESULT_USE_CHECK +const ETHAccessList *ETHTransactionGetAccessList(const ETHTransaction *transaction); + +/** + * Indicates the total number of access tuples in a transaction access list. + * + * - Individual access tuples may be investigated using `ETHAccessListGet`. + * + * @param accessList Transaction access list. + * + * @return Number of available access tuples. + */ +ETH_RESULT_USE_CHECK +int ETHAccessListGetCount(const ETHAccessList *accessList); + +/** + * Access tuple. + */ +typedef struct ETHAccessTuple ETHAccessTuple; + +/** + * Obtains an individual access tuple by sequential index + * in a transaction access list. + * + * - The returned value is allocated in the given transaction access list. + * It must neither be released nor written to, and the transaction + * access list must not be released while the returned value is in use. + * + * @param accessList Transaction access list. + * @param accessTupleIndex Sequential access tuple index. + * + * @return Access tuple. + */ +ETH_RESULT_USE_CHECK +const ETHAccessTuple *ETHAccessListGet( + const ETHAccessList *accessList, + int accessTupleIndex); + +/** + * Obtains the address of an access tuple. + * + * - The returned value is allocated in the given access tuple. + * It must neither be released nor written to, and the access tuple + * must not be released while the returned value is in use. + * + * @param accessTuple Access tuple. + * + * @return Address. + */ +ETH_RESULT_USE_CHECK +const ETHExecutionAddress *ETHAccessTupleGetAddress(const ETHAccessTuple *accessTuple); + +/** + * Indicates the total number of storage keys in an access tuple. + * + * - Individual storage keys may be investigated using + * `ETHAccessTupleGetStorageKey`. + * + * @param accessTuple Access tuple. + * + * @return Number of available storage keys. + */ +ETH_RESULT_USE_CHECK +int ETHAccessTupleGetNumStorageKeys(const ETHAccessTuple *accessTuple); + +/** + * Obtains an individual storage key by sequential index + * in an access tuple. + * + * - The returned value is allocated in the given transaction access tuple. + * It must neither be released nor written to, and the transaction + * access tuple must not be released while the returned value is in use. + * + * @param accessTuple Access tuple. + * @param storageKeyIndex Sequential storage key index. + * + * @return Storage key. + */ +ETH_RESULT_USE_CHECK +const ETHRoot *ETHAccessTupleGetStorageKey( + const ETHAccessTuple *accessTuple, + int storageKeyIndex); + +/** + * Obtains the max fee per blob gas of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * + * @return Max fee per blob gas. + */ +ETH_RESULT_USE_CHECK +const uint64_t *ETHTransactionGetMaxFeePerBlobGas(const ETHTransaction *transaction); + +/** + * Indicates the total number of blob versioned hashes of a transaction. + * + * - Individual blob versioned hashes may be investigated using + * `ETHTransactionGetBlobVersionedHash`. + * + * @param transaction Transaction. + * + * @return Number of available blob versioned hashes. + */ +ETH_RESULT_USE_CHECK +int ETHTransactionGetNumBlobVersionedHashes(const ETHTransaction *transaction); + +/** + * Obtains an individual blob versioned hash by sequential index + * in a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * @param versionedHashIndex Sequential blob versioned hash index. + * + * @return Blob versioned hash. + */ +ETH_RESULT_USE_CHECK +const ETHRoot *ETHTransactionGetBlobVersionedHash( + const ETHTransaction *transaction, + int versionedHashIndex); + +/** + * Obtains the signature of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * @param[out] numBytes Length of buffer. + * + * @return Buffer with signature. + */ +ETH_RESULT_USE_CHECK +const void *ETHTransactionGetSignatureBytes( + const ETHTransaction *transaction, + int *numBytes); + +/** + * Obtains the raw byte representation of a transaction. + * + * - The returned value is allocated in the given transaction. + * It must neither be released nor written to, and the transaction + * must not be released while the returned value is in use. + * + * @param transaction Transaction. + * @param[out] numBytes Length of buffer. + * + * @return Buffer with raw transaction data. + */ +ETH_RESULT_USE_CHECK +const void *ETHTransactionGetBytes( + const ETHTransaction *transaction, + int *numBytes); + #if __has_feature(nullability) #pragma clang assume_nonnull end #endif diff --git a/beacon_chain/libnimbus_lc/libnimbus_lc.nim b/beacon_chain/libnimbus_lc/libnimbus_lc.nim index 1d9a58587..36572a9c2 100644 --- a/beacon_chain/libnimbus_lc/libnimbus_lc.nim +++ b/beacon_chain/libnimbus_lc/libnimbus_lc.nim @@ -8,11 +8,15 @@ {.push raises: [].} import - std/[json, times], + std/[json, sequtils, times], stew/saturation_arith, - eth/common/eth_types_rlp, + eth/common/[eth_types_rlp, transaction], + eth/keys, eth/p2p/discoveryv5/random2, + eth/rlp, + eth/trie/[db, hexary], json_rpc/jsonmarshal, + secp256k1, web3/ethtypes, ../el/el_manager, ../spec/eth2_apis/[eth2_rest_serialization, rest_light_client_calls], @@ -1174,7 +1178,7 @@ func ETHExecutionPayloadHeaderGetExcessBlobGas( execution[].excess_blob_gas.cint type ETHExecutionBlockHeader = object - txRoot: Eth2Digest + transactionsRoot: Eth2Digest withdrawalsRoot: Eth2Digest proc ETHExecutionBlockHeaderCreateFromJson( @@ -1185,7 +1189,7 @@ proc ETHExecutionBlockHeaderCreateFromJson( ## ## * The JSON-RPC `eth_getBlockByHash` with params `[executionHash, false]` ## may be used to obtain execution block header data for a given execution - ## block hash. Pass the response's `result` property to `blockHeaderJson`. + ## block hash. Pass the response's `result` property as `blockHeaderJson`. ## ## * The execution block header must be destroyed with ## `ETHExecutionBlockHeaderDestroy` once no longer needed, @@ -1206,78 +1210,76 @@ proc ETHExecutionBlockHeaderCreateFromJson( parseJson($blockHeaderJson) except Exception: return nil - var bdata: BlockObject + var data: BlockObject try: - fromJson(node, argName = "", bdata) + fromJson(node, argName = "", data) except KeyError, ValueError: return nil - if bdata == nil: + if data == nil: return nil # Sanity check - if bdata.hash.asEth2Digest != executionHash[]: + if data.hash.asEth2Digest != executionHash[]: return nil # Check fork consistency static: doAssert totalSerializedFields(BlockObject) == 26, "Only update this number once code is adjusted to check new fields!" - if bdata.baseFeePerGas.isNone and ( - bdata.withdrawals.isSome or bdata.withdrawalsRoot.isSome or - bdata.blobGasUsed.isSome or bdata.excessBlobGas.isSome): + if data.baseFeePerGas.isNone and ( + data.withdrawals.isSome or data.withdrawalsRoot.isSome or + data.blobGasUsed.isSome or data.excessBlobGas.isSome): return nil - if bdata.withdrawalsRoot.isNone and ( - bdata.blobGasUsed.isSome or bdata.excessBlobGas.isSome): + if data.withdrawalsRoot.isNone and ( + data.blobGasUsed.isSome or data.excessBlobGas.isSome): return nil - if bdata.withdrawals.isSome != bdata.withdrawalsRoot.isSome: + if data.withdrawals.isSome != data.withdrawalsRoot.isSome: return nil - if bdata.blobGasUsed.isSome != bdata.excessBlobGas.isSome: - return nil - if bdata.parentBeaconBlockRoot.isSome != bdata.parentBeaconBlockRoot.isSome: + if data.blobGasUsed.isSome != data.excessBlobGas.isSome: return nil # Construct block header static: # `GasInt` is signed. We only use it for hashing. - doAssert sizeof(int64) == sizeof(bdata.gasLimit) - doAssert sizeof(int64) == sizeof(bdata.gasUsed) - if distinctBase(bdata.timestamp) > int64.high.uint64: + doAssert sizeof(int64) == sizeof(data.gasLimit) + doAssert sizeof(int64) == sizeof(data.gasUsed) + if distinctBase(data.timestamp) > int64.high.uint64: return nil - if bdata.nonce.isNone: + if data.nonce.isNone: return nil let blockHeader = ExecutionBlockHeader( - parentHash: bdata.parentHash.asEth2Digest, - ommersHash: bdata.sha3Uncles.asEth2Digest, - coinbase: distinctBase(bdata.miner), - stateRoot: bdata.stateRoot.asEth2Digest, - txRoot: bdata.transactionsRoot.asEth2Digest, - receiptRoot: bdata.receiptsRoot.asEth2Digest, - bloom: distinctBase(bdata.logsBloom), - difficulty: bdata.difficulty, - blockNumber: distinctBase(bdata.number).u256, - gasLimit: cast[int64](bdata.gasLimit), - gasUsed: cast[int64](bdata.gasUsed), - timestamp: fromUnix(int64.saturate distinctBase(bdata.timestamp)), - extraData: distinctBase(bdata.extraData), - mixDigest: bdata.mixHash.asEth2Digest, - nonce: distinctBase(bdata.nonce.get), - fee: bdata.baseFeePerGas, + parentHash: data.parentHash.asEth2Digest, + ommersHash: data.sha3Uncles.asEth2Digest, + coinbase: distinctBase(data.miner), + stateRoot: data.stateRoot.asEth2Digest, + txRoot: data.transactionsRoot.asEth2Digest, + receiptRoot: data.receiptsRoot.asEth2Digest, + bloom: distinctBase(data.logsBloom), + difficulty: data.difficulty, + blockNumber: distinctBase(data.number).u256, + gasLimit: cast[int64](data.gasLimit), + gasUsed: cast[int64](data.gasUsed), + timestamp: fromUnix(int64.saturate distinctBase(data.timestamp)), + extraData: distinctBase(data.extraData), + mixDigest: data.mixHash.asEth2Digest, + nonce: distinctBase(data.nonce.get), + fee: data.baseFeePerGas, withdrawalsRoot: - if bdata.withdrawalsRoot.isSome: - some(bdata.withdrawalsRoot.get.asEth2Digest) + if data.withdrawalsRoot.isSome: + some(data.withdrawalsRoot.get.asEth2Digest) else: none(ExecutionHash256), blobGasUsed: - if bdata.blobGasUsed.isSome: - some distinctBase(bdata.blobGasUsed.get) + if data.blobGasUsed.isSome: + some distinctBase(data.blobGasUsed.get) else: none(uint64), excessBlobGas: - if bdata.excessBlobGas.isSome: - some distinctBase(bdata.excessBlobGas.get) + if data.excessBlobGas.isSome: + some distinctBase(data.excessBlobGas.get) else: none(uint64), parentBeaconBlockRoot: - if bdata.parentBeaconBlockRoot.isSome: - some distinctBase(bdata.parentBeaconBlockRoot.get.asEth2Digest) + if data.parentBeaconBlockRoot.isSome: + some distinctBase(data.parentBeaconBlockRoot.get.asEth2Digest) else: none(ExecutionHash256)) if rlpHash(blockHeader) != executionHash[]: @@ -1285,7 +1287,7 @@ proc ETHExecutionBlockHeaderCreateFromJson( let executionBlockHeader = ETHExecutionBlockHeader.new() executionBlockHeader[] = ETHExecutionBlockHeader( - txRoot: blockHeader.txRoot, + transactionsRoot: blockHeader.txRoot, withdrawalsRoot: blockHeader.withdrawalsRoot.get(ZERO_HASH)) executionBlockHeader.toUnmanagedPtr() @@ -1313,7 +1315,7 @@ func ETHExecutionBlockHeaderGetTransactionsRoot( ## ## Returns: ## * Execution transactions root. - addr executionBlockHeader[].txRoot + addr executionBlockHeader[].transactionsRoot func ETHExecutionBlockHeaderGetWithdrawalsRoot( executionBlockHeader: ptr ETHExecutionBlockHeader @@ -1330,3 +1332,645 @@ func ETHExecutionBlockHeaderGetWithdrawalsRoot( ## Returns: ## * Execution withdrawals root. addr executionBlockHeader[].withdrawalsRoot + +type + ETHAccessTuple = object + address: ExecutionAddress + storageKeys: seq[Eth2Digest] + + DestinationType {.pure.} = enum + Regular, + Create + + ETHTransaction = object + hash: Eth2Digest + chainId: UInt256 + `from`: ExecutionAddress + nonce: uint64 + maxPriorityFeePerGas: uint64 + maxFeePerGas: uint64 + gas: uint64 + destinationType: DestinationType + to: ExecutionAddress + value: UInt256 + input: seq[byte] + accessList: seq[ETHAccessTuple] + maxFeePerBlobGas: uint64 + blobVersionedHashes: seq[Eth2Digest] + signature: seq[byte] + bytes: TypedTransaction + +proc ETHTransactionsCreateFromJson( + transactionsRoot: ptr Eth2Digest, + transactionsJson: cstring): ptr seq[ETHTransaction] {.exported.} = + ## Verifies that JSON transactions data is valid and that it matches + ## the given `transactionsRoot`. + ## + ## * The JSON-RPC `eth_getBlockByHash` with params `[executionHash, true]` + ## may be used to obtain transactions data for a given execution + ## block hash. Pass `result.transactions` as `transactionsJson`. + ## + ## * The transaction sequence must be destroyed with + ## `ETHTransactionsDestroy` once no longer needed, + ## to release memory. + ## + ## Parameters: + ## * `transactionsRoot` - Execution transactions root. + ## * `transactionsJson` - Buffer with JSON transactions list. NULL-terminated. + ## + ## Returns: + ## * Pointer to an initialized transaction sequence - If successful. + ## * `NULL` - If the given `transactionsJson` is malformed or incompatible. + ## + ## See: + ## * https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash + let node = + try: + parseJson($transactionsJson) + except Exception: + return nil + var datas: seq[TransactionObject] + try: + fromJson(node, argName = "", datas) + except KeyError, ValueError: + return nil + + var txs = newSeqOfCap[ETHTransaction](datas.len) + for i, data in datas: + # Sanity check + if data.transactionIndex.isNone: + return nil + if distinctBase(data.transactionIndex.get) != i.uint64: + return nil + + # Check fork consistency + static: doAssert totalSerializedFields(TransactionObject) == 21, + "Only update this number once code is adjusted to check new fields!" + let txType = + case data.`type`.get(0.Quantity): + of 0.Quantity: + if data.accessList.isSome or + data.maxFeePerGas.isSome or data.maxPriorityFeePerGas.isSome or + data.maxFeePerBlobGas.isSome or data.blobVersionedHashes.isSome: + return nil + TxLegacy + of 1.Quantity: + if data.chainId.isNone or data.accessList.isNone: + return nil + if data.maxFeePerGas.isSome or data.maxPriorityFeePerGas.isSome or + data.maxFeePerBlobGas.isSome or data.blobVersionedHashes.isSome: + return nil + TxEip2930 + of 2.Quantity: + if data.chainId.isNone or data.accessList.isNone or + data.maxFeePerGas.isNone or data.maxPriorityFeePerGas.isNone: + return nil + if data.maxFeePerBlobGas.isSome or data.blobVersionedHashes.isSome: + return nil + TxEip1559 + of 3.Quantity: + if data.to.isNone or data.chainId.isNone or data.accessList.isNone or + data.maxFeePerGas.isNone or data.maxPriorityFeePerGas.isNone or + data.maxFeePerBlobGas.isNone or data.blobVersionedHashes.isNone: + return nil + TxEip4844 + else: + return nil + + # Construct transaction + static: + doAssert sizeof(uint64) == sizeof(ChainId) + doAssert sizeof(int64) == sizeof(data.gasPrice) + doAssert sizeof(int64) == sizeof(data.maxPriorityFeePerGas.get) + doAssert sizeof(int64) == sizeof(data.maxFeePerBlobGas.get) + if data.chainId.get(default(UInt256)) > distinctBase(ChainId.high).u256: + return nil + if distinctBase(data.gasPrice) > int64.high.uint64: + return nil + if distinctBase(data.maxFeePerGas.get(0.Quantity)) > int64.high.uint64: + return nil + if distinctBase(data.maxPriorityFeePerGas.get(0.Quantity)) > + int64.high.uint64: + return nil + if distinctBase(data.maxFeePerBlobGas.get(0.Quantity)) > + int64.high.uint64: + return nil + if distinctBase(data.gas) > int64.high.uint64: + return nil + if data.v > int64.high.u256: + return nil + let + tx = ExecutionTransaction( + txType: txType, + chainId: data.chainId.get(default(UInt256)).truncate(uint64).ChainId, + nonce: distinctBase(data.nonce), + gasPrice: data.gasPrice.GasInt, + maxPriorityFee: + distinctBase(data.maxPriorityFeePerGas.get(data.gasPrice)).GasInt, + maxFee: distinctBase(data.maxFeePerGas.get(data.gasPrice)).GasInt, + gasLimit: distinctBase(data.gas).GasInt, + to: + if data.to.isSome: + some(distinctBase(data.to.get)) + else: + none(EthAddress), + value: data.value, + payload: data.input, + accessList: + if data.accessList.isSome: + data.accessList.get.mapIt(AccessPair( + address: distinctBase(it.address), + storageKeys: it.storageKeys.mapIt(distinctBase(it)))) + else: + @[], + maxFeePerBlobGas: + distinctBase(data.maxFeePerBlobGas.get(0.Quantity)).GasInt, + versionedHashes: + if data.blobVersionedHashes.isSome: + data.blobVersionedHashes.get.mapIt( + ExecutionHash256(data: distinctBase(it))) + else: + @[], + V: data.v.truncate(uint64).int64, + R: data.r, + S: data.s) + rlpBytes = + try: + rlp.encode(tx) + except RlpError: + raiseAssert "Unreachable" + hash = keccakHash(rlpBytes) + if data.hash.asEth2Digest != hash: + return nil + + # Compute from execution address + var rawSig {.noinit.}: array[65, byte] + rawSig[0 ..< 32] = tx.R.toBytesBE() + rawSig[32 ..< 64] = tx.S.toBytesBE() + rawSig[64] = + if txType != TxLegacy: + tx.V.uint8 + elif tx.V.isEven: + 1 + else: + 0 + let + sig = SkRecoverableSignature.fromRaw(rawSig).valueOr: + return nil + sigHash = SkMessage.fromBytes(tx.txHashNoSignature().data).valueOr: + return nil + fromPubkey = sig.recover(sigHash).valueOr: + return nil + fromAddress = keys.PublicKey(fromPubkey).toCanonicalAddress() + if distinctBase(data.`from`) != fromAddress: + return nil + + # Compute to execution address + let + destinationType = + if tx.to.isSome: + DestinationType.Regular + else: + DestinationType.Create + toAddress = + case destinationType + of DestinationType.Regular: + tx.to.get + of DestinationType.Create: + var res {.noinit.}: array[20, byte] + res[0 ..< 20] = keccakHash(rlp.encodeList(fromAddress, tx.nonce)) + .data.toOpenArray(12, 31) + res + + txs.add ETHTransaction( + hash: keccakHash(rlpBytes), + chainId: distinctBase(tx.chainId).u256, + `from`: ExecutionAddress(data: fromAddress), + nonce: tx.nonce, + maxPriorityFeePerGas: tx.maxPriorityFee.uint64, + maxFeePerGas: tx.maxFee.uint64, + gas: tx.gasLimit.uint64, + destinationType: destinationType, + to: ExecutionAddress(data: toAddress), + value: tx.value, + input: tx.payload, + accessList: tx.accessList.mapIt(ETHAccessTuple( + address: ExecutionAddress(data: it.address), + storageKeys: it.storageKeys.mapIt(Eth2Digest(data: it)))), + maxFeePerBlobGas: tx.maxFeePerBlobGas.uint64, + blobVersionedHashes: tx.versionedHashes, + signature: @rawSig, + bytes: rlpBytes.TypedTransaction) + + var tr = initHexaryTrie(newMemoryDB()) + for i, transaction in txs: + try: + tr.put(rlp.encode(i), distinctBase(transaction.bytes)) + except RlpError: + raiseAssert "Unreachable" + if tr.rootHash() != transactionsRoot[]: + return nil + + let transactions = seq[ETHTransaction].new() + transactions[] = txs + transactions.toUnmanagedPtr() + +proc ETHTransactionsDestroy( + transactions: ptr seq[ETHTransaction]) {.exported.} = + ## Destroys a transaction sequence. + ## + ## * The transaction sequence must no longer be used after destruction. + ## + ## Parameters: + ## * `transactions` - Transaction sequence. + transactions.destroy() + +func ETHTransactionsGetCount( + transactions: ptr seq[ETHTransaction]): cint {.exported.} = + ## Indicates the total number of transactions in a transaction sequence. + ## + ## * Individual transactions may be investigated using `ETHTransactionsGet`. + ## + ## Parameters: + ## * `transactions` - Transaction sequence. + ## + ## Returns: + ## * Number of available transactions. + transactions[].len.cint + +func ETHTransactionsGet( + transactions: ptr seq[ETHTransaction], + transactionIndex: cint): ptr ETHTransaction {.exported.} = + ## Obtains an individual transaction by sequential index + ## in a transaction sequence. + ## + ## * The returned value is allocated in the given transaction sequence. + ## It must neither be released nor written to, and the transaction + ## sequence must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transactions` - Transaction sequence. + ## * `transactionIndex` - Sequential transaction index. + ## + ## Returns: + ## * Transaction. + addr transactions[][transactionIndex.int] + +func ETHTransactionGetHash( + transaction: ptr ETHTransaction): ptr Eth2Digest {.exported.} = + ## Obtains the transaction hash of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Transaction hash. + addr transaction[].hash + +func ETHTransactionGetChainId( + transaction: ptr ETHTransaction): ptr UInt256 {.exported.} = + ## Obtains the chain ID of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Chain ID. + addr transaction[].chainId + +func ETHTransactionGetFrom( + transaction: ptr ETHTransaction): ptr ExecutionAddress {.exported.} = + ## Obtains the from address of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * From execution address. + addr transaction[].`from` + +func ETHTransactionGetNonce( + transaction: ptr ETHTransaction): ptr uint64 {.exported.} = + ## Obtains the nonce of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Nonce. + addr transaction[].nonce + +func ETHTransactionGetMaxPriorityFeePerGas( + transaction: ptr ETHTransaction): ptr uint64 {.exported.} = + ## Obtains the max priority fee per gas of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Max priority fee per gas. + addr transaction[].maxPriorityFeePerGas + +func ETHTransactionGetMaxFeePerGas( + transaction: ptr ETHTransaction): ptr uint64 {.exported.} = + ## Obtains the max fee per gas of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Max fee per gas. + addr transaction[].maxFeePerGas + +func ETHTransactionGetGas( + transaction: ptr ETHTransaction): ptr uint64 {.exported.} = + ## Obtains the gas of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Gas. + addr transaction[].gas + +func ETHTransactionIsCreatingContract( + transaction: ptr ETHTransaction): bool {.exported.} = + ## Indicates whether or not a transaction is creating a contract. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Whether or not the transaction is creating a contract. + case transaction[].destinationType + of DestinationType.Regular: + false + of DestinationType.Create: + true + +func ETHTransactionGetTo( + transaction: ptr ETHTransaction): ptr ExecutionAddress {.exported.} = + ## Obtains the to address of a transaction. + ## + ## * If the transaction is creating a contract, this function returns + ## the address of the new contract. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * To execution address. + addr transaction[].to + +func ETHTransactionGetValue( + transaction: ptr ETHTransaction): ptr UInt256 {.exported.} = + ## Obtains the value of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Value. + addr transaction[].value + +func ETHTransactionGetInputBytes( + transaction: ptr ETHTransaction, + numBytes #[out]#: ptr cint): ptr UncheckedArray[byte] {.exported.} = + ## Obtains the input of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## * `numBytes` [out] - Length of buffer. + ## + ## Returns: + ## * Buffer with input. + numBytes[] = transaction[].input.len.cint + if transaction[].input.len == 0: + # https://github.com/nim-lang/Nim/issues/22389 + const defaultInput: cstring = "" + return cast[ptr UncheckedArray[byte]](defaultInput) + cast[ptr UncheckedArray[byte]](addr transaction[].input[0]) + +func ETHTransactionGetAccessList( + transaction: ptr ETHTransaction): ptr seq[ETHAccessTuple] {.exported.} = + ## Obtains the access list of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Transaction access list. + addr transaction[].accessList + +func ETHAccessListGetCount( + accessList: ptr seq[ETHAccessTuple]): cint {.exported.} = + ## Indicates the total number of access tuples in a transaction access list. + ## + ## * Individual access tuples may be investigated using `ETHAccessListGet`. + ## + ## Parameters: + ## * `accessList` - Transaction access list. + ## + ## Returns: + ## * Number of available access tuples. + accessList[].len.cint + +func ETHAccessListGet( + accessList: ptr seq[ETHAccessTuple], + accessTupleIndex: cint): ptr ETHAccessTuple {.exported.} = + ## Obtains an individual access tuple by sequential index + ## in a transaction access list. + ## + ## * The returned value is allocated in the given transaction access list. + ## It must neither be released nor written to, and the transaction + ## access list must not be released while the returned value is in use. + ## + ## Parameters: + ## * `accessList` - Transaction access list. + ## * `accessTupleIndex` - Sequential access tuple index. + ## + ## Returns: + ## * Access tuple. + addr accessList[][accessTupleIndex.int] + +func ETHAccessTupleGetAddress( + accessTuple: ptr ETHAccessTuple): ptr ExecutionAddress {.exported.} = + ## Obtains the address of an access tuple. + ## + ## * The returned value is allocated in the given access tuple. + ## It must neither be released nor written to, and the access tuple + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `accessTuple` - Access tuple. + ## + ## Returns: + ## * Address. + addr accessTuple[].address + +func ETHAccessTupleGetNumStorageKeys( + accessTuple: ptr ETHAccessTuple): cint {.exported.} = + ## Indicates the total number of storage keys in an access tuple. + ## + ## * Individual storage keys may be investigated using + ## `ETHAccessTupleGetStorageKey`. + ## + ## Parameters: + ## * `accessTuple` - Access tuple. + ## + ## Returns: + ## * Number of available storage keys. + accessTuple[].storageKeys.len.cint + +func ETHAccessTupleGetStorageKey( + accessTuple: ptr ETHAccessTuple, + storageKeyIndex: cint): ptr Eth2Digest {.exported.} = + ## Obtains an individual storage key by sequential index + ## in an access tuple. + ## + ## * The returned value is allocated in the given transaction access tuple. + ## It must neither be released nor written to, and the transaction + ## access tuple must not be released while the returned value is in use. + ## + ## Parameters: + ## * `accessTuple` - Access tuple. + ## * `storageKeyIndex` - Sequential storage key index. + ## + ## Returns: + ## * Storage key. + addr accessTuple[].storageKeys[storageKeyIndex.int] + +func ETHTransactionGetMaxFeePerBlobGas( + transaction: ptr ETHTransaction): ptr uint64 {.exported.} = + ## Obtains the max fee per blob gas of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Max fee per blob gas. + addr transaction[].maxFeePerBlobGas + +func ETHTransactionGetNumBlobVersionedHashes( + transaction: ptr ETHTransaction): cint {.exported.} = + ## Indicates the total number of blob versioned hashes of a transaction. + ## + ## * Individual blob versioned hashes may be investigated using + ## `ETHTransactionGetBlobVersionedHash`. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## + ## Returns: + ## * Number of available blob versioned hashes. + transaction[].blobVersionedHashes.len.cint + +func ETHTransactionGetBlobVersionedHash( + transaction: ptr ETHTransaction, + versionedHashIndex: cint): ptr Eth2Digest {.exported.} = + ## Obtains an individual blob versioned hash by sequential index + ## in a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## * `versionedHashIndex` - Sequential blob versioned hash index. + ## + ## Returns: + ## * Blob versioned hash. + addr transaction[].blobVersionedHashes[versionedHashIndex.int] + +func ETHTransactionGetSignatureBytes( + transaction: ptr ETHTransaction, + numBytes #[out]#: ptr cint): ptr UncheckedArray[byte] {.exported.} = + ## Obtains the signature of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## * `numBytes` [out] - Length of buffer. + ## + ## Returns: + ## * Buffer with signature. + numBytes[] = distinctBase(transaction[].signature).len.cint + if distinctBase(transaction[].signature).len == 0: + # https://github.com/nim-lang/Nim/issues/22389 + const defaultBytes: cstring = "" + return cast[ptr UncheckedArray[byte]](defaultBytes) + cast[ptr UncheckedArray[byte]](addr distinctBase(transaction[].signature)[0]) + +func ETHTransactionGetBytes( + transaction: ptr ETHTransaction, + numBytes #[out]#: ptr cint): ptr UncheckedArray[byte] {.exported.} = + ## Obtains the raw byte representation of a transaction. + ## + ## * The returned value is allocated in the given transaction. + ## It must neither be released nor written to, and the transaction + ## must not be released while the returned value is in use. + ## + ## Parameters: + ## * `transaction` - Transaction. + ## * `numBytes` [out] - Length of buffer. + ## + ## Returns: + ## * Buffer with raw transaction data. + numBytes[] = distinctBase(transaction[].bytes).len.cint + if distinctBase(transaction[].bytes).len == 0: + # https://github.com/nim-lang/Nim/issues/22389 + const defaultBytes: cstring = "" + return cast[ptr UncheckedArray[byte]](defaultBytes) + cast[ptr UncheckedArray[byte]](addr distinctBase(transaction[].bytes)[0]) diff --git a/beacon_chain/libnimbus_lc/test_files/transactions.json b/beacon_chain/libnimbus_lc/test_files/transactions.json new file mode 100644 index 000000000..5c01427c5 --- /dev/null +++ b/beacon_chain/libnimbus_lc/test_files/transactions.json @@ -0,0 +1,249 @@ +[ + { + "blockHash": "0x8e38b4dbf6b11fcc3b9dee84fb7986e29ca0a02cecd8977c161ff7333329681e", + "blockNumber": "0xf4240", + "from": "0x32be343b94f860124dc4fee278fdcbd38c102d88", + "gas": "0xc350", + "gasPrice": "0xdf8475800", + "hash": "0xe9e91f1ee4b56c0df2e9f06c2b8c27c6076195a88a7b8537ba8313d80e6f124e", + "input": "0x", + "nonce": "0x43eb", + "to": "0xdf190dc7190dfba737d7777a163445b7fff16133", + "transactionIndex": "0x0", + "value": "0x6113a84987be800", + "type": "0x0", + "v": "0x1c", + "r": "0x3b08715b4403c792b8c7567edea634088bedcd7f60d9352b1f16c69830f3afd5", + "s": "0x10b9afb67d2ec8b956f0e1dbc07eb79152904f3a7bf789fc869db56320adfe09" + }, + { + "type": "0x0", + "blockHash": "0xe380e7cf640a646ef901b6a5db4d3076fdcad5ac2a922ca098f639d2b762df4f", + "blockNumber": "0x10fa02b", + "from": "0xbe49bd130e126a917ddb5fabf7cdeb6dd9887f40", + "gas": "0x15f90", + "hash": "0xdc81918bf78322ce017c592e81c855f40bb96bd82da9779167de1de109962be6", + "input": "0xd508e62389272d541e4168e5303b5838dcef5f9ac769a057f8dc6aabce7ec1e69b7ce5e6", + "nonce": "0x2ecd", + "to": "0x84654be796dad370032391d5479f8f1fd9ddd14e", + "transactionIndex": "0x1", + "value": "0x0", + "v": "0x25", + "r": "0x78e88f9c69d217c76d92d5472f5812501021342f0054178c0579ee532dc2a218", + "s": "0x484723f0933633a6c213fc201ee3aecbe919579377b11a79acd887950a068e33", + "gasPrice": "0x9839089a0", + "chainId": "0x1" + }, + { + "blockHash": "0x802f1f5a7575098ce5e716cfc6817e24d6944fde8e32eb95dbc178931b11baea", + "blockNumber": "0xc35000", + "from": "0x1fd34033240c95aabf73e186a94b9576c6dab81b", + "gas": "0xbb224", + "gasPrice": "0x0", + "hash": "0x8135b5403ea5528341d661cdadd8eb67983909fc1644b0a133de708b13e10937", + "input": "0x5f53273d00000000000000000000000000000000000000000000000000112cfa39a81d7c00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000004e4128acb080000000000000000000000003765521db364ee269e9540970fd21e5a3e825699000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001dac7be33000000000000000000000000000000000000000000000000000000010005bd8200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006a9850e46518231b23e50467c975fa94026be5d5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000324128acb0800000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000001ade409ce94c21807e0000000000000000000000000000000000000000000000000000000010005bd8200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd855390000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd8553900000000000000000000000000000000000000000000000034a2e5498f6f66f80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4022c0d9f0000000000000000000000000000000000000000000001ade409ce94c21807e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a9850e46518231b23e50467c975fa94026be5d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x1536", + "to": "0x3765521db364ee269e9540970fd21e5a3e825699", + "transactionIndex": "0x2", + "value": "0x0", + "type": "0x1", + "accessList": [ + { + "address": "0x1c86b3cdf2a60ae3a574f7f71d44e2c50bddb87e", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000003", + "0x50f2c0a7453ed72f1987f5c26e34dd531d584edf35a9b2dd71d8cbd0b46cbec2" + ] + }, + { + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "storageKeys": [ + "0xc5192a5360898ecb25d40688e79d4568e38430536a3f38f85b3859328d3cedbc", + "0xcc805915145ea1d9dd6fe22fe624a946d6b02968a5cf3e32ab5376b3fcedd207", + "0x390f6178407c9b8e95802b8659e6df8e34c1e3d4f8d6a49e6132bbcdd937b63a" + ] + }, + { + "address": "0x3765521db364ee269e9540970fd21e5a3e825699", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] + }, + { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "storageKeys": [ + "0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b", + "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3", + "0x1f21a62c4538bacf2aabeca410f0fe63151869f172e03c0e00357ba26a341eff", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xfaa1053f6d4d1d5c438dc7bcb1d301a860f75f57f936878518deaed1f60940d0", + "0x390f6178407c9b8e95802b8659e6df8e34c1e3d4f8d6a49e6132bbcdd937b63a", + "0x441b08c38c1e5e3510dc0c6fdeb4e6a8d60744b906171767ae804339d85b866c" + ] + }, + { + "address": "0x6a9850e46518231b23e50467c975fa94026be5d5", + "storageKeys": [ + "0x918cfc45073e7a8befeda107cec8f3ce514f4a406e227c253b570e1d6485d524", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x0000000000000000000000000000000000000000000000000000000000000001" + ] + }, + { + "address": "0x57ab1ec28d129707052df4df418d58a2d46d5f51", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000002" + ] + }, + { + "address": "0x05a9cbe762b36632b3594da4f082340e0e5343e8", + "storageKeys": [ + "0xfaa1053f6d4d1d5c438dc7bcb1d301a860f75f57f936878518deaed1f60940d0", + "0xc5192a5360898ecb25d40688e79d4568e38430536a3f38f85b3859328d3cedbc", + "0x0000000000000000000000000000000000000000000000000000000000000002" + ] + }, + { + "address": "0x613c773c7a1d85d2f1dcc051b0573d33470762eb", + "storageKeys": [ + "0x0563a8a19823933e751ef690567f0351d13ee18500841743a77290b3deeac37d", + "0x41feecc8dc55520132a464384eb4cad04fca8408899b069cf80a59042ac84c7a" + ] + }, + { + "address": "0xc757acba3c0506218b3022266a9dc7f3612d85f5", + "storageKeys": [ + "0xad77bf801726b2c83e9e3fa10f319bf2df99397a561126e8c3df0f7596519f75", + "0xf0afdce5671e49e66c5829c89ac80a06875a30b8a123df04dc6cc02b9c7c845c" + ] + }, + { + "address": "0xf1f85b2c54a2bd284b1cf4141d64fd171bd85539", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000008", + "0x0000000000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x0000000000000000000000000000000000000000000000000000000000000009", + "0x000000000000000000000000000000000000000000000000000000000000000a", + "0x000000000000000000000000000000000000000000000000000000000000000c" + ] + }, + { + "address": "0x0000000000000000000000000000000000000000", + "storageKeys": [] + }, + { + "address": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xa6172f64e80168333d3bc97ef096a7cb251d24be47156dff7a40f6163a6ab42b" + ] + }, + { + "address": "0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf", + "storageKeys": [] + }, + { + "address": "0x4d8dbd193d89b7b506be5dc9db75b91da00d6a1d", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0xb79e191a25a1c10448c48948add5400e67bdba9b68cb8e4ab5ccc4025afe7bf6", + "0x000000000000000000000000000000000000000000000000000000000000000b", + "0xd8f0dca3c14b74279ad90a75338db7cccdd5b2448369aeb32a94693a1c4cde0d", + "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x0000000000000000000000000000000000000000000000000000000000000002" + ] + }, + { + "address": "0x545973f28950f50fc6c7f52aab4ad214a27c0564", + "storageKeys": [ + "0x97176f14e7115c17104cb26360d789269f7e452d9b8ac6a3b8945c07081b33ac" + ] + } + ], + "chainId": "0x1", + "v": "0x1", + "r": "0xdc6b057ac2591f402a243c3b81e429e750442d0a86f0fc112cf2eaaac26d4b8d", + "s": "0x3e5cace679d3104fae7f63ef0e64e7f4be5cfae64f9e03aebc0e19e5de0f29f8" + }, + { + "type": "0x2", + "blockHash": "0xe380e7cf640a646ef901b6a5db4d3076fdcad5ac2a922ca098f639d2b762df4f", + "blockNumber": "0x10fa02b", + "from": "0xae2fc483527b8ef99eb5d9b44875f005ba1fae13", + "gas": "0x2690c", + "hash": "0xba363483b992ef59342094ab98b8523ed6c055b5788e6726140d2badf27bf6d6", + "input": "0x2b2f1a397217ae1de4a6e543858b0191c9213aadbcc4ed256de6ec", + "nonce": "0xf9b35", + "to": "0x6b75d8af000000e20b7a7ddf000ba900b4009a80", + "transactionIndex": "0x3", + "value": "0x3e168d7", + "v": "0x1", + "r": "0xbcd30031cd0ee1132ec0fd4debd5157269adf0e478e4c4733d846b09f8891dcd", + "s": "0x2afb6af719e9b548c7d543e7698c5a9c15f97d7f126277d7178ff33670d84e08", + "gasPrice": "0x64a2d5a95", + "maxFeePerGas": "0x64a2d5a95", + "maxPriorityFeePerGas": "0x0", + "chainId": "0x1", + "accessList": [ + { + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "storageKeys": [ + "0x12231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8", + "0xf3bba710d3566d618899e2756f47b6b6ab971f4e7a9b49c8676839ce70a3b615" + ] + }, + { + "address": "0x397217ae1de4a6e543858b0191c9213aadbcc4ed", + "storageKeys": [ + "0x000000000000000000000000000000000000000000000000000000000000000c", + "0x0000000000000000000000000000000000000000000000000000000000000008", + "0x0000000000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x0000000000000000000000000000000000000000000000000000000000000009", + "0x000000000000000000000000000000000000000000000000000000000000000a" + ] + }, + { + "address": "0x4ecfc56672c7630b84dac9c1f7407579715de155", + "storageKeys": [ + "0x000000000000000000000000000000000000000000000000000000000000000f", + "0x38ed69781a961bb9622064044b9913b1581bddd02ed6468e0e8c3899ae4ff6ce", + "0x29cb8bd4e192d16f51155329ce8b0f5eb88a1d9e4d3b93ce07efbac9e1c4d175", + "0xa34640eb1c607d836ceb4af07c59befcec4cdb4943351c3a245f8712063aa3b6", + "0x000000000000000000000000000000000000000000000000000000000000000a", + "0x0000000000000000000000000000000000000000000000000000000000000008", + "0x0e0b1ffc883156bcc50271d13adbf2142a3da019b453b028078482a0967df23b", + "0xdc59cdc7b4ec63ea402af3d39d169ec1338c1dd00754c63deca3620ef11ce970", + "0x4eb8e6d369a44c627e68958caefca5b050389afd4410af55103da22160f32e6f", + "0xe9c8ce3daf53241f9a1be37866116a52a57048d3c7f27faf9b4e8c6e2e50cf81", + "0x489f94fa9c8ead25fac83530419e4f3ae96ec772b8179124ec3bf465ad8ddb2e" + ] + } + ] + }, + { + "blockHash": "0x421e594f79995d1aba3c62c80c678a1f6d4d70a6c49c9d721a5ad1ef802f79b3", + "blockNumber": "0x10fd2c3", + "from": "0x979db18107552faa36a52480a1dbb65ed3f51d70", + "gas": "0xefb7a", + "gasPrice": "0xa00a0c2f8", + "maxPriorityFeePerGas": "0x19fa53ad", + "maxFeePerGas": "0xc87eaa4da", + "hash": "0xa3b805acacb25da412a44bd9612a73464292fc684a400ab54f0a9626f7d9c3f2", + "input": "0x608060405260405162000eda38038062000eda83398101604081905262000026916200049d565b828162000036828260006200004d565b50620000449050826200008a565b505050620005d0565b6200005883620000e5565b600082511180620000665750805b1562000085576200008383836200012760201b620001791760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000b562000156565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000e2816200018f565b50565b620000f08162000244565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200014f838360405180606001604052806027815260200162000eb360279139620002f8565b9392505050565b60006200018060008051602062000e9383398151915260001b6200037760201b620001a51760201c565b546001600160a01b0316919050565b6001600160a01b038116620001fa5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b806200022360008051602062000e9383398151915260001b6200037760201b620001a51760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6200025a816200037a60201b620001a81760201c565b620002be5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001f1565b80620002237f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200037760201b620001a51760201c565b6060600080856001600160a01b0316856040516200031791906200057d565b600060405180830381855af49150503d806000811462000354576040519150601f19603f3d011682016040523d82523d6000602084013e62000359565b606091505b5090925090506200036d8683838762000389565b9695505050505050565b90565b6001600160a01b03163b151590565b60608315620003fa578251620003f2576001600160a01b0385163b620003f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001f1565b508162000406565b6200040683836200040e565b949350505050565b8151156200041f5781518083602001fd5b8060405162461bcd60e51b8152600401620001f191906200059b565b80516001600160a01b03811681146200045357600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200048b57818101518382015260200162000471565b83811115620000835750506000910152565b600080600060608486031215620004b357600080fd5b620004be846200043b565b9250620004ce602085016200043b565b60408501519092506001600160401b0380821115620004ec57600080fd5b818601915086601f8301126200050157600080fd5b81518181111562000516576200051662000458565b604051601f8201601f19908116603f0116810190838211818310171562000541576200054162000458565b816040528281528960208487010111156200055b57600080fd5b6200056e8360208301602088016200046e565b80955050505050509250925092565b60008251620005918184602087016200046e565b9190910192915050565b6020815260008251806020840152620005bc8160408501602087016200046e565b601f01601f19169190910160400192915050565b6108b380620005e06000396000f3fe60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65640000000000000000000000007e22fcb742572515d1c3fef972ec066c995820ef000000000000000000000000d89f6892a2b58d50e0e8f51a961b12a25ce3f7570000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000020457405d050000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000064c7eb930000000000000000000000000000000000000000000000000000000064d2bde300000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000004580900be782a567ad407cc8fcde24dbda2a1aae000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000165a0bc00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000009795118749000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000023a8f4b6a00000000000000000000000000000000000000000000000000000000", + "nonce": "0x3", + "to": null, + "transactionIndex": "0x4", + "value": "0x0", + "type": "0x2", + "accessList": [], + "chainId": "0x1", + "v": "0x0", + "r": "0x6fd00841d705c002a846de1b56d0c36941cd2897a7bb19419d427a252bc4fff4", + "s": "0x5be5ed4725f8b6047b5309da5f47d1e98fa2c79e5c0841595291fae7167de108" + } +] diff --git a/beacon_chain/libnimbus_lc/test_libnimbus_lc.c b/beacon_chain/libnimbus_lc/test_libnimbus_lc.c index 74e8f5eda..ac46b38bd 100644 --- a/beacon_chain/libnimbus_lc/test_libnimbus_lc.c +++ b/beacon_chain/libnimbus_lc/test_libnimbus_lc.c @@ -7,6 +7,7 @@ * at your option. This file may not be copied, modified, or distributed except according to those terms. */ +#include #include #include #include @@ -96,6 +97,15 @@ static void printHexString(const void *bytes, int numBytes) } } +static void printHexStringReversed(const void *bytes, int numBytes) +{ + const uint8_t *bytes_ = bytes; + printf("0x"); + for (int i = numBytes - 1; i >= 0; i--) { + printf("%02x", bytes_[i]); + } +} + static void printGweiString(const ETHUInt256 *wei) { ETHUInt256 value; @@ -380,5 +390,125 @@ int main(void) ETHExecutionBlockHeaderDestroy(executionBlockHeader); + ETHRoot sampleTransactionsRoot = {{ + 0x4e, 0x90, 0xdc, 0x06, 0xca, 0xd6, 0xa7, 0xc0, + 0x57, 0xd2, 0xd7, 0x7f, 0x8f, 0x77, 0xd1, 0x45, + 0xb4, 0x6f, 0xf3, 0xad, 0x9c, 0xa7, 0xe1, 0xef, + 0x57, 0x11, 0x5f, 0xa8, 0xbf, 0xad, 0xfe, 0xe1, + }}; + void *sampleTransactionsJson = readEntireFile( + __DIR__ "/test_files/transactions.json", /* numBytes: */ NULL); + ETHTransactions *transactions = + ETHTransactionsCreateFromJson(&sampleTransactionsRoot, sampleTransactionsJson); + check(transactions); + free(sampleTransactionsJson); + + int numTransactions = ETHTransactionsGetCount(transactions); + printf("\nSample transactions:\n"); + for (int transactionIndex = 0; transactionIndex < numTransactions; transactionIndex++) { + const ETHTransaction *transaction = ETHTransactionsGet(transactions, transactionIndex); + + const ETHRoot *transactionHash = ETHTransactionGetHash(transaction); + printf("- "); + printHexString(transactionHash, sizeof *transactionHash); + printf("\n"); + + const ETHUInt256 *transactionChainId = ETHTransactionGetChainId(transaction); + printf(" - chain_id: "); + printHexStringReversed(transactionChainId, sizeof *transactionChainId); + printf("\n"); + + const ETHExecutionAddress *transactionFrom = ETHTransactionGetFrom(transaction); + printf(" - from: "); + printHexString(transactionFrom, sizeof *transactionFrom); + printf("\n"); + + const uint64_t *transactionNonce = ETHTransactionGetNonce(transaction); + printf(" - nonce: %" PRIu64 "\n", *transactionNonce); + + const uint64_t *transactionMaxPriorityFeePerGas = + ETHTransactionGetMaxPriorityFeePerGas(transaction); + printf(" - max_priority_fee_per_gas: %" PRIu64 "\n", *transactionMaxPriorityFeePerGas); + + const uint64_t *transactionMaxFeePerGas = ETHTransactionGetMaxFeePerGas(transaction); + printf(" - max_fee_per_gas: %" PRIu64 "\n", *transactionMaxFeePerGas); + + const uint64_t *transactionGas = ETHTransactionGetGas(transaction); + printf(" - gas: %" PRIu64 "\n", *transactionGas); + + bool transactionIsCreatingContract = ETHTransactionIsCreatingContract(transaction); + const ETHExecutionAddress *transactionTo = ETHTransactionGetTo(transaction); + if (transactionIsCreatingContract) { + printf(" - contract_address: "); + } else { + printf(" - to: "); + } + printHexString(transactionTo, sizeof *transactionTo); + printf("\n"); + + const ETHUInt256 *transactionValue = ETHTransactionGetValue(transaction); + printf(" - value: "); + printGweiString(transactionValue); + printf(" Gwei\n"); + + int numTransactionInputBytes; + const void *transactionInputBytes = + ETHTransactionGetInputBytes(transaction, &numTransactionInputBytes); + printf(" - input: "); + printHexString(transactionInputBytes, numTransactionInputBytes); + printf("\n"); + + const ETHAccessList *transactionAccessList = ETHTransactionGetAccessList(transaction); + printf(" - access_list:\n"); + int numAccessTuples = ETHAccessListGetCount(transactionAccessList); + for (int accessTupleIndex = 0; accessTupleIndex < numAccessTuples; accessTupleIndex++) { + const ETHAccessTuple *accessTuple = + ETHAccessListGet(transactionAccessList, accessTupleIndex); + + const ETHExecutionAddress *accessTupleAddress = ETHAccessTupleGetAddress(accessTuple); + printf(" - "); + printHexString(accessTupleAddress, sizeof *accessTupleAddress); + printf("\n"); + + int numStorageKeys = ETHAccessTupleGetNumStorageKeys(accessTuple); + for (int storageKeyIndex = 0; storageKeyIndex < numStorageKeys; storageKeyIndex++) { + const ETHRoot *storageKey = + ETHAccessTupleGetStorageKey(accessTuple, storageKeyIndex); + printf(" - "); + printHexString(storageKey, sizeof *storageKey); + printf("\n"); + } + } + + const uint64_t *transactionMaxFeePerBlobGas = + ETHTransactionGetMaxFeePerBlobGas(transaction); + printf(" - max_fee_per_blob_gas: %" PRIu64 "\n", *transactionMaxFeePerBlobGas); + + printf(" - blob_versioned_hashes:\n"); + int numBlobVersionedHashes = ETHTransactionGetNumBlobVersionedHashes(transaction); + for (int hashIndex = 0; hashIndex < numBlobVersionedHashes; hashIndex++) { + const ETHRoot *blobVersionedHash = + ETHTransactionGetBlobVersionedHash(transaction, hashIndex); + printf(" - "); + printHexString(blobVersionedHash, sizeof *blobVersionedHash); + printf("\n"); + } + + int numTransactionSignatureBytes; + const void *transactionSignatureBytes = + ETHTransactionGetSignatureBytes(transaction, &numTransactionSignatureBytes); + printf(" - signature: "); + printHexString(transactionSignatureBytes, numTransactionSignatureBytes); + printf("\n"); + + int numTransactionBytes; + const void *transactionBytes = ETHTransactionGetBytes(transaction, &numTransactionBytes); + printf(" - bytes: "); + printHexString(transactionBytes, numTransactionBytes); + printf("\n"); + } + + ETHTransactionsDestroy(transactions); + return 0; } diff --git a/beacon_chain/spec/helpers.nim b/beacon_chain/spec/helpers.nim index 78439f307..a5d99fcfd 100644 --- a/beacon_chain/spec/helpers.nim +++ b/beacon_chain/spec/helpers.nim @@ -32,6 +32,7 @@ func toEther*(gwei: Gwei): Ether = type ExecutionHash256* = eth_types.Hash256 + ExecutionTransaction* = eth_types.Transaction ExecutionWithdrawal = eth_types.Withdrawal ExecutionBlockHeader* = eth_types.BlockHeader