diff --git a/arbitrum/apibackend.go b/arbitrum/apibackend.go index baa7238fee..b7b9f5731b 100644 --- a/arbitrum/apibackend.go +++ b/arbitrum/apibackend.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "runtime" "strconv" "strings" "time" @@ -229,11 +230,10 @@ func (a *APIBackend) FeeHistory( // use the most recent average compute rate for all blocks // note: while we could query this value for each block, it'd be prohibitively expensive - state, _, release, err := a.StateAndHeaderByNumber(ctx, newestBlock) + state, _, err := a.StateAndHeaderByNumber(ctx, newestBlock) if err != nil { return common.Big0, nil, nil, nil, err } - defer release() speedLimit, err := core.GetArbOSSpeedLimitPerSecond(state) if err != nil { return common.Big0, nil, nil, nil, err @@ -434,15 +434,15 @@ func (a *APIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc. return nil, errors.New("invalid arguments; neither block nor hash specified") } -func (a *APIBackend) stateAndHeaderFromHeader(ctx context.Context, header *types.Header, err error) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) { +func (a *APIBackend) stateAndHeaderFromHeader(ctx context.Context, header *types.Header, err error) (*state.StateDB, *types.Header, error) { if err != nil { - return nil, header, nil, err + return nil, header, err } if header == nil { - return nil, nil, nil, errors.New("header not found") + return nil, nil, errors.New("header not found") } if !a.BlockChain().Config().IsArbitrumNitro(header.Number) { - return nil, header, nil, types.ErrUseFallback + return nil, header, types.ErrUseFallback } bc := a.BlockChain() stateFor := func(header *types.Header) (*state.StateDB, error) { @@ -450,43 +450,61 @@ func (a *APIBackend) stateAndHeaderFromHeader(ctx context.Context, header *types // Try referencing the root, if it isn't in dirties cache then Reference will have no effect bc.StateCache().TrieDB().Reference(header.Root, common.Hash{}) } - state, err := bc.StateAt(header.Root) - return state, err + statedb, err := state.New(header.Root, bc.StateCache(), bc.Snapshots()) + if err != nil { + return nil, err + } + if header.Root != (common.Hash{}) { + // we are setting finalizer instead of returning a StateReleaseFunc to avoid changing ethapi.Backend interface to minimize diff to upstream + headerRoot := header.Root + runtime.SetFinalizer(statedb, func(_ *state.StateDB) { + bc.StateCache().TrieDB().Dereference(headerRoot) + }) + } + return statedb, err } lastState, lastHeader, err := FindLastAvailableState(ctx, bc, stateFor, header, nil, a.b.config.MaxRecreateStateDepth) if err != nil { - return nil, nil, nil, err - } - release := func() { - if lastHeader.Root != (common.Hash{}) { - bc.StateCache().TrieDB().Dereference(lastHeader.Root) - } + return nil, nil, err } if lastHeader == header { - return lastState, header, release, nil + return lastState, header, nil + } + if lastHeader.Root != (common.Hash{}) { + defer bc.StateCache().TrieDB().Dereference(lastHeader.Root) } - defer release() targetBlock := bc.GetBlockByNumber(header.Number.Uint64()) if targetBlock == nil { - return nil, nil, nil, errors.New("target block not found") + return nil, nil, errors.New("target block not found") } lastBlock := bc.GetBlockByNumber(lastHeader.Number.Uint64()) if lastBlock == nil { - return nil, nil, nil, errors.New("last block not found") + return nil, nil, errors.New("last block not found") } reexec := uint64(0) checkLive := false preferDisk := true - state, release, err := eth.NewArbEthereum(a.b.arb.BlockChain(), a.ChainDb()).StateAtBlock(ctx, targetBlock, reexec, lastState, lastBlock, checkLive, preferDisk) - return state, header, release, err + statedb, release, err := eth.NewArbEthereum(a.b.arb.BlockChain(), a.ChainDb()).StateAtBlock(ctx, targetBlock, reexec, lastState, lastBlock, checkLive, preferDisk) + if err != nil { + return nil, nil, err + } + // we are setting finalizer instead of returning a StateReleaseFunc to avoid changing ethapi.Backend interface to minimize diff to upstream + // to set a finalizer we need to allocated the obj in current block + statedb, err = state.New(header.Root, statedb.Database(), nil) + if header.Root != (common.Hash{}) { + runtime.SetFinalizer(statedb, func(_ *state.StateDB) { + release() + }) + } + return statedb, header, err } -func (a *APIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) { +func (a *APIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { header, err := a.HeaderByNumber(ctx, number) return a.stateAndHeaderFromHeader(ctx, header, err) } -func (a *APIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) { +func (a *APIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { header, err := a.HeaderByNumberOrHash(ctx, blockNrOrHash) return a.stateAndHeaderFromHeader(ctx, header, err) } diff --git a/eth/api_backend.go b/eth/api_backend.go index 558ded2e98..7656d63c58 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -37,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -199,46 +198,46 @@ func (b *EthAPIBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) return b.eth.miner.PendingBlockAndReceipts() } -func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) { +func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { // Pending state is only known by the miner if number == rpc.PendingBlockNumber { block, state := b.eth.miner.Pending() if block == nil || state == nil { - return nil, nil, nil, errors.New("pending state is not available") + return nil, nil, errors.New("pending state is not available") } - return state, block.Header(), ethapi.NoOpStateRelease, nil + return state, block.Header(), nil } // Otherwise resolve the block number and return its state header, err := b.HeaderByNumber(ctx, number) if err != nil { - return nil, nil, nil, err + return nil, nil, err } if header == nil { - return nil, nil, nil, errors.New("header not found") + return nil, nil, errors.New("header not found") } stateDb, err := b.eth.BlockChain().StateAt(header.Root) - return stateDb, header, ethapi.NoOpStateRelease, err + return stateDb, header, err } -func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) { +func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { if blockNr, ok := blockNrOrHash.Number(); ok { return b.StateAndHeaderByNumber(ctx, blockNr) } if hash, ok := blockNrOrHash.Hash(); ok { header, err := b.HeaderByHash(ctx, hash) if err != nil { - return nil, nil, nil, err + return nil, nil, err } if header == nil { - return nil, nil, nil, errors.New("header for hash not found") + return nil, nil, errors.New("header for hash not found") } if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash { - return nil, nil, nil, errors.New("hash is not currently canonical") + return nil, nil, errors.New("hash is not currently canonical") } stateDb, err := b.eth.BlockChain().StateAt(header.Root) - return stateDb, header, ethapi.NoOpStateRelease, err + return stateDb, header, err } - return nil, nil, nil, errors.New("invalid arguments; neither block nor hash specified") + return nil, nil, errors.New("invalid arguments; neither block nor hash specified") } func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index cd846a499e..05ad3def48 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1143,11 +1143,10 @@ func TestWithdrawals(t *testing.T) { } // 11: verify withdrawals were processed. - db, _, release, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number)) + db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number)) if err != nil { t.Fatalf("unable to load db: %v", err) } - defer release() for i, w := range blockParams.Withdrawals { // w.Amount is in gwei, balance in wei if db.GetBalance(w.Address).Uint64() != w.Amount*params.GWei { diff --git a/graphql/graphql.go b/graphql/graphql.go index ac8b79ea5a..c40e42718d 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -86,9 +86,9 @@ type Account struct { } // getState fetches the StateDB object for an account. -func (a *Account) getState(ctx context.Context) (*state.StateDB, ethapi.StateReleaseFunc, error) { - state, _, release, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash) - return state, release, err +func (a *Account) getState(ctx context.Context) (*state.StateDB, error) { + state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash) + return state, err } func (a *Account) Address(ctx context.Context) (common.Address, error) { @@ -96,11 +96,10 @@ func (a *Account) Address(ctx context.Context) (common.Address, error) { } func (a *Account) Balance(ctx context.Context) (hexutil.Big, error) { - state, release, err := a.getState(ctx) + state, err := a.getState(ctx) if err != nil { return hexutil.Big{}, err } - defer release() balance := state.GetBalance(a.address) if balance == nil { return hexutil.Big{}, fmt.Errorf("failed to load balance %x", a.address) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c268e08586..1fd916d903 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -620,7 +620,7 @@ func (s *BlockChainAPI) BlockNumber() hexutil.Uint64 { // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // block numbers are also allowed. func (s *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { - state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { if client := fallbackClientFor(s.b, err); client != nil { var res hexutil.Big @@ -629,7 +629,6 @@ func (s *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, } return nil, err } - defer release() return (*hexutil.Big)(state.GetBalance(address)), state.Error() } @@ -682,11 +681,10 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st } } - state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } - defer release() if storageTrie, err = state.StorageTrie(address); err != nil { return nil, err } @@ -869,7 +867,7 @@ func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash // GetCode returns the code stored at the given address in the state for the given block number. func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { if client := fallbackClientFor(s.b, err); client != nil { var res hexutil.Bytes @@ -878,7 +876,6 @@ func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blo } return nil, err } - defer release() code := state.GetCode(address) return code, state.Error() } @@ -891,7 +888,7 @@ func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address if err != nil { return nil, fmt.Errorf("unable to decode storage key: %s", err) } - state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { if client := fallbackClientFor(s.b, err); client != nil { var res hexutil.Bytes @@ -900,7 +897,6 @@ func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address } return nil, err } - defer release() res := state.GetState(address, key) return res[:], state.Error() } @@ -1129,11 +1125,10 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64, runMode core.MessageRunMode) (*core.ExecutionResult, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) - state, header, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } - defer release() return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap, runMode) } @@ -1237,11 +1232,10 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr } // Recap the highest gas limit with account's available balance. if feeCap.BitLen() != 0 { - state, _, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if err != nil { return 0, err } - defer release() err = overrides.Apply(state) if err != nil { return 0, err @@ -1271,11 +1265,10 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr // Arbitrum: raise the gas cap to ignore L1 costs so that it's compute-only vanillaGasCap := gasCap { - state, header, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return 0, err } - defer release() gasCap, err = args.L2OnlyGasCap(gasCap, header, state, core.MessageGasEstimationMode) if err != nil { return 0, err @@ -1302,11 +1295,10 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr } return result.Failed(), result, nil } - state, header, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return 0, err } - defer release() err = overrides.Apply(state) if err != nil { return 0, err @@ -1703,11 +1695,10 @@ func (s *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionAr // If the transaction itself fails, an vmErr is returned. func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs) (acl types.AccessList, gasUsed uint64, vmErr error, err error) { // Retrieve the execution context - db, header, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if db == nil || err != nil { return nil, 0, nil, err } - defer release() // If the gas amount is not set, default to RPC gas cap. if args.Gas == nil { tmp := hexutil.Uint64(b.RPCGasCap()) @@ -1838,7 +1829,7 @@ func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common return (*hexutil.Uint64)(&nonce), nil } // Resolve block number and use its state to ask for the nonce - state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { if client := fallbackClientFor(s.b, err); client != nil { var res hexutil.Uint64 @@ -1847,7 +1838,6 @@ func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common } return nil, err } - defer release() nonce := state.GetNonce(address) return (*hexutil.Uint64)(&nonce), state.Error() } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index dad135b79e..c92b438b03 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -437,7 +437,7 @@ func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc. func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil } -func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, StateReleaseFunc, error) { +func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { if number == rpc.PendingBlockNumber { panic("pending state not implemented") } @@ -449,9 +449,9 @@ func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.Bloc return nil, nil, nil, errors.New("header not found") } stateDb, err := b.chain.StateAt(header.Root) - return stateDb, header, NoOpStateRelease, err + return stateDb, header, err } -func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, StateReleaseFunc, error) { +func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { if blockNr, ok := blockNrOrHash.Number(); ok { return b.StateAndHeaderByNumber(ctx, blockNr) } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 7017b8c010..6ebd22ddaf 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -37,10 +37,6 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -type StateReleaseFunc func() - -var NoOpStateRelease StateReleaseFunc = func() {} - // Backend interface provides the common API services (that are provided by // both full and light clients) with access to necessary functions. type Backend interface { @@ -70,8 +66,8 @@ type Backend interface { BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) - StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, StateReleaseFunc, error) - StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, StateReleaseFunc, error) + StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) + StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) PendingBlockAndReceipts() (*types.Block, types.Receipts) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetTd(ctx context.Context, hash common.Hash) *big.Int diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index bc75c3dc12..ba5dd3977f 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -291,11 +291,11 @@ func (b *backendMock) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc func (b *backendMock) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { return nil, nil } -func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, StateReleaseFunc, error) { - return nil, nil, NoOpStateRelease, nil +func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { + return nil, nil, nil } -func (b *backendMock) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, StateReleaseFunc, error) { - return nil, nil, NoOpStateRelease, nil +func (b *backendMock) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { + return nil, nil, nil } func (b *backendMock) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return nil, nil } func (b *backendMock) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { diff --git a/les/api_backend.go b/les/api_backend.go index 323c97a9c3..1ac58f9380 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -138,7 +137,7 @@ func (b *LesApiBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) return nil, nil } -func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) { +func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { header, err := b.HeaderByNumber(ctx, number) if err != nil { return nil, nil, nil, err @@ -146,24 +145,24 @@ func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B if header == nil { return nil, nil, nil, errors.New("header not found") } - return light.NewState(ctx, header, b.eth.odr), header, ethapi.NoOpStateRelease, nil + return light.NewState(ctx, header, b.eth.odr), header, nil } -func (b *LesApiBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) { +func (b *LesApiBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { if blockNr, ok := blockNrOrHash.Number(); ok { return b.StateAndHeaderByNumber(ctx, blockNr) } if hash, ok := blockNrOrHash.Hash(); ok { header := b.eth.blockchain.GetHeaderByHash(hash) if header == nil { - return nil, nil, nil, errors.New("header for hash not found") + return nil, nil, errors.New("header for hash not found") } if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash { - return nil, nil, nil, errors.New("hash is not currently canonical") + return nil, nil, errors.New("hash is not currently canonical") } - return light.NewState(ctx, header, b.eth.odr), header, ethapi.NoOpStateRelease, nil + return light.NewState(ctx, header, b.eth.odr), header, nil } - return nil, nil, nil, errors.New("invalid arguments; neither block nor hash specified") + return nil, nil, errors.New("invalid arguments; neither block nor hash specified") } func (b *LesApiBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {