Skip to content

Commit 814e540

Browse files
committed
use finalizer instead of returning state release function
1 parent 8d5951a commit 814e540

File tree

9 files changed

+83
-83
lines changed

9 files changed

+83
-83
lines changed

arbitrum/apibackend.go

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"math/big"
8+
"runtime"
89
"strconv"
910
"strings"
1011
"time"
@@ -229,11 +230,10 @@ func (a *APIBackend) FeeHistory(
229230

230231
// use the most recent average compute rate for all blocks
231232
// note: while we could query this value for each block, it'd be prohibitively expensive
232-
state, _, release, err := a.StateAndHeaderByNumber(ctx, newestBlock)
233+
state, _, err := a.StateAndHeaderByNumber(ctx, newestBlock)
233234
if err != nil {
234235
return common.Big0, nil, nil, nil, err
235236
}
236-
defer release()
237237
speedLimit, err := core.GetArbOSSpeedLimitPerSecond(state)
238238
if err != nil {
239239
return common.Big0, nil, nil, nil, err
@@ -434,59 +434,77 @@ func (a *APIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.
434434
return nil, errors.New("invalid arguments; neither block nor hash specified")
435435
}
436436

437-
func (a *APIBackend) stateAndHeaderFromHeader(ctx context.Context, header *types.Header, err error) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) {
437+
func (a *APIBackend) stateAndHeaderFromHeader(ctx context.Context, header *types.Header, err error) (*state.StateDB, *types.Header, error) {
438438
if err != nil {
439-
return nil, header, nil, err
439+
return nil, header, err
440440
}
441441
if header == nil {
442-
return nil, nil, nil, errors.New("header not found")
442+
return nil, nil, errors.New("header not found")
443443
}
444444
if !a.BlockChain().Config().IsArbitrumNitro(header.Number) {
445-
return nil, header, nil, types.ErrUseFallback
445+
return nil, header, types.ErrUseFallback
446446
}
447447
bc := a.BlockChain()
448448
stateFor := func(header *types.Header) (*state.StateDB, error) {
449449
if header.Root != (common.Hash{}) {
450450
// Try referencing the root, if it isn't in dirties cache then Reference will have no effect
451451
bc.StateCache().TrieDB().Reference(header.Root, common.Hash{})
452452
}
453-
state, err := bc.StateAt(header.Root)
454-
return state, err
453+
statedb, err := state.New(header.Root, bc.StateCache(), bc.Snapshots())
454+
if err != nil {
455+
return nil, err
456+
}
457+
if header.Root != (common.Hash{}) {
458+
// we are setting finalizer instead of returning a StateReleaseFunc to avoid changing ethapi.Backend interface to minimize diff to upstream
459+
headerRoot := header.Root
460+
runtime.SetFinalizer(statedb, func(_ *state.StateDB) {
461+
bc.StateCache().TrieDB().Dereference(headerRoot)
462+
})
463+
}
464+
return statedb, err
455465
}
456466
lastState, lastHeader, err := FindLastAvailableState(ctx, bc, stateFor, header, nil, a.b.config.MaxRecreateStateDepth)
457467
if err != nil {
458-
return nil, nil, nil, err
459-
}
460-
release := func() {
461-
if lastHeader.Root != (common.Hash{}) {
462-
bc.StateCache().TrieDB().Dereference(lastHeader.Root)
463-
}
468+
return nil, nil, err
464469
}
465470
if lastHeader == header {
466-
return lastState, header, release, nil
471+
return lastState, header, nil
472+
}
473+
if lastHeader.Root != (common.Hash{}) {
474+
defer bc.StateCache().TrieDB().Dereference(lastHeader.Root)
467475
}
468-
defer release()
469476
targetBlock := bc.GetBlockByNumber(header.Number.Uint64())
470477
if targetBlock == nil {
471-
return nil, nil, nil, errors.New("target block not found")
478+
return nil, nil, errors.New("target block not found")
472479
}
473480
lastBlock := bc.GetBlockByNumber(lastHeader.Number.Uint64())
474481
if lastBlock == nil {
475-
return nil, nil, nil, errors.New("last block not found")
482+
return nil, nil, errors.New("last block not found")
476483
}
477484
reexec := uint64(0)
478485
checkLive := false
479486
preferDisk := true
480-
state, release, err := eth.NewArbEthereum(a.b.arb.BlockChain(), a.ChainDb()).StateAtBlock(ctx, targetBlock, reexec, lastState, lastBlock, checkLive, preferDisk)
481-
return state, header, release, err
487+
statedb, release, err := eth.NewArbEthereum(a.b.arb.BlockChain(), a.ChainDb()).StateAtBlock(ctx, targetBlock, reexec, lastState, lastBlock, checkLive, preferDisk)
488+
if err != nil {
489+
return nil, nil, err
490+
}
491+
// we are setting finalizer instead of returning a StateReleaseFunc to avoid changing ethapi.Backend interface to minimize diff to upstream
492+
// to set a finalizer we need to allocated the obj in current block
493+
statedb, err = state.New(header.Root, statedb.Database(), nil)
494+
if header.Root != (common.Hash{}) {
495+
runtime.SetFinalizer(statedb, func(_ *state.StateDB) {
496+
release()
497+
})
498+
}
499+
return statedb, header, err
482500
}
483501

484-
func (a *APIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) {
502+
func (a *APIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
485503
header, err := a.HeaderByNumber(ctx, number)
486504
return a.stateAndHeaderFromHeader(ctx, header, err)
487505
}
488506

489-
func (a *APIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) {
507+
func (a *APIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
490508
header, err := a.HeaderByNumberOrHash(ctx, blockNrOrHash)
491509
return a.stateAndHeaderFromHeader(ctx, header, err)
492510
}

eth/api_backend.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import (
3737
"github.com/ethereum/go-ethereum/eth/tracers"
3838
"github.com/ethereum/go-ethereum/ethdb"
3939
"github.com/ethereum/go-ethereum/event"
40-
"github.com/ethereum/go-ethereum/internal/ethapi"
4140
"github.com/ethereum/go-ethereum/miner"
4241
"github.com/ethereum/go-ethereum/params"
4342
"github.com/ethereum/go-ethereum/rpc"
@@ -199,46 +198,46 @@ func (b *EthAPIBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts)
199198
return b.eth.miner.PendingBlockAndReceipts()
200199
}
201200

202-
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) {
201+
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
203202
// Pending state is only known by the miner
204203
if number == rpc.PendingBlockNumber {
205204
block, state := b.eth.miner.Pending()
206205
if block == nil || state == nil {
207-
return nil, nil, nil, errors.New("pending state is not available")
206+
return nil, nil, errors.New("pending state is not available")
208207
}
209-
return state, block.Header(), ethapi.NoOpStateRelease, nil
208+
return state, block.Header(), nil
210209
}
211210
// Otherwise resolve the block number and return its state
212211
header, err := b.HeaderByNumber(ctx, number)
213212
if err != nil {
214-
return nil, nil, nil, err
213+
return nil, nil, err
215214
}
216215
if header == nil {
217-
return nil, nil, nil, errors.New("header not found")
216+
return nil, nil, errors.New("header not found")
218217
}
219218
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
220-
return stateDb, header, ethapi.NoOpStateRelease, err
219+
return stateDb, header, err
221220
}
222221

223-
func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, ethapi.StateReleaseFunc, error) {
222+
func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
224223
if blockNr, ok := blockNrOrHash.Number(); ok {
225224
return b.StateAndHeaderByNumber(ctx, blockNr)
226225
}
227226
if hash, ok := blockNrOrHash.Hash(); ok {
228227
header, err := b.HeaderByHash(ctx, hash)
229228
if err != nil {
230-
return nil, nil, nil, err
229+
return nil, nil, err
231230
}
232231
if header == nil {
233-
return nil, nil, nil, errors.New("header for hash not found")
232+
return nil, nil, errors.New("header for hash not found")
234233
}
235234
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
236-
return nil, nil, nil, errors.New("hash is not currently canonical")
235+
return nil, nil, errors.New("hash is not currently canonical")
237236
}
238237
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
239-
return stateDb, header, ethapi.NoOpStateRelease, err
238+
return stateDb, header, err
240239
}
241-
return nil, nil, nil, errors.New("invalid arguments; neither block nor hash specified")
240+
return nil, nil, errors.New("invalid arguments; neither block nor hash specified")
242241
}
243242

244243
func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {

eth/catalyst/api_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,11 +1143,10 @@ func TestWithdrawals(t *testing.T) {
11431143
}
11441144

11451145
// 11: verify withdrawals were processed.
1146-
db, _, release, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number))
1146+
db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number))
11471147
if err != nil {
11481148
t.Fatalf("unable to load db: %v", err)
11491149
}
1150-
defer release()
11511150
for i, w := range blockParams.Withdrawals {
11521151
// w.Amount is in gwei, balance in wei
11531152
if db.GetBalance(w.Address).Uint64() != w.Amount*params.GWei {

graphql/graphql.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,20 @@ type Account struct {
8686
}
8787

8888
// getState fetches the StateDB object for an account.
89-
func (a *Account) getState(ctx context.Context) (*state.StateDB, ethapi.StateReleaseFunc, error) {
90-
state, _, release, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash)
91-
return state, release, err
89+
func (a *Account) getState(ctx context.Context) (*state.StateDB, error) {
90+
state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash)
91+
return state, err
9292
}
9393

9494
func (a *Account) Address(ctx context.Context) (common.Address, error) {
9595
return a.address, nil
9696
}
9797

9898
func (a *Account) Balance(ctx context.Context) (hexutil.Big, error) {
99-
state, release, err := a.getState(ctx)
99+
state, err := a.getState(ctx)
100100
if err != nil {
101101
return hexutil.Big{}, err
102102
}
103-
defer release()
104103
balance := state.GetBalance(a.address)
105104
if balance == nil {
106105
return hexutil.Big{}, fmt.Errorf("failed to load balance %x", a.address)

internal/ethapi/api.go

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ func (s *BlockChainAPI) BlockNumber() hexutil.Uint64 {
620620
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
621621
// block numbers are also allowed.
622622
func (s *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
623-
state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
623+
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
624624
if state == nil || err != nil {
625625
if client := fallbackClientFor(s.b, err); client != nil {
626626
var res hexutil.Big
@@ -629,7 +629,6 @@ func (s *BlockChainAPI) GetBalance(ctx context.Context, address common.Address,
629629
}
630630
return nil, err
631631
}
632-
defer release()
633632
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
634633
}
635634

@@ -682,11 +681,10 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
682681
}
683682
}
684683

685-
state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
684+
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
686685
if state == nil || err != nil {
687686
return nil, err
688687
}
689-
defer release()
690688
if storageTrie, err = state.StorageTrie(address); err != nil {
691689
return nil, err
692690
}
@@ -869,7 +867,7 @@ func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash
869867

870868
// GetCode returns the code stored at the given address in the state for the given block number.
871869
func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
872-
state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
870+
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
873871
if state == nil || err != nil {
874872
if client := fallbackClientFor(s.b, err); client != nil {
875873
var res hexutil.Bytes
@@ -878,7 +876,6 @@ func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blo
878876
}
879877
return nil, err
880878
}
881-
defer release()
882879
code := state.GetCode(address)
883880
return code, state.Error()
884881
}
@@ -891,7 +888,7 @@ func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address
891888
if err != nil {
892889
return nil, fmt.Errorf("unable to decode storage key: %s", err)
893890
}
894-
state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
891+
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
895892
if state == nil || err != nil {
896893
if client := fallbackClientFor(s.b, err); client != nil {
897894
var res hexutil.Bytes
@@ -900,7 +897,6 @@ func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address
900897
}
901898
return nil, err
902899
}
903-
defer release()
904900
res := state.GetState(address, key)
905901
return res[:], state.Error()
906902
}
@@ -1129,11 +1125,10 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
11291125
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) {
11301126
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
11311127

1132-
state, header, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
1128+
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
11331129
if state == nil || err != nil {
11341130
return nil, err
11351131
}
1136-
defer release()
11371132

11381133
return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap, runMode)
11391134
}
@@ -1237,11 +1232,10 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
12371232
}
12381233
// Recap the highest gas limit with account's available balance.
12391234
if feeCap.BitLen() != 0 {
1240-
state, _, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
1235+
state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
12411236
if err != nil {
12421237
return 0, err
12431238
}
1244-
defer release()
12451239
err = overrides.Apply(state)
12461240
if err != nil {
12471241
return 0, err
@@ -1271,11 +1265,10 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
12711265
// Arbitrum: raise the gas cap to ignore L1 costs so that it's compute-only
12721266
vanillaGasCap := gasCap
12731267
{
1274-
state, header, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
1268+
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
12751269
if state == nil || err != nil {
12761270
return 0, err
12771271
}
1278-
defer release()
12791272
gasCap, err = args.L2OnlyGasCap(gasCap, header, state, core.MessageGasEstimationMode)
12801273
if err != nil {
12811274
return 0, err
@@ -1302,11 +1295,10 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
13021295
}
13031296
return result.Failed(), result, nil
13041297
}
1305-
state, header, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
1298+
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
13061299
if state == nil || err != nil {
13071300
return 0, err
13081301
}
1309-
defer release()
13101302
err = overrides.Apply(state)
13111303
if err != nil {
13121304
return 0, err
@@ -1703,11 +1695,10 @@ func (s *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionAr
17031695
// If the transaction itself fails, an vmErr is returned.
17041696
func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs) (acl types.AccessList, gasUsed uint64, vmErr error, err error) {
17051697
// Retrieve the execution context
1706-
db, header, release, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
1698+
db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
17071699
if db == nil || err != nil {
17081700
return nil, 0, nil, err
17091701
}
1710-
defer release()
17111702
// If the gas amount is not set, default to RPC gas cap.
17121703
if args.Gas == nil {
17131704
tmp := hexutil.Uint64(b.RPCGasCap())
@@ -1838,7 +1829,7 @@ func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common
18381829
return (*hexutil.Uint64)(&nonce), nil
18391830
}
18401831
// Resolve block number and use its state to ask for the nonce
1841-
state, _, release, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
1832+
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
18421833
if state == nil || err != nil {
18431834
if client := fallbackClientFor(s.b, err); client != nil {
18441835
var res hexutil.Uint64
@@ -1847,7 +1838,6 @@ func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common
18471838
}
18481839
return nil, err
18491840
}
1850-
defer release()
18511841
nonce := state.GetNonce(address)
18521842
return (*hexutil.Uint64)(&nonce), state.Error()
18531843
}

internal/ethapi/api_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.
437437
func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
438438
return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil
439439
}
440-
func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, StateReleaseFunc, error) {
440+
func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
441441
if number == rpc.PendingBlockNumber {
442442
panic("pending state not implemented")
443443
}
@@ -449,9 +449,9 @@ func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.Bloc
449449
return nil, nil, nil, errors.New("header not found")
450450
}
451451
stateDb, err := b.chain.StateAt(header.Root)
452-
return stateDb, header, NoOpStateRelease, err
452+
return stateDb, header, err
453453
}
454-
func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, StateReleaseFunc, error) {
454+
func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
455455
if blockNr, ok := blockNrOrHash.Number(); ok {
456456
return b.StateAndHeaderByNumber(ctx, blockNr)
457457
}

0 commit comments

Comments
 (0)