From e8d146ab7305e6f5e7f46d659d2ca0e956d5824b Mon Sep 17 00:00:00 2001 From: Roy Crihfield Date: Wed, 17 Apr 2024 12:23:26 +0800 Subject: [PATCH] update code --- pkg/eth/api.go | 186 ++++++++++++++++++++---------- pkg/eth/api_test/api_test.go | 17 ++- pkg/eth/backend.go | 57 +++++---- pkg/eth/backend_utils.go | 140 +++++++++++++++------- pkg/eth/node_types.go | 5 +- pkg/eth/state_test/helper_test.go | 60 +++++++++- pkg/eth/state_test/state_test.go | 98 ++++++++-------- pkg/eth/test_helpers/test_data.go | 47 ++++---- pkg/eth/types.go | 42 ++++--- pkg/graphql/graphql.go | 2 +- 10 files changed, 421 insertions(+), 233 deletions(-) diff --git a/pkg/eth/api.go b/pkg/eth/api.go index ef4da70c..d21e364a 100644 --- a/pkg/eth/api.go +++ b/pkg/eth/api.go @@ -19,19 +19,25 @@ package eth import ( "context" "database/sql" + "encoding/hex" "encoding/json" "errors" "fmt" "io" "math/big" "strconv" + "strings" "time" - "github.com/cerc-io/plugeth-statediff" + ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf" + "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/state" + "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie" + statediff "github.com/cerc-io/plugeth-statediff" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -39,9 +45,9 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" + "github.com/holiman/uint256" "github.com/cerc-io/ipld-eth-server/v5/pkg/log" - ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf" ) const ( @@ -106,6 +112,25 @@ Headers and blocks */ +// decodeHash parses a hex-encoded 32-byte hash. The input may optionally +// be prefixed by 0x and can have a byte length up to 32. +func decodeHash(s string) (h common.Hash, inputLength int, err error) { + if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") { + s = s[2:] + } + if (len(s) & 1) > 0 { + s = "0" + s + } + b, err := hex.DecodeString(s) + if err != nil { + return common.Hash{}, 0, errors.New("hex string invalid") + } + if len(b) > 32 { + return common.Hash{}, len(b), errors.New("hex string too long, want at most 32 bytes") + } + return common.BytesToHash(b), len(b), nil +} + // GetHeaderByNumber returns the requested canonical block header. // * When blockNr is -1 the chain head is returned. // * We cannot support pending block calls since we do not have an active miner @@ -222,8 +247,7 @@ Uncles */ -// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true -// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned. +// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. func (pea *PublicEthAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { block, err := pea.B.BlockByNumber(ctx, blockNr) if block != nil && err == nil { @@ -379,7 +403,7 @@ func (pea *PublicEthAPI) GetBlockTransactionCountByHash(ctx context.Context, blo // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index)) + return newRPCTransactionFromBlockIndex(block, uint64(index), pea.B.ChainConfig()) } if pea.config.ProxyOnError { @@ -396,7 +420,7 @@ func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. func (pea *PublicEthAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index)) + return newRPCTransactionFromBlockIndex(block, uint64(index), pea.B.ChainConfig()) } if pea.config.ProxyOnError { @@ -443,14 +467,14 @@ func (pea *PublicEthAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Contex // GetTransactionByHash returns the transaction for the given hash // eth ipld-eth-server cannot currently handle pending/tx_pool txs func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { - tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash) + _, tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash) if tx != nil && err == nil { header, err := pea.B.HeaderByHash(ctx, blockHash) if err != nil { return nil, err } - return NewRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee), nil + return NewRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, pea.B.ChainConfig()), nil } if pea.config.ProxyOnError { var tx *RPCTransaction @@ -465,7 +489,7 @@ func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.H // GetRawTransactionByHash returns the bytes of the transaction for the given hash. func (pea *PublicEthAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { // Retrieve a finalized transaction, or a pooled otherwise - tx, _, _, _, err := pea.B.GetTransaction(ctx, hash) + _, tx, _, _, _, err := pea.B.GetTransaction(ctx, hash) if tx != nil && err == nil { return tx.MarshalBinary() } @@ -580,7 +604,7 @@ func (pea *PublicEthAPI) GetTransactionReceipt(ctx context.Context, hash common. func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { // TODO: this can be optimized for Postgres - tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash) + _, tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash) if err != nil { return nil, err } @@ -595,7 +619,11 @@ func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash co if err != nil { return nil, err } - err = receipts.DeriveFields(pea.B.Config.ChainConfig, blockHash, blockNumber, block.BaseFee(), block.Transactions()) + var blobGasPrice *big.Int + if excessBlobGas := block.ExcessBlobGas(); excessBlobGas != nil { + blobGasPrice = eip4844.CalcBlobFee(*excessBlobGas) + } + err = receipts.DeriveFields(pea.B.Config.ChainConfig, blockHash, blockNumber, block.Time(), block.BaseFee(), blobGasPrice, block.Transactions()) if err != nil { return nil, err } @@ -793,7 +821,7 @@ func (pea *PublicEthAPI) localGetBalance(ctx context.Context, address common.Add if err != nil { return nil, err } - return (*hexutil.Big)(account.Balance), nil + return (*hexutil.Big)(account.Balance.ToBig()), nil } // GetStorageAt returns the storage from the state at the given address, key and @@ -822,7 +850,7 @@ func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Addres return value[:], nil } if pea.config.ProxyOnError { - log.Warnxf(ctx, "Missing eth_getStorageAt(%s, %s, %s)", address.Hash().String(), key, blockNrOrHash.String()) + log.Warnxf(ctx, "Missing eth_getStorageAt(%s, %s, %s)", address, key, blockNrOrHash.String()) var res hexutil.Bytes if err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash); res != nil && err == nil { return res, nil @@ -868,57 +896,95 @@ func (pea *PublicEthAPI) GetProof(ctx context.Context, address common.Address, s return nil, err } +// proofList implements ethdb.KeyValueWriter and collects the proofs as +// hex-strings for delivery to rpc-caller. +type proofList []string + +func (n *proofList) Put(key []byte, value []byte) error { + *n = append(*n, hexutil.Encode(value)) + return nil +} + +func (n *proofList) Delete(key []byte) error { + panic("not supported") +} + // this continues to use ipfs-ethdb based geth StateDB as it requires trie access func (pea *PublicEthAPI) localGetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { - state, _, err := pea.B.IPLDTrieStateDBAndHeaderByNumberOrHash(ctx, blockNrOrHash) - if state == nil || err != nil { - return nil, err - } - - storageTrie, err := state.StorageTrie(address) - if storageTrie == nil || err != nil { - return nil, err - } - storageHash := types.EmptyRootHash - codeHash := state.GetCodeHash(address) - storageProof := make([]StorageResult, len(storageKeys)) - - // if we have a storageTrie, (which means the account exists), we can update the storagehash - if storageTrie != nil { - storageHash = storageTrie.Hash() - } else { - // no storageTrie means the account does not exist, so the codeHash is the hash of an empty bytearray. - codeHash = crypto.Keccak256Hash(nil) - } - - // create the proof for the storageKeys - for i, key := range storageKeys { - if storageTrie != nil { - proof, storageError := state.GetStorageProof(address, common.HexToHash(key)) - if storageError != nil { - return nil, storageError - } - storageProof[i] = StorageResult{key, (*hexutil.Big)(state.GetState(address, common.HexToHash(key)).Big()), toHexSlice(proof)} - } else { - storageProof[i] = StorageResult{key, &hexutil.Big{}, []string{}} + var ( + keys = make([]common.Hash, len(storageKeys)) + keyLengths = make([]int, len(storageKeys)) + storageProof = make([]StorageResult, len(storageKeys)) + ) + // Deserialize all keys. This prevents state access on invalid input. + for i, hexKey := range storageKeys { + var err error + keys[i], keyLengths[i], err = decodeHash(hexKey) + if err != nil { + return nil, err } } - - // create the accountProof - accountProof, proofErr := state.GetProof(address) - if proofErr != nil { - return nil, proofErr + statedb, header, err := pea.B.IPLDTrieStateDBAndHeaderByNumberOrHash(ctx, blockNrOrHash) + // statedb, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + if statedb == nil || err != nil { + return nil, err } + codeHash := statedb.GetCodeHash(address) + storageRoot := statedb.GetStorageRoot(address) + if len(keys) > 0 { + var storageTrie state.Trie + if storageRoot != types.EmptyRootHash && storageRoot != (common.Hash{}) { + id := trie.StorageTrieID(header.Root, crypto.Keccak256Hash(address.Bytes()), storageRoot) + st, err := trie.NewStateTrie(id, statedb.Database().TrieDB()) + if err != nil { + return nil, err + } + storageTrie = st + } + // Create the proofs for the storageKeys. + for i, key := range keys { + // Output key encoding is a bit special: if the input was a 32-byte hash, it is + // returned as such. Otherwise, we apply the QUANTITY encoding mandated by the + // JSON-RPC spec for getProof. This behavior exists to preserve backwards + // compatibility with older client versions. + var outputKey string + if keyLengths[i] != 32 { + outputKey = hexutil.EncodeBig(key.Big()) + } else { + outputKey = hexutil.Encode(key[:]) + } + if storageTrie == nil { + storageProof[i] = StorageResult{outputKey, &hexutil.Big{}, []string{}} + continue + } + var proof proofList + if err := storageTrie.Prove(crypto.Keccak256(key.Bytes()), &proof); err != nil { + return nil, err + } + value := (*hexutil.Big)(statedb.GetState(address, key).Big()) + storageProof[i] = StorageResult{outputKey, value, proof} + } + } + // Create the accountProof. + tr, err := trie.NewStateTrie(trie.StateTrieID(header.Root), statedb.Database().TrieDB()) + if err != nil { + return nil, err + } + var accountProof proofList + if err := tr.Prove(crypto.Keccak256(address.Bytes()), &accountProof); err != nil { + return nil, err + } + balance := statedb.GetBalance(address).ToBig() return &AccountResult{ Address: address, - AccountProof: toHexSlice(accountProof), - Balance: (*hexutil.Big)(state.GetBalance(address)), + AccountProof: accountProof, + Balance: (*hexutil.Big)(balance), CodeHash: codeHash, - Nonce: hexutil.Uint64(state.GetNonce(address)), - StorageHash: storageHash, + Nonce: hexutil.Uint64(statedb.GetNonce(address)), + StorageHash: storageRoot, StorageProof: storageProof, - }, state.Error() + }, statedb.Error() } // GetSlice returns a slice of state or storage nodes from a provided root to a provided path and past it to a certain depth @@ -989,7 +1055,7 @@ func (diff *StateOverride) Apply(state *ipld_direct_state.StateDB) error { } // Override account balance. if account.Balance != nil { - state.SetBalance(addr, (*big.Int)(*account.Balance)) + state.SetBalance(addr, uint256.MustFromBig((*big.Int)(*account.Balance))) } if account.State != nil && account.StateDiff != nil { return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) @@ -1175,11 +1241,7 @@ func (pea *PublicEthAPI) writeStateDiffFor(blockHash common.Hash) { // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field func (pea *PublicEthAPI) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields, err := RPCMarshalBlock(b, inclTx, fullTx) - if err != nil { - log.Errorf("error RPC marshalling block with hash %s: %s", b.Hash().String(), err) - return nil, err - } + fields := RPCMarshalBlock(b, inclTx, fullTx, pea.B.ChainConfig()) if inclTx { td, err := pea.B.GetTd(b.Hash()) if err != nil { @@ -1188,12 +1250,12 @@ func (pea *PublicEthAPI) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx boo } fields["totalDifficulty"] = (*hexutil.Big)(td) } - return fields, err + return fields, nil } // rpcMarshalBlockWithUncleHashes uses the generalized output filler, then adds the total difficulty field func (pea *PublicEthAPI) rpcMarshalBlockWithUncleHashes(b *types.Block, uncleHashes []common.Hash, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields, err := RPCMarshalBlockWithUncleHashes(b, uncleHashes, inclTx, fullTx) + fields, err := RPCMarshalBlockWithUncleHashes(b, uncleHashes, inclTx, fullTx, pea.B.ChainConfig()) if err != nil { return nil, err } diff --git a/pkg/eth/api_test/api_test.go b/pkg/eth/api_test/api_test.go index 2899e0bb..8b47b9ba 100644 --- a/pkg/eth/api_test/api_test.go +++ b/pkg/eth/api_test/api_test.go @@ -19,7 +19,6 @@ package eth_api_test import ( "context" "math/big" - "strconv" "github.com/cerc-io/plugeth-statediff/indexer/interfaces" "github.com/cerc-io/plugeth-statediff/indexer/ipld" @@ -44,8 +43,8 @@ import ( var ( randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f") randomHash = crypto.Keccak256Hash(randomAddr.Bytes()) - number = rpc.BlockNumber(test_helpers.BlockNumber.Int64()) - londonBlockNum = rpc.BlockNumber(test_helpers.LondonBlockNum.Int64()) + number = rpc.BlockNumber(test_helpers.BlockNumber1) + londonBlockNum = rpc.BlockNumber(test_helpers.LondonBlockNum) wrongNumber = number + 1 blockHash = test_helpers.MockBlock.Header().Hash() baseFee = test_helpers.MockLondonBlock.BaseFee() @@ -293,9 +292,7 @@ var _ = Describe("API", func() { Describe("eth_blockNumber", func() { It("Retrieves the head block number", func() { bn := api.BlockNumber() - ubn := (uint64)(bn) - subn := strconv.FormatUint(ubn, 10) - Expect(subn).To(Equal(test_helpers.LondonBlockNum.String())) + Expect(bn).To(Equal(hexutil.Uint64(test_helpers.LondonBlockNum))) }) }) @@ -1104,20 +1101,20 @@ var _ = Describe("API", func() { It("Retrieves the eth balance for the provided account address at the block with the provided number", func() { bal, err := api.GetBalance(ctx, test_helpers.AccountAddresss, rpc.BlockNumberOrHashWithNumber(number)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(test_helpers.AccountBalance))) + Expect(bal).To(Equal((*hexutil.Big)(test_helpers.AccountBalance.ToBig()))) bal, err = api.GetBalance(ctx, test_helpers.ContractAddress, rpc.BlockNumberOrHashWithNumber(number)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal.ToInt().Cmp(common.Big0)).To(Equal(0)) }) It("Retrieves the eth balance for the provided account address at the block with the provided hash", func() { bal, err := api.GetBalance(ctx, test_helpers.AccountAddresss, rpc.BlockNumberOrHashWithHash(blockHash, true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(test_helpers.AccountBalance))) + Expect(bal).To(Equal((*hexutil.Big)(test_helpers.AccountBalance.ToBig()))) bal, err = api.GetBalance(ctx, test_helpers.ContractAddress, rpc.BlockNumberOrHashWithHash(blockHash, true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal.ToInt().Cmp(common.Big0)).To(Equal(0)) }) It("Retrieves the eth balance for the non-existing account address at the block with the provided hash", func() { bal, err := api.GetBalance(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true)) diff --git a/pkg/eth/backend.go b/pkg/eth/backend.go index ece9c820..ba9d91e1 100644 --- a/pkg/eth/backend.go +++ b/pkg/eth/backend.go @@ -25,6 +25,12 @@ import ( "math/big" "time" + validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg" + ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5/postgres/v0" + ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf" + ipld_sql "github.com/cerc-io/ipld-eth-statedb/sql" + ipld_trie_state "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/state" + ipld_trie "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie" "github.com/cerc-io/plugeth-statediff/indexer/ipld" "github.com/cerc-io/plugeth-statediff/utils" "github.com/ethereum/go-ethereum/common" @@ -42,15 +48,11 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" + "github.com/holiman/uint256" "github.com/jmoiron/sqlx" - validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg" - ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5/postgres/v0" "github.com/cerc-io/ipld-eth-server/v5/pkg/log" "github.com/cerc-io/ipld-eth-server/v5/pkg/shared" - ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf" - ipld_sql "github.com/cerc-io/ipld-eth-statedb/sql" - ipld_trie_state "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/state" ) var ( @@ -80,7 +82,7 @@ type Backend struct { // ethereum interfaces EthDB ethdb.Database // We use this state.Database for eth_call and any place we don't need trie access - IpldDirectStateDatabase ipld_direct_state.StateDatabase + IpldDirectStateDatabase ipld_direct_state.Database // We use this where state must be accessed by trie IpldTrieStateDatabase ipld_trie_state.Database @@ -115,7 +117,7 @@ func NewEthBackend(db *sqlx.DB, c *Config) (*Backend, error) { DB: db, Retriever: r, EthDB: ethDB, - IpldDirectStateDatabase: ipld_direct_state.NewStateDatabase(driver), + IpldDirectStateDatabase: ipld_direct_state.NewDatabase(driver), IpldTrieStateDatabase: ipld_trie_state.NewDatabase(ethDB), Config: c, }, nil @@ -494,7 +496,7 @@ func (b *Backend) GetReceiptsByBlockHashAndNumber(tx *sqlx.Tx, hash common.Hash, // GetTransaction retrieves a tx by hash // It also returns the blockhash, blocknumber, and tx index associated with the transaction -func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { +func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) { type txRes struct { Data []byte `db:"data"` HeaderID string `db:"header_id"` @@ -503,22 +505,22 @@ func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (*type } var res = make([]txRes, 0) if err := b.DB.Select(&res, RetrieveRPCTransaction, txHash.String()); err != nil { - return nil, common.Hash{}, 0, 0, err + return false, nil, common.Hash{}, 0, 0, err } if len(res) == 0 { - return nil, common.Hash{}, 0, 0, errTxHashNotFound + return false, nil, common.Hash{}, 0, 0, errTxHashNotFound } else if len(res) > 1 { // a transaction can be part of a only one canonical block - return nil, common.Hash{}, 0, 0, errTxHashInMultipleBlocks + return false, nil, common.Hash{}, 0, 0, errTxHashInMultipleBlocks } var transaction types.Transaction if err := transaction.UnmarshalBinary(res[0].Data); err != nil { - return nil, common.Hash{}, 0, 0, err + return false, nil, common.Hash{}, 0, 0, err } - return &transaction, common.HexToHash(res[0].HeaderID), res[0].BlockNumber, res[0].Index, nil + return true, &transaction, common.HexToHash(res[0].HeaderID), res[0].BlockNumber, res[0].Index, nil } // GetReceipts retrieves receipts for provided block hash @@ -778,7 +780,7 @@ func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address, } return &types.StateAccount{ Nonce: acctRecord.Nonce, - Balance: balance, + Balance: uint256.MustFromBig(balance), Root: common.HexToHash(acctRecord.Root), CodeHash: acctRecord.CodeHash, }, nil @@ -917,7 +919,10 @@ func (b *Backend) GetSlice(path string, depth int, root common.Hash, storage boo var t ipld_trie_state.Trie var err error if storage { - t, err = b.IpldTrieStateDatabase.OpenStorageTrie(common.Hash{}, common.Hash{}, root) + // Note 1: once Verkle tries are used, this will be the same as state trie + // Note 2: a dummy hash is passed as owner here, and is only used to signal to ipld-eth-statedb + // that a storage, not state trie is being accessed + t, err = b.IpldTrieStateDatabase.OpenStorageTrie(common.Hash{}, common.Hash{1}, root, nil) } else { t, err = b.IpldTrieStateDatabase.OpenTrie(root) } @@ -929,21 +934,24 @@ func (b *Backend) GetSlice(path string, depth int, root common.Hash, storage boo // Convert the head hex path to a decoded byte path headPath := common.FromHex(path) + // Convert the Trie object to its concrete type for raw node access + stateTrie := t.(*ipld_trie.StateTrie) + // Get Stem nodes - err = b.getSliceStem(headPath, t, response, &metaData, storage) + err = b.getSliceStem(headPath, stateTrie, response, &metaData, storage) if err != nil { return nil, err } // Get Head node - err = b.getSliceHead(headPath, t, response, &metaData, storage) + err = b.getSliceHead(headPath, stateTrie, response, &metaData, storage) if err != nil { return nil, err } if depth > 0 { // Get Slice nodes - err = b.getSliceTrie(headPath, t, response, &metaData, depth, storage) + err = b.getSliceTrie(headPath, stateTrie, response, &metaData, depth, storage) if err != nil { return nil, err } @@ -954,7 +962,7 @@ func (b *Backend) GetSlice(path string, depth int, root common.Hash, storage boo return response, nil } -func (b *Backend) getSliceStem(headPath []byte, t ipld_trie_state.Trie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error { +func (b *Backend) getSliceStem(headPath []byte, t *ipld_trie.StateTrie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error { leavesFetchTime := int64(0) totalStemStartTime := makeTimestamp() @@ -963,7 +971,7 @@ func (b *Backend) getSliceStem(headPath []byte, t ipld_trie_state.Trie, response // nodePath := make([]byte, len(headPath[:i])) nodePath := headPath[:i] - rawNode, _, err := t.TryGetNode(utils.HexToCompact(nodePath)) + rawNode, _, err := t.GetNode(utils.HexToCompact(nodePath)) if err != nil { return err } @@ -1002,10 +1010,10 @@ func (b *Backend) getSliceStem(headPath []byte, t ipld_trie_state.Trie, response return nil } -func (b *Backend) getSliceHead(headPath []byte, t ipld_trie_state.Trie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error { +func (b *Backend) getSliceHead(headPath []byte, t *ipld_trie.StateTrie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error { totalHeadStartTime := makeTimestamp() - rawNode, _, err := t.TryGetNode(utils.HexToCompact(headPath)) + rawNode, _, err := t.GetNode(utils.HexToCompact(headPath)) if err != nil { return err } @@ -1043,7 +1051,10 @@ func (b *Backend) getSliceHead(headPath []byte, t ipld_trie_state.Trie, response } func (b *Backend) getSliceTrie(headPath []byte, t ipld_trie_state.Trie, response *GetSliceResponse, metaData *metaDataFields, depth int, storage bool) error { - it, timeTaken := getIteratorAtPath(t, headPath) + it, timeTaken, err := getIteratorAtPath(t, headPath) + if err != nil { + return nil + } metaData.trieLoadingTime += timeTaken leavesFetchTime := int64(0) diff --git a/pkg/eth/backend_utils.go b/pkg/eth/backend_utils.go index 1776ddbb..f467c27e 100644 --- a/pkg/eth/backend_utils.go +++ b/pkg/eth/backend_utils.go @@ -28,9 +28,9 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" @@ -41,10 +41,11 @@ import ( var nullHashBytes = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000") var emptyCodeHash = crypto.Keccak256([]byte{}) +// These marshalling functions are from internal/ethapi so we have to make our own versions here: + // RPCMarshalHeader converts the given header to the RPC output. -// This function is eth/internal so we have to make our own version here... func RPCMarshalHeader(head *types.Header) map[string]interface{} { - headerMap := map[string]interface{}{ + result := map[string]interface{}{ "number": (*hexutil.Big)(head.Number), "hash": head.Hash(), "parentHash": head.ParentHash, @@ -56,43 +57,50 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { "miner": head.Coinbase, "difficulty": (*hexutil.Big)(head.Difficulty), "extraData": hexutil.Bytes(head.Extra), - "size": hexutil.Uint64(head.Size()), "gasLimit": hexutil.Uint64(head.GasLimit), "gasUsed": hexutil.Uint64(head.GasUsed), "timestamp": hexutil.Uint64(head.Time), "transactionsRoot": head.TxHash, "receiptsRoot": head.ReceiptHash, } - if head.BaseFee != nil { - headerMap["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) + result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) } - return headerMap + if head.WithdrawalsHash != nil { + result["withdrawalsRoot"] = head.WithdrawalsHash + } + if head.BlobGasUsed != nil { + result["blobGasUsed"] = hexutil.Uint64(*head.BlobGasUsed) + } + if head.ExcessBlobGas != nil { + result["excessBlobGas"] = hexutil.Uint64(*head.ExcessBlobGas) + } + if head.ParentBeaconRoot != nil { + result["parentBeaconBlockRoot"] = head.ParentBeaconRoot + } + return result } // RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. -func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { +func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) map[string]interface{} { fields := RPCMarshalHeader(block.Header()) fields["size"] = hexutil.Uint64(block.Size()) if inclTx { - formatTx := func(tx *types.Transaction) (interface{}, error) { - return tx.Hash(), nil + formatTx := func(idx int, tx *types.Transaction) interface{} { + return tx.Hash() } if fullTx { - formatTx = func(tx *types.Transaction) (interface{}, error) { - return NewRPCTransactionFromBlockHash(block, tx.Hash()), nil + formatTx = func(idx int, tx *types.Transaction) interface{} { + return newRPCTransactionFromBlockIndex(block, uint64(idx), config) } } txs := block.Transactions() transactions := make([]interface{}, len(txs)) - var err error for i, tx := range txs { - if transactions[i], err = formatTx(tx); err != nil { - return nil, err - } + transactions[i] = formatTx(i, tx) } fields["transactions"] = transactions } @@ -102,12 +110,14 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]i uncleHashes[i] = uncle.Hash() } fields["uncles"] = uncleHashes - - return fields, nil + if block.Header().WithdrawalsHash != nil { + fields["withdrawals"] = block.Withdrawals() + } + return fields } // RPCMarshalBlockWithUncleHashes marshals the block with the provided uncle hashes -func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Hash, inclTx bool, fullTx bool) (map[string]interface{}, error) { +func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Hash, inclTx bool, fullTx bool, config *params.ChainConfig) (map[string]interface{}, error) { fields := RPCMarshalHeader(block.Header()) fields["size"] = hexutil.Uint64(block.Size()) @@ -117,7 +127,7 @@ func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Has } if fullTx { formatTx = func(tx *types.Transaction) (interface{}, error) { - return NewRPCTransactionFromBlockHash(block, tx.Hash()), nil + return NewRPCTransactionFromBlockHash(block, tx.Hash(), config), nil } } txs := block.Transactions() @@ -135,11 +145,11 @@ func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Has return fields, nil } -// NewRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. -func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { +// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. +func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *params.ChainConfig) *RPCTransaction { for idx, tx := range b.Transactions() { if tx.Hash() == hash { - return newRPCTransactionFromBlockIndex(b, uint64(idx)) + return newRPCTransactionFromBlockIndex(b, uint64(idx), config) } } return nil @@ -158,11 +168,12 @@ func SignerForTx(tx *types.Transaction) types.Signer { // NewRPCTransaction returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). -func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *RPCTransaction { - signer := SignerForTx(tx) +func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { + signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) from, _ := types.Sender(signer, tx) v, r, s := tx.RawSignatureValues() result := &RPCTransaction{ + Type: hexutil.Uint64(tx.Type()), From: from, Gas: hexutil.Uint64(tx.Gas()), GasPrice: (*hexutil.Big)(tx.GasPrice()), @@ -171,7 +182,6 @@ func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber Nonce: hexutil.Uint64(tx.Nonce()), To: tx.To(), Value: (*hexutil.Big)(tx.Value()), - Type: hexutil.Uint64(tx.Type()), V: (*hexutil.Big)(v), R: (*hexutil.Big)(r), S: (*hexutil.Big)(s), @@ -181,34 +191,69 @@ func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) result.TransactionIndex = (*hexutil.Uint64)(&index) } + switch tx.Type() { case types.LegacyTxType: // if a legacy transaction has an EIP-155 chain id, include it explicitly if id := tx.ChainId(); id.Sign() != 0 { result.ChainID = (*hexutil.Big)(id) } + case types.AccessListTxType: al := tx.AccessList() + yparity := hexutil.Uint64(v.Sign()) result.Accesses = &al result.ChainID = (*hexutil.Big)(tx.ChainId()) + result.YParity = &yparity + case types.DynamicFeeTxType: al := tx.AccessList() + yparity := hexutil.Uint64(v.Sign()) result.Accesses = &al result.ChainID = (*hexutil.Big)(tx.ChainId()) + result.YParity = &yparity result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap()) result.GasTipCap = (*hexutil.Big)(tx.GasTipCap()) // if the transaction has been mined, compute the effective gas price if baseFee != nil && blockHash != (common.Hash{}) { - // price = min(tip, gasFeeCap - baseFee) + baseFee - price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap()) - result.GasPrice = (*hexutil.Big)(price) + // price = min(gasTipCap + baseFee, gasFeeCap) + result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee)) } else { result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) } + + case types.BlobTxType: + al := tx.AccessList() + yparity := hexutil.Uint64(v.Sign()) + result.Accesses = &al + result.ChainID = (*hexutil.Big)(tx.ChainId()) + result.YParity = &yparity + result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap()) + result.GasTipCap = (*hexutil.Big)(tx.GasTipCap()) + // if the transaction has been mined, compute the effective gas price + if baseFee != nil && blockHash != (common.Hash{}) { + result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee)) + } else { + result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) + } + result.MaxFeePerBlobGas = (*hexutil.Big)(tx.BlobGasFeeCap()) + result.BlobVersionedHashes = tx.BlobHashes() } return result } +// effectiveGasPrice computes the transaction gas fee, based on the given basefee value. +// +// price = min(gasTipCap + baseFee, gasFeeCap) +func effectiveGasPrice(tx *types.Transaction, baseFee *big.Int) *big.Int { + fee := tx.GasTipCap() + fee = fee.Add(fee, baseFee) + if tx.GasFeeCapIntCmp(fee) < 0 { + return tx.GasFeeCap() + } + return fee +} + type rpcBlock struct { Hash common.Hash `json:"hash"` Transactions []rpcTransaction `json:"transactions"` @@ -270,6 +315,15 @@ func getBlockAndUncleHashes(cli *rpc.Client, ctx context.Context, method string, return types.NewBlockWithHeader(head).WithBody(txs, nil), body.UncleHashes, nil } +// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig) *RPCTransaction { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config) +} + // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { txs := b.Transactions() @@ -280,15 +334,6 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.By return blob } -// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction { - txs := b.Transactions() - if index >= uint64(len(txs)) { - return nil - } - return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee()) -} - func toFilterArg(q ethereum.FilterQuery) (interface{}, error) { arg := map[string]interface{}{ "address": q.Addresses, @@ -317,21 +362,28 @@ func toBlockNumArg(number *big.Int) string { return hexutil.EncodeBig(number) } -func getIteratorAtPath(t state.Trie, startKey []byte) (trie.NodeIterator, int64) { +func getIteratorAtPath(t state.Trie, startKey []byte) (trie.NodeIterator, int64, error) { startTime := makeTimestamp() var it trie.NodeIterator + var err error if len(startKey)%2 != 0 { // Zero-pad for odd-length keys, required by HexToKeyBytes() startKey = append(startKey, 0) - it = t.NodeIterator(nodeiter.HexToKeyBytes(startKey)) + it, err = t.NodeIterator(nodeiter.HexToKeyBytes(startKey)) + if err != nil { + return nil, 0, err + } } else { - it = t.NodeIterator(nodeiter.HexToKeyBytes(startKey)) + it, err = t.NodeIterator(nodeiter.HexToKeyBytes(startKey)) + if err != nil { + return nil, 0, err + } // Step to the required node (not required if original startKey was odd-length) it.Next(true) } - return it, makeTimestamp() - startTime + return it, makeTimestamp() - startTime, nil } func fillSliceNodeData( @@ -351,7 +403,7 @@ func fillSliceNodeData( if node.NodeType == Leaf && !storage { stateLeafKey, storageRoot, code, err := extractContractAccountInfo(sdb, node, nodeElements) if err != nil { - return 0, fmt.Errorf("GetSlice account lookup error: %s", err.Error()) + return 0, fmt.Errorf("GetSlice account lookup error: %w", err) } if len(code) > 0 { @@ -387,7 +439,7 @@ func extractContractAccountInfo(sdb state.Database, node StateNode, nodeElements // Extract codeHash and get code codeHash := common.BytesToHash(account.CodeHash) - codeBytes, err := sdb.ContractCode(codeHash) + codeBytes, err := sdb.ContractCode(common.Address{}, codeHash) if err != nil { return "", "", nil, err } diff --git a/pkg/eth/node_types.go b/pkg/eth/node_types.go index 24cc46f0..430ed45b 100644 --- a/pkg/eth/node_types.go +++ b/pkg/eth/node_types.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie" + "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/triedb" ) // NodeType for explicitly setting type of node @@ -73,7 +74,7 @@ type StorageNode struct { LeafKey []byte `json:"leafKey"` } -func ResolveNode(path []byte, node []byte, trieDB *trie.Database) (StateNode, []interface{}, error) { +func ResolveNode(path []byte, node []byte, trieDB *triedb.Database) (StateNode, []interface{}, error) { var nodeElements []interface{} if err := rlp.DecodeBytes(node, &nodeElements); err != nil { return StateNode{}, nil, err @@ -93,7 +94,7 @@ func ResolveNode(path []byte, node []byte, trieDB *trie.Database) (StateNode, [] } // ResolveNodeIt return the state diff node pointed by the iterator. -func ResolveNodeIt(it trie.NodeIterator, trieDB *trie.Database) (StateNode, []interface{}, error) { +func ResolveNodeIt(it trie.NodeIterator, trieDB *triedb.Database) (StateNode, []interface{}, error) { node, err := it.NodeBlob(), it.Error() if err != nil { return StateNode{}, nil, err diff --git a/pkg/eth/state_test/helper_test.go b/pkg/eth/state_test/helper_test.go index 39e35940..2fe55b2d 100644 --- a/pkg/eth/state_test/helper_test.go +++ b/pkg/eth/state_test/helper_test.go @@ -1,8 +1,15 @@ package eth_state_test import ( - "github.com/cerc-io/ipld-eth-server/v5/pkg/eth" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" . "github.com/onsi/gomega" + "github.com/onsi/gomega/format" + "github.com/onsi/gomega/types" + + "github.com/cerc-io/ipld-eth-server/v5/pkg/eth" ) func CheckGetSliceResponse(sliceResponse eth.GetSliceResponse, expectedResponse eth.GetSliceResponse) { @@ -11,3 +18,54 @@ func CheckGetSliceResponse(sliceResponse eth.GetSliceResponse, expectedResponse Expect(sliceResponse.Leaves).To(Equal(expectedResponse.Leaves)) Expect(sliceResponse.MetaData.NodeStats).To(Equal(expectedResponse.MetaData.NodeStats)) } + +// EqualBigInt compares a hexutil.Big for equality with a big.Int or hexutil.Big value. +// It is an error for both actual and expected to be nil. Use BeNil() instead. +func EqualBigInt(expected *big.Int) types.GomegaMatcher { + return &BigIntEqualMatcher{ + Expected: expected, + } +} + +// EqualBigHex compares a hexutil.Big for equality with a big.Int or hexutil.Big value. +// It is an error for both actual and expected to be nil. Use BeNil() instead. +func EqualBigHex(expected *hexutil.Big) types.GomegaMatcher { + return &BigIntEqualMatcher{ + Expected: expected.ToInt(), + } +} + +type BigIntEqualMatcher struct { + Expected *big.Int +} + +func (matcher *BigIntEqualMatcher) Match(actual interface{}) (success bool, err error) { + if actual == nil && matcher.Expected == nil { + return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") + } + + var asInt *big.Int + switch casted := actual.(type) { + case *big.Int: + asInt = casted + case *hexutil.Big: + asInt = (*big.Int)(casted) + default: + return false, fmt.Errorf("BigIntEqualMatcher expects a hexutil.Big or big.Int. Got:\n%s", format.Object(actual, 1)) + } + return matcher.Expected.Cmp(asInt) == 0, nil +} + +func (matcher *BigIntEqualMatcher) FailureMessage(actual interface{}) (message string) { + actualString, actualOK := actual.(string) + expectedString := matcher.Expected.String() + if actualOK { + return format.MessageWithDiff(actualString, "to equal", expectedString) + } + + return format.Message(actual, "to equal", matcher.Expected) +} + +func (matcher *BigIntEqualMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return format.Message(actual, "not to equal", matcher.Expected) +} diff --git a/pkg/eth/state_test/state_test.go b/pkg/eth/state_test/state_test.go index 32c1fd69..2bde1e66 100644 --- a/pkg/eth/state_test/state_test.go +++ b/pkg/eth/state_test/state_test.go @@ -47,7 +47,7 @@ var ( parsedABI abi.ABI randomAddress = common.HexToAddress("0x9F4203bd7a11aCB94882050E6f1C3ab14BBaD3D9") randomHash = crypto.Keccak256Hash(randomAddress.Bytes()) - number = rpc.BlockNumber(test_helpers.BlockNumber.Int64()) + number = rpc.BlockNumber(test_helpers.BlockNumber1) block1StateRoot = common.HexToHash("0xa1f614839ebdd58677df2c9d66a3e0acc9462acc49fad6006d0b6e5d2b98ed21") rootDataHashBlock1 = "a1f614839ebdd58677df2c9d66a3e0acc9462acc49fad6006d0b6e5d2b98ed21" @@ -294,198 +294,198 @@ var _ = Describe("eth state reading tests", func() { It("Retrieves account balance by block number", func() { bal, err := api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(0)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock0)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock0)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(1)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(1)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt((common.Big0))) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(1)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt((common.Big0))) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(1)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(2)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(2)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct2BalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock2)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(2)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedContractBalance)) + Expect(bal).To(EqualBigHex(expectedContractBalance)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(2)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(3)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(3)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct2BalanceBlock3)) + Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock3)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(3)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedContractBalance)) + Expect(bal).To(EqualBigHex(expectedContractBalance)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(3)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(4)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(4)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct2BalanceBlock4)) + Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock4)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(4)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedContractBalance)) + Expect(bal).To(EqualBigHex(expectedContractBalance)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(4)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(5)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock5)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock5)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(5)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct2BalanceBlock4)) + Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock4)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(5)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedContractBalance)) + Expect(bal).To(EqualBigHex(expectedContractBalance)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(5)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) }) It("Retrieves account balance by block hash", func() { bal, err := api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock0)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock0)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt((common.Big0))) _, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt((common.Big0))) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct2BalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock2)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedContractBalance)) + Expect(bal).To(EqualBigHex(expectedContractBalance)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct2BalanceBlock3)) + Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock3)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedContractBalance)) + Expect(bal).To(EqualBigHex(expectedContractBalance)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock1)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct2BalanceBlock4)) + Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock4)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedContractBalance)) + Expect(bal).To(EqualBigHex(expectedContractBalance)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct1BalanceBlock5)) + Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock5)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedAcct2BalanceBlock4)) + Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock4)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedContractBalance)) + Expect(bal).To(EqualBigHex(expectedContractBalance)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal(expectedBankBalanceBlock2)) + Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) }) It("Returns 0 if account balance not found by block number", func() { bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(0)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt(common.Big0)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(0)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt(common.Big0)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt(common.Big0)) }) It("Returns 0 if account balance not found by block hash", func() { bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt(common.Big0)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt(common.Big0)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true)) Expect(err).ToNot(HaveOccurred()) - Expect(bal).To(Equal((*hexutil.Big)(common.Big0))) + Expect(bal).To(EqualBigInt(common.Big0)) }) }) diff --git a/pkg/eth/test_helpers/test_data.go b/pkg/eth/test_helpers/test_data.go index 71a63a78..e1cac26a 100644 --- a/pkg/eth/test_helpers/test_data.go +++ b/pkg/eth/test_helpers/test_data.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/holiman/uint256" "github.com/ipfs/go-cid" "github.com/cerc-io/ipld-eth-server/v5/pkg/eth" @@ -40,10 +41,11 @@ import ( // Test variables var ( // block data - BlockNumber = big.NewInt(1) - MockHeader = types.Header{ + BlockNumber1 = int64(1) + BlockTime1 = uint64(0) + MockHeader = types.Header{ Time: 0, - Number: new(big.Int).Set(BlockNumber), + Number: big.NewInt(BlockNumber1), Root: common.HexToHash("0x0"), TxHash: common.HexToHash("0x0"), ReceiptHash: common.HexToHash("0x0"), @@ -54,7 +56,7 @@ var ( MockUncles = []*types.Header{ { Time: 1, - Number: new(big.Int).Add(BlockNumber, big.NewInt(1)), + Number: big.NewInt(BlockNumber1 + 1), Root: common.HexToHash("0x1"), TxHash: common.HexToHash("0x1"), ReceiptHash: common.HexToHash("0x1"), @@ -64,7 +66,7 @@ var ( }, { Time: 2, - Number: new(big.Int).Add(BlockNumber, big.NewInt(2)), + Number: big.NewInt(BlockNumber1 + 2), Root: common.HexToHash("0x2"), TxHash: common.HexToHash("0x2"), ReceiptHash: common.HexToHash("0x2"), @@ -76,7 +78,7 @@ var ( MockBlock = createNewBlock(&MockHeader, MockTransactions, MockUncles, MockReceipts, trie.NewEmpty(nil)) MockChildHeader = types.Header{ Time: 0, - Number: new(big.Int).Add(BlockNumber, common.Big1), + Number: big.NewInt(BlockNumber1 + 1), Root: common.HexToHash("0x0"), TxHash: common.HexToHash("0x0"), ReceiptHash: common.HexToHash("0x0"), @@ -104,7 +106,7 @@ var ( Address: Address, Topics: []common.Hash{mockTopic11, mockTopic12}, Data: []byte{}, - BlockNumber: BlockNumber.Uint64(), + BlockNumber: uint64(BlockNumber1), TxIndex: 0, Index: 0, } @@ -112,7 +114,7 @@ var ( Address: AnotherAddress, Topics: []common.Hash{mockTopic21, mockTopic22}, Data: []byte{}, - BlockNumber: BlockNumber.Uint64(), + BlockNumber: uint64(BlockNumber1), TxIndex: 1, Index: 1, } @@ -120,7 +122,7 @@ var ( Address: AnotherAddress1, Topics: []common.Hash{mockTopic31}, Data: []byte{}, - BlockNumber: BlockNumber.Uint64(), + BlockNumber: uint64(BlockNumber1), TxIndex: 2, Index: 2, } @@ -129,7 +131,7 @@ var ( Address: AnotherAddress1, Topics: []common.Hash{mockTopic41, mockTopic42, mockTopic43}, Data: []byte{}, - BlockNumber: BlockNumber.Uint64(), + BlockNumber: uint64(BlockNumber1), TxIndex: 2, Index: 3, } @@ -137,7 +139,7 @@ var ( Address: AnotherAddress1, Topics: []common.Hash{mockTopic51}, Data: []byte{}, - BlockNumber: BlockNumber.Uint64(), + BlockNumber: uint64(BlockNumber1), TxIndex: 2, Index: 4, } @@ -145,7 +147,7 @@ var ( Address: AnotherAddress2, Topics: []common.Hash{mockTopic61}, Data: []byte{}, - BlockNumber: BlockNumber.Uint64(), + BlockNumber: uint64(BlockNumber1), TxIndex: 3, Index: 5, } @@ -217,7 +219,7 @@ var ( ContractLeafKey = crypto.Keccak256(ContractAddress[:]) ContractAccount = types.StateAccount{ Nonce: uint64(1), - Balance: big.NewInt(0), + Balance: uint256.NewInt(0), CodeHash: CodeHash.Bytes(), Root: common.HexToHash(ContractRoot), } @@ -229,7 +231,7 @@ var ( }) nonce0 = uint64(0) - AccountBalance = big.NewInt(1000) + AccountBalance = uint256.NewInt(1000) AccountRoot = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" AccountCodeHash = common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") AccountAddresss = common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e") @@ -290,21 +292,22 @@ var ( StateNodes: MockStateNodes, } - LondonBlockNum = new(big.Int).Add(BlockNumber, big.NewInt(2)) + LondonBlockNum = (BlockNumber1 + 2) + LondonBlockTime = BlockTime1 + 1 MockLondonHeader = types.Header{ Time: 0, - Number: LondonBlockNum, + Number: big.NewInt(LondonBlockNum), Root: common.HexToHash("0x00"), Difficulty: big.NewInt(5000000), Extra: []byte{}, BaseFee: big.NewInt(params.InitialBaseFee), } - MockLondonTransactions, MockLondonReceipts, _ = createDynamicTransactionsAndReceipts(LondonBlockNum) + MockLondonTransactions, MockLondonReceipts, _ = createDynamicTransactionsAndReceipts(big.NewInt(LondonBlockNum), LondonBlockTime) MockLondonUncles = []*types.Header{ { Time: 1, - Number: new(big.Int).Add(BlockNumber, big.NewInt(1)), + Number: big.NewInt(BlockNumber1 + 1), ParentHash: common.HexToHash("0x2"), Root: common.HexToHash("0x1"), TxHash: common.HexToHash("0x1"), @@ -314,7 +317,7 @@ var ( }, { Time: 2, - Number: new(big.Int).Add(BlockNumber, big.NewInt(1)), + Number: big.NewInt(BlockNumber1 + 1), ParentHash: common.HexToHash("0x1"), Root: common.HexToHash("0x2"), TxHash: common.HexToHash("0x2"), @@ -338,7 +341,7 @@ func createNewBlock(header *types.Header, txs []*types.Transaction, uncles []*ty } // createDynamicTransactionsAndReceipts is a helper function to generate signed mock transactions and mock receipts with mock logs -func createDynamicTransactionsAndReceipts(blockNumber *big.Int) (types.Transactions, types.Receipts, common.Address) { +func createDynamicTransactionsAndReceipts(blockNumber *big.Int, blockTime uint64) (types.Transactions, types.Receipts, common.Address) { // make transactions config := *params.TestChainConfig config.LondonBlock = blockNumber @@ -353,7 +356,7 @@ func createDynamicTransactionsAndReceipts(blockNumber *big.Int) (types.Transacti Data: []byte{}, }) - transactionSigner := types.MakeSigner(&config, blockNumber) + transactionSigner := types.MakeSigner(&config, blockNumber, blockTime) mockCurve := elliptic.P256() mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader) if err != nil { @@ -391,7 +394,7 @@ func createLegacyTransactionsAndReceipts() (types.Transactions, types.Receipts, trx2 := types.NewTransaction(1, AnotherAddress, big.NewInt(2000), 100, big.NewInt(200), []byte{}) trx3 := types.NewContractCreation(2, big.NewInt(1500), 75, big.NewInt(150), ContractCode) trx4 := types.NewTransaction(3, AnotherAddress1, big.NewInt(2000), 100, big.NewInt(200), []byte{}) - transactionSigner := types.MakeSigner(params.MainnetChainConfig, new(big.Int).Set(BlockNumber)) + transactionSigner := types.MakeSigner(params.MainnetChainConfig, big.NewInt(BlockNumber1), 0) mockCurve := elliptic.P256() mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader) if err != nil { diff --git a/pkg/eth/types.go b/pkg/eth/types.go index 71c11f19..65b02b8c 100644 --- a/pkg/eth/types.go +++ b/pkg/eth/types.go @@ -33,26 +33,30 @@ import ( ) // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction +// Note: copied from go-ethereum/internal/ethapi type RPCTransaction struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` - GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - Type hexutil.Uint64 `json:"type"` - Accesses *types.AccessList `json:"accessList,omitempty"` - ChainID *hexutil.Big `json:"chainId,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` + BlockHash *common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` + GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` + MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + Type hexutil.Uint64 `json:"type"` + Accesses *types.AccessList `json:"accessList,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` + BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` + YParity *hexutil.Uint64 `json:"yParity,omitempty"` } // RPCReceipt represents a receipt that will serialize to the RPC representation of a receipt diff --git a/pkg/graphql/graphql.go b/pkg/graphql/graphql.go index 75a8b690..47155758 100644 --- a/pkg/graphql/graphql.go +++ b/pkg/graphql/graphql.go @@ -64,7 +64,7 @@ func (a *Account) Balance(ctx context.Context) (hexutil.Big, error) { if err != nil { return hexutil.Big{}, err } - return hexutil.Big(*state.GetBalance(a.address)), nil + return hexutil.Big(*state.GetBalance(a.address).ToBig()), nil } func (a *Account) TransactionCount(ctx context.Context) (hexutil.Uint64, error) {