| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- package ethapi
- import (
- "context"
- "errors"
- "fmt"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/consensus"
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/rpc"
- "math/big"
- "time"
- )
- // PublicBlockChainAPI provides an API to access the Ethereum blockchain.
- // It offers only methods that operate on public data that is freely available to anyone.
- type PublicBlockChainAPI struct {
- b Backend
- }
- // NewPublicBlockChainAPI creates a new Ethereum blockchain API.
- func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
- return &PublicBlockChainAPI{b}
- }
- // Call executes the given transaction on the state for the given block number.
- //
- // Additionally, the caller can specify a batch of contract for fields overriding.
- //
- // Note, this function doesn't make and changes in the state/blockchain and is
- // useful to execute and retrieve values.
- func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) {
- result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, vm.Config{}, 5*time.Second, s.b.RPCGasCap())
- if err != nil {
- return nil, err
- }
- // If the result contains a revert reason, try to unpack and return it.
- if len(result.Revert()) > 0 {
- return nil, newRevertError(result)
- }
- return result.Return(), result.Err
- }
- func (s *PublicBlockChainAPI) NewCall(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (CallResult, error) {
- result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, vm.Config{}, 5*time.Second, s.b.RPCGasCap())
- if err != nil {
- return CallResult{Success: false, Msg: err.Error()}, nil
- } else {
- if len(result.Revert()) > 0 {
- revertErr := newRevertError(result)
- return CallResult{Success: false, Return: result.Return(), Msg: revertErr.Error()}, nil
- }
- return CallResult{Success: true, Return: result.Return()}, nil
- }
- }
- // ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
- func (api *PublicBlockChainAPI) ChainId() (*hexutil.Big, error) {
- // if current block is at or past the EIP-155 replay-protection fork block, return chainID from config
- if config := api.b.ChainConfig(); config.IsEIP155(api.b.CurrentBlock().Number()) {
- return (*hexutil.Big)(config.ChainID), nil
- }
- return nil, fmt.Errorf("chain not synced beyond EIP-155 replay-protection fork block")
- }
- // BlockNumber returns the block number of the chain head.
- func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
- header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
- return hexutil.Uint64(header.Number.Uint64())
- }
- // GetBalance returns the amount of wei for the given address in the state of the
- // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
- // block numbers are also allowed.
- func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
- state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
- if state == nil || err != nil {
- return nil, err
- }
- return (*hexutil.Big)(state.GetBalance(address)), state.Error()
- }
- // BatchCall executes a series of transactions on the state of a given block as base.
- // The base state can be overridden once before transactions are executed.
- //
- // Additionally, each call can override block context fields such as number.
- //
- // Note, this function doesn't make any changes in the state/blockchain and is
- // useful to execute and retrieve values.
- func (s *PublicBlockChainAPI) BatchCall(ctx context.Context, config BatchCallConfig) ([]CallResult, error) {
- state, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, config.Block)
- if state == nil || err != nil {
- return nil, err
- }
- // State overrides are applied once before all calls
- if err := config.StateOverrides.Apply(state); err != nil {
- return nil, err
- }
- // Setup context so it may be cancelled before the calls completed
- // or, in case of unmetered gas, setup a context with a timeout.
- var (
- cancel context.CancelFunc
- //timeout = s.b.RPCEVMTimeout()
- timeout = time.Duration(5000000000)
- )
- if timeout > 0 {
- ctx, cancel = context.WithTimeout(ctx, timeout)
- } else {
- ctx, cancel = context.WithCancel(ctx)
- }
- // Make sure the context is cancelled when the call has completed
- // this makes sure resources are cleaned up.
- defer cancel()
- var (
- results []CallResult
- // Each tx and all the series of txes shouldn't consume more gas than cap
- globalGasCap = s.b.RPCGasCap()
- gp = new(core.GasPool).AddGas(globalGasCap)
- )
- for _, call := range config.Calls {
- blockContext := core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil)
- if call.BlockOverrides != nil {
- call.BlockOverrides.Apply(&blockContext)
- }
- result, doCallErr := doCall(ctx, s.b, call.CallArgs, state, header, timeout, gp, &blockContext)
- if doCallErr != nil {
- results = append(results, CallResult{Success: false, Msg: doCallErr.Error()})
- } else {
- if len(result.Revert()) > 0 {
- revertErr := newRevertError(result)
- results = append(results, CallResult{Success: false, Return: result.Return(), Msg: revertErr.Error()})
- } else {
- results = append(results, CallResult{Success: true, Return: result.Return()})
- }
- }
- }
- return results, nil
- }
- // EstimateGas returns an estimate of the amount of gas needed to execute the
- // given transaction against the current pending block.
- func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) {
- bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
- if blockNrOrHash != nil {
- bNrOrHash = *blockNrOrHash
- }
- return DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap())
- }
- // GetProof returns the Merkle-proof for a given account and optionally some storage keys.
- func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
- state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
- if state == nil || err != nil {
- return nil, err
- }
- storageTrie := state.StorageTrie(address)
- 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{}}
- }
- }
- // create the accountProof
- accountProof, proofErr := state.GetProof(address)
- if proofErr != nil {
- return nil, proofErr
- }
- return &AccountResult{
- Address: address,
- AccountProof: toHexSlice(accountProof),
- Balance: (*hexutil.Big)(state.GetBalance(address)),
- CodeHash: codeHash,
- Nonce: hexutil.Uint64(state.GetNonce(address)),
- StorageHash: storageHash,
- StorageProof: storageProof,
- }, state.Error()
- }
- // GetHeaderByNumber returns the requested canonical block header.
- // * When blockNr is -1 the chain head is returned.
- // * When blockNr is -2 the pending chain head is returned.
- func (s *PublicBlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) {
- header, err := s.b.HeaderByNumber(ctx, number)
- if header != nil && err == nil {
- response := s.rpcMarshalHeader(ctx, header)
- if number == rpc.PendingBlockNumber {
- // Pending header need to nil out a few fields
- for _, field := range []string{"hash", "nonce", "miner"} {
- response[field] = nil
- }
- }
- return response, err
- }
- return nil, err
- }
- // GetHeaderByHash returns the requested header by hash.
- func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} {
- header, _ := s.b.HeaderByHash(ctx, hash)
- if header != nil {
- return s.rpcMarshalHeader(ctx, header)
- }
- return nil
- }
- // GetBlockByNumber returns the requested canonical block.
- // - When blockNr is -1 the chain head is returned.
- // - When blockNr is -2 the pending chain head is returned.
- // - When fullTx is true all transactions in the block are returned, otherwise
- // only the transaction hash is returned.
- func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
- block, err := s.b.BlockByNumber(ctx, number)
- if block != nil && err == nil {
- response, err := s.rpcMarshalBlock(ctx, block, true, fullTx)
- if err == nil && number == rpc.PendingBlockNumber {
- // Pending blocks need to nil out a few fields
- for _, field := range []string{"hash", "nonce", "miner"} {
- response[field] = nil
- }
- }
- return response, err
- }
- return nil, err
- }
- // GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
- // detail, otherwise only the transaction hash is returned.
- func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
- block, err := s.b.BlockByHash(ctx, hash)
- if block != nil {
- return s.rpcMarshalBlock(ctx, block, true, fullTx)
- }
- return nil, err
- }
- func (s *PublicBlockChainAPI) Health() bool {
- if rpc.RpcServingTimer != nil {
- return rpc.RpcServingTimer.Percentile(0.75) < float64(UnHealthyTimeout)
- }
- return true
- }
- // 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.
- func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) {
- block, err := s.b.BlockByNumber(ctx, blockNr)
- if block != nil {
- uncles := block.Uncles()
- if index >= hexutil.Uint(len(uncles)) {
- log.Debug("Requested uncle not found", "number", blockNr, "hash", block.Hash(), "index", index)
- return nil, nil
- }
- block = types.NewBlockWithHeader(uncles[index])
- return s.rpcMarshalBlock(ctx, block, false, false)
- }
- return nil, err
- }
- // GetUncleByBlockHashAndIndex 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.
- func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) {
- block, err := s.b.BlockByHash(ctx, blockHash)
- if block != nil {
- uncles := block.Uncles()
- if index >= hexutil.Uint(len(uncles)) {
- log.Debug("Requested uncle not found", "number", block.Number(), "hash", blockHash, "index", index)
- return nil, nil
- }
- block = types.NewBlockWithHeader(uncles[index])
- return s.rpcMarshalBlock(ctx, block, false, false)
- }
- return nil, err
- }
- // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number
- func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
- if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
- n := hexutil.Uint(len(block.Uncles()))
- return &n
- }
- return nil
- }
- // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash
- func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
- if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
- n := hexutil.Uint(len(block.Uncles()))
- return &n
- }
- return nil
- }
- // GetCode returns the code stored at the given address in the state for the given block number.
- func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
- state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
- if state == nil || err != nil {
- return nil, err
- }
- code := state.GetCode(address)
- return code, state.Error()
- }
- // GetStorageAt returns the storage from the state at the given address, key and
- // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
- // numbers are also allowed.
- func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
- state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
- if state == nil || err != nil {
- return nil, err
- }
- res := state.GetState(address, common.HexToHash(key))
- return res[:], state.Error()
- }
- // GetDiffAccounts returns changed accounts in a specific block number.
- func (s *PublicBlockChainAPI) GetDiffAccounts(ctx context.Context, blockNr rpc.BlockNumber) ([]common.Address, error) {
- if s.b.Chain() == nil {
- return nil, fmt.Errorf("blockchain not support get diff accounts")
- }
- header, err := s.b.HeaderByNumber(ctx, blockNr)
- if err != nil {
- return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err)
- }
- accounts, err := s.b.Chain().GetDiffAccounts(header.Hash())
- if err == nil || !errors.Is(err, core.ErrDiffLayerNotFound) {
- return accounts, err
- }
- // Replay the block when diff layer not found, it is very slow.
- block, err := s.b.BlockByNumber(ctx, blockNr)
- if err != nil {
- return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err)
- }
- _, statedb, err := s.replay(ctx, block, nil)
- if err != nil {
- return nil, err
- }
- return statedb.GetDirtyAccounts(), nil
- }
- func (s *PublicBlockChainAPI) needToReplay(ctx context.Context, block *types.Block, accounts []common.Address) (bool, error) {
- receipts, err := s.b.GetReceipts(ctx, block.Hash())
- if err != nil || len(receipts) != len(block.Transactions()) {
- return false, fmt.Errorf("receipt incorrect for block number (%d): %v", block.NumberU64(), err)
- }
- accountSet := make(map[common.Address]struct{}, len(accounts))
- for _, account := range accounts {
- accountSet[account] = struct{}{}
- }
- spendValueMap := make(map[common.Address]int64, len(accounts))
- receiveValueMap := make(map[common.Address]int64, len(accounts))
- signer := types.MakeSigner(s.b.ChainConfig(), block.Number())
- for index, tx := range block.Transactions() {
- receipt := receipts[index]
- from, err := types.Sender(signer, tx)
- if err != nil {
- return false, fmt.Errorf("get sender for tx failed: %v", err)
- }
- if _, exists := accountSet[from]; exists {
- spendValueMap[from] += int64(receipt.GasUsed) * tx.GasPrice().Int64()
- if receipt.Status == types.ReceiptStatusSuccessful {
- spendValueMap[from] += tx.Value().Int64()
- }
- }
- if tx.To() == nil {
- continue
- }
- if _, exists := accountSet[*tx.To()]; exists && receipt.Status == types.ReceiptStatusSuccessful {
- receiveValueMap[*tx.To()] += tx.Value().Int64()
- }
- }
- parent, err := s.b.BlockByHash(ctx, block.ParentHash())
- if err != nil {
- return false, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err)
- }
- parentState, err := s.b.Chain().StateAt(parent.Root())
- if err != nil {
- return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64()-1, err)
- }
- currentState, err := s.b.Chain().StateAt(block.Root())
- if err != nil {
- return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64(), err)
- }
- for _, account := range accounts {
- parentBalance := parentState.GetBalance(account).Int64()
- currentBalance := currentState.GetBalance(account).Int64()
- if receiveValueMap[account]-spendValueMap[account] != currentBalance-parentBalance {
- return true, nil
- }
- }
- return false, nil
- }
- func (s *PublicBlockChainAPI) replay(ctx context.Context, block *types.Block, accounts []common.Address) (*types.DiffAccountsInBlock, *state.StateDB, error) {
- result := &types.DiffAccountsInBlock{
- Number: block.NumberU64(),
- BlockHash: block.Hash(),
- Transactions: make([]types.DiffAccountsInTx, 0),
- }
- parent, err := s.b.BlockByHash(ctx, block.ParentHash())
- if err != nil {
- return nil, nil, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err)
- }
- statedb, err := s.b.Chain().StateAt(parent.Root())
- if err != nil {
- return nil, nil, fmt.Errorf("state not found for block number (%d): %v", block.NumberU64()-1, err)
- }
- accountSet := make(map[common.Address]struct{}, len(accounts))
- for _, account := range accounts {
- accountSet[account] = struct{}{}
- }
- // Recompute transactions.
- signer := types.MakeSigner(s.b.ChainConfig(), block.Number())
- for _, tx := range block.Transactions() {
- // Skip data empty tx and to is one of the interested accounts tx.
- skip := false
- if len(tx.Data()) == 0 {
- skip = true
- } else if to := tx.To(); to != nil {
- if _, exists := accountSet[*to]; exists {
- skip = true
- }
- }
- diffTx := types.DiffAccountsInTx{
- TxHash: tx.Hash(),
- Accounts: make(map[common.Address]*big.Int, len(accounts)),
- }
- if !skip {
- // Record account balance
- for _, account := range accounts {
- diffTx.Accounts[account] = statedb.GetBalance(account)
- }
- }
- // Apply transaction
- msg, _ := tx.AsMessage(signer)
- txContext := core.NewEVMTxContext(msg)
- context := core.NewEVMBlockContext(block.Header(), s.b.Chain(), nil)
- vmenv := vm.NewEVM(context, txContext, statedb, s.b.ChainConfig(), vm.Config{})
- if posa, ok := s.b.Engine().(consensus.PoSA); ok {
- if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem {
- balance := statedb.GetBalance(consensus.SystemAddress)
- if balance.Cmp(common.Big0) > 0 {
- statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
- statedb.AddBalance(block.Header().Coinbase, balance)
- }
- }
- }
- if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
- return nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
- }
- statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
- if !skip {
- // Compute account balance diff.
- for _, account := range accounts {
- diffTx.Accounts[account] = new(big.Int).Sub(statedb.GetBalance(account), diffTx.Accounts[account])
- if diffTx.Accounts[account].Cmp(big.NewInt(0)) == 0 {
- delete(diffTx.Accounts, account)
- }
- }
- if len(diffTx.Accounts) != 0 {
- result.Transactions = append(result.Transactions, diffTx)
- }
- }
- }
- return result, statedb, nil
- }
- // GetDiffAccountsWithScope returns detailed changes of some interested accounts in a specific block number.
- func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, blockNr rpc.BlockNumber, accounts []common.Address) (*types.DiffAccountsInBlock, error) {
- if s.b.Chain() == nil {
- return nil, fmt.Errorf("blockchain not support get diff accounts")
- }
- block, err := s.b.BlockByNumber(ctx, blockNr)
- if err != nil {
- return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err)
- }
- needReplay, err := s.needToReplay(ctx, block, accounts)
- if err != nil {
- return nil, err
- }
- if !needReplay {
- return &types.DiffAccountsInBlock{
- Number: uint64(blockNr),
- BlockHash: block.Hash(),
- Transactions: make([]types.DiffAccountsInTx, 0),
- }, nil
- }
- result, _, err := s.replay(ctx, block, accounts)
- return result, err
- }
- // rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires
- // a `PublicBlockchainAPI`.
- func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} {
- fields := RPCMarshalHeader(header)
- fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash()))
- return fields
- }
- // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires
- // a `PublicBlockchainAPI`.
- func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
- fields, err := RPCMarshalBlock(b, inclTx, fullTx)
- if err != nil {
- return nil, err
- }
- if inclTx {
- fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, b.Hash()))
- }
- return fields, err
- }
- // CreateAccessList creates a EIP-2930 type AccessList for the given transaction.
- // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
- func (s *PublicBlockChainAPI) CreateAccessList(ctx context.Context, args SendTxArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) {
- bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
- if blockNrOrHash != nil {
- bNrOrHash = *blockNrOrHash
- }
- acl, gasUsed, vmerr, err := AccessList(ctx, s.b, bNrOrHash, args)
- if err != nil {
- return nil, err
- }
- result := &accessListResult{Accesslist: &acl, GasUsed: hexutil.Uint64(gasUsed)}
- if vmerr != nil {
- result.Error = vmerr.Error()
- }
- return result, nil
- }
|