core: kill off managed state, use own tiny noncer for txpool
This commit is contained in:
		
							parent
							
								
									5873c01c3d
								
							
						
					
					
						commit
						a966425a1d
					
				| @ -1,143 +0,0 @@ | ||||
| // Copyright 2015 The go-ethereum Authors
 | ||||
| // This file is part of the go-ethereum library.
 | ||||
| //
 | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU Lesser General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| //
 | ||||
| // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU Lesser General Public License for more details.
 | ||||
| //
 | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package state | ||||
| 
 | ||||
| import ( | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| ) | ||||
| 
 | ||||
| type account struct { | ||||
| 	stateObject *stateObject | ||||
| 	nstart      uint64 | ||||
| 	nonces      []bool | ||||
| } | ||||
| 
 | ||||
| type ManagedState struct { | ||||
| 	*StateDB | ||||
| 
 | ||||
| 	mu sync.RWMutex | ||||
| 
 | ||||
| 	accounts map[common.Address]*account | ||||
| } | ||||
| 
 | ||||
| // ManagedState returns a new managed state with the statedb as it's backing layer
 | ||||
| func ManageState(statedb *StateDB) *ManagedState { | ||||
| 	return &ManagedState{ | ||||
| 		StateDB:  statedb.Copy(), | ||||
| 		accounts: make(map[common.Address]*account), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // SetState sets the backing layer of the managed state
 | ||||
| func (ms *ManagedState) SetState(statedb *StateDB) { | ||||
| 	ms.mu.Lock() | ||||
| 	defer ms.mu.Unlock() | ||||
| 	ms.StateDB = statedb | ||||
| } | ||||
| 
 | ||||
| // RemoveNonce removed the nonce from the managed state and all future pending nonces
 | ||||
| func (ms *ManagedState) RemoveNonce(addr common.Address, n uint64) { | ||||
| 	if ms.hasAccount(addr) { | ||||
| 		ms.mu.Lock() | ||||
| 		defer ms.mu.Unlock() | ||||
| 
 | ||||
| 		account := ms.getAccount(addr) | ||||
| 		if n-account.nstart <= uint64(len(account.nonces)) { | ||||
| 			reslice := make([]bool, n-account.nstart) | ||||
| 			copy(reslice, account.nonces[:n-account.nstart]) | ||||
| 			account.nonces = reslice | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewNonce returns the new canonical nonce for the managed account
 | ||||
| func (ms *ManagedState) NewNonce(addr common.Address) uint64 { | ||||
| 	ms.mu.Lock() | ||||
| 	defer ms.mu.Unlock() | ||||
| 
 | ||||
| 	account := ms.getAccount(addr) | ||||
| 	for i, nonce := range account.nonces { | ||||
| 		if !nonce { | ||||
| 			return account.nstart + uint64(i) | ||||
| 		} | ||||
| 	} | ||||
| 	account.nonces = append(account.nonces, true) | ||||
| 
 | ||||
| 	return uint64(len(account.nonces)-1) + account.nstart | ||||
| } | ||||
| 
 | ||||
| // GetNonce returns the canonical nonce for the managed or unmanaged account.
 | ||||
| //
 | ||||
| // Because GetNonce mutates the DB, we must take a write lock.
 | ||||
| func (ms *ManagedState) GetNonce(addr common.Address) uint64 { | ||||
| 	ms.mu.Lock() | ||||
| 	defer ms.mu.Unlock() | ||||
| 
 | ||||
| 	if ms.hasAccount(addr) { | ||||
| 		account := ms.getAccount(addr) | ||||
| 		return uint64(len(account.nonces)) + account.nstart | ||||
| 	} else { | ||||
| 		return ms.StateDB.GetNonce(addr) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // SetNonce sets the new canonical nonce for the managed state
 | ||||
| func (ms *ManagedState) SetNonce(addr common.Address, nonce uint64) { | ||||
| 	ms.mu.Lock() | ||||
| 	defer ms.mu.Unlock() | ||||
| 
 | ||||
| 	so := ms.GetOrNewStateObject(addr) | ||||
| 	so.SetNonce(nonce) | ||||
| 
 | ||||
| 	ms.accounts[addr] = newAccount(so) | ||||
| } | ||||
| 
 | ||||
| // HasAccount returns whether the given address is managed or not
 | ||||
| func (ms *ManagedState) HasAccount(addr common.Address) bool { | ||||
| 	ms.mu.RLock() | ||||
| 	defer ms.mu.RUnlock() | ||||
| 	return ms.hasAccount(addr) | ||||
| } | ||||
| 
 | ||||
| func (ms *ManagedState) hasAccount(addr common.Address) bool { | ||||
| 	_, ok := ms.accounts[addr] | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| // populate the managed state
 | ||||
| func (ms *ManagedState) getAccount(addr common.Address) *account { | ||||
| 	if account, ok := ms.accounts[addr]; !ok { | ||||
| 		so := ms.GetOrNewStateObject(addr) | ||||
| 		ms.accounts[addr] = newAccount(so) | ||||
| 	} else { | ||||
| 		// Always make sure the state account nonce isn't actually higher
 | ||||
| 		// than the tracked one.
 | ||||
| 		so := ms.StateDB.getStateObject(addr) | ||||
| 		if so != nil && uint64(len(account.nonces))+account.nstart < so.Nonce() { | ||||
| 			ms.accounts[addr] = newAccount(so) | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	return ms.accounts[addr] | ||||
| } | ||||
| 
 | ||||
| func newAccount(so *stateObject) *account { | ||||
| 	return &account{so, so.Nonce(), nil} | ||||
| } | ||||
| @ -1,123 +0,0 @@ | ||||
| // Copyright 2015 The go-ethereum Authors
 | ||||
| // This file is part of the go-ethereum library.
 | ||||
| //
 | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU Lesser General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| //
 | ||||
| // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU Lesser General Public License for more details.
 | ||||
| //
 | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package state | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core/rawdb" | ||||
| ) | ||||
| 
 | ||||
| var addr = common.BytesToAddress([]byte("test")) | ||||
| 
 | ||||
| func create() (*ManagedState, *account) { | ||||
| 	statedb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) | ||||
| 	ms := ManageState(statedb) | ||||
| 	ms.StateDB.SetNonce(addr, 100) | ||||
| 	ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr)) | ||||
| 	return ms, ms.accounts[addr] | ||||
| } | ||||
| 
 | ||||
| func TestNewNonce(t *testing.T) { | ||||
| 	ms, _ := create() | ||||
| 
 | ||||
| 	nonce := ms.NewNonce(addr) | ||||
| 	if nonce != 100 { | ||||
| 		t.Error("expected nonce 100. got", nonce) | ||||
| 	} | ||||
| 
 | ||||
| 	nonce = ms.NewNonce(addr) | ||||
| 	if nonce != 101 { | ||||
| 		t.Error("expected nonce 101. got", nonce) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestRemove(t *testing.T) { | ||||
| 	ms, account := create() | ||||
| 
 | ||||
| 	nn := make([]bool, 10) | ||||
| 	for i := range nn { | ||||
| 		nn[i] = true | ||||
| 	} | ||||
| 	account.nonces = append(account.nonces, nn...) | ||||
| 
 | ||||
| 	i := uint64(5) | ||||
| 	ms.RemoveNonce(addr, account.nstart+i) | ||||
| 	if len(account.nonces) != 5 { | ||||
| 		t.Error("expected", i, "'th index to be false") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestReuse(t *testing.T) { | ||||
| 	ms, account := create() | ||||
| 
 | ||||
| 	nn := make([]bool, 10) | ||||
| 	for i := range nn { | ||||
| 		nn[i] = true | ||||
| 	} | ||||
| 	account.nonces = append(account.nonces, nn...) | ||||
| 
 | ||||
| 	i := uint64(5) | ||||
| 	ms.RemoveNonce(addr, account.nstart+i) | ||||
| 	nonce := ms.NewNonce(addr) | ||||
| 	if nonce != 105 { | ||||
| 		t.Error("expected nonce to be 105. got", nonce) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestRemoteNonceChange(t *testing.T) { | ||||
| 	ms, account := create() | ||||
| 	nn := make([]bool, 10) | ||||
| 	for i := range nn { | ||||
| 		nn[i] = true | ||||
| 	} | ||||
| 	account.nonces = append(account.nonces, nn...) | ||||
| 	ms.NewNonce(addr) | ||||
| 
 | ||||
| 	ms.StateDB.stateObjects[addr].data.Nonce = 200 | ||||
| 	nonce := ms.NewNonce(addr) | ||||
| 	if nonce != 200 { | ||||
| 		t.Error("expected nonce after remote update to be", 200, "got", nonce) | ||||
| 	} | ||||
| 	ms.NewNonce(addr) | ||||
| 	ms.NewNonce(addr) | ||||
| 	ms.NewNonce(addr) | ||||
| 	ms.StateDB.stateObjects[addr].data.Nonce = 200 | ||||
| 	nonce = ms.NewNonce(addr) | ||||
| 	if nonce != 204 { | ||||
| 		t.Error("expected nonce after remote update to be", 204, "got", nonce) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestSetNonce(t *testing.T) { | ||||
| 	ms, _ := create() | ||||
| 
 | ||||
| 	var addr common.Address | ||||
| 	ms.SetNonce(addr, 10) | ||||
| 
 | ||||
| 	if ms.GetNonce(addr) != 10 { | ||||
| 		t.Error("Expected nonce of 10, got", ms.GetNonce(addr)) | ||||
| 	} | ||||
| 
 | ||||
| 	addr[0] = 1 | ||||
| 	ms.StateDB.SetNonce(addr, 1) | ||||
| 
 | ||||
| 	if ms.GetNonce(addr) != 1 { | ||||
| 		t.Error("Expected nonce of 1, got", ms.GetNonce(addr)) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										53
									
								
								core/tx_noncer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								core/tx_noncer.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| // Copyright 2019 The go-ethereum Authors
 | ||||
| // This file is part of the go-ethereum library.
 | ||||
| //
 | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU Lesser General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| //
 | ||||
| // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU Lesser General Public License for more details.
 | ||||
| //
 | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package core | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core/state" | ||||
| ) | ||||
| 
 | ||||
| // txNoncer is a tiny virtual state database to manage the executable nonces of
 | ||||
| // accounts in the pool, falling back to reading from a real state database if
 | ||||
| // an account is unknown.
 | ||||
| type txNoncer struct { | ||||
| 	fallback *state.StateDB | ||||
| 	nonces   map[common.Address]uint64 | ||||
| } | ||||
| 
 | ||||
| // newTxNoncer creates a new virtual state database to track the pool nonces.
 | ||||
| func newTxNoncer(statedb *state.StateDB) *txNoncer { | ||||
| 	return &txNoncer{ | ||||
| 		fallback: statedb.Copy(), | ||||
| 		nonces:   make(map[common.Address]uint64), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // get returns the current nonce of an account, falling back to a real state
 | ||||
| // database if the account is unknown.
 | ||||
| func (txn *txNoncer) get(addr common.Address) uint64 { | ||||
| 	if _, ok := txn.nonces[addr]; !ok { | ||||
| 		txn.nonces[addr] = txn.fallback.GetNonce(addr) | ||||
| 	} | ||||
| 	return txn.nonces[addr] | ||||
| } | ||||
| 
 | ||||
| // set inserts a new virtual nonce into the virtual state database to be returned
 | ||||
| // whenever the pool requests it instead of reaching into the real state database.
 | ||||
| func (txn *txNoncer) set(addr common.Address, nonce uint64) { | ||||
| 	txn.nonces[addr] = nonce | ||||
| } | ||||
| @ -217,9 +217,9 @@ type TxPool struct { | ||||
| 	signer      types.Signer | ||||
| 	mu          sync.RWMutex | ||||
| 
 | ||||
| 	currentState  *state.StateDB      // Current state in the blockchain head
 | ||||
| 	pendingState  *state.ManagedState // Pending state tracking virtual nonces
 | ||||
| 	currentMaxGas uint64              // Current gas limit for transaction caps
 | ||||
| 	currentState  *state.StateDB // Current state in the blockchain head
 | ||||
| 	pendingNonces *txNoncer      // Pending state tracking virtual nonces
 | ||||
| 	currentMaxGas uint64         // Current gas limit for transaction caps
 | ||||
| 
 | ||||
| 	locals  *accountSet // Set of local transaction to exempt from eviction rules
 | ||||
| 	journal *txJournal  // Journal of local transaction to back up to disk
 | ||||
| @ -417,12 +417,13 @@ func (pool *TxPool) SetGasPrice(price *big.Int) { | ||||
| 	log.Info("Transaction pool price threshold updated", "price", price) | ||||
| } | ||||
| 
 | ||||
| // State returns the virtual managed state of the transaction pool.
 | ||||
| func (pool *TxPool) State() *state.ManagedState { | ||||
| // Nonce returns the next nonce of an account, with all transactions executable
 | ||||
| // by the pool already applied on top.
 | ||||
| func (pool *TxPool) Nonce(addr common.Address) uint64 { | ||||
| 	pool.mu.RLock() | ||||
| 	defer pool.mu.RUnlock() | ||||
| 
 | ||||
| 	return pool.pendingState | ||||
| 	return pool.pendingNonces.get(addr) | ||||
| } | ||||
| 
 | ||||
| // Stats retrieves the current pool stats, namely the number of pending and the
 | ||||
| @ -713,7 +714,7 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T | ||||
| 	} | ||||
| 	// Set the potentially new pending nonce and notify any subsystems of the new tx
 | ||||
| 	pool.beats[addr] = time.Now() | ||||
| 	pool.pendingState.SetNonce(addr, tx.Nonce()+1) | ||||
| 	pool.pendingNonces.set(addr, tx.Nonce()+1) | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| @ -853,8 +854,8 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { | ||||
| 				pool.enqueueTx(tx.Hash(), tx) | ||||
| 			} | ||||
| 			// Update the account nonce if needed
 | ||||
| 			if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { | ||||
| 				pool.pendingState.SetNonce(addr, nonce) | ||||
| 			if nonce := tx.Nonce(); pool.pendingNonces.get(addr) > nonce { | ||||
| 				pool.pendingNonces.set(addr, nonce) | ||||
| 			} | ||||
| 			// Reduce the pending counter
 | ||||
| 			pendingCounter.Dec(int64(1 + len(invalids))) | ||||
| @ -990,7 +991,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt | ||||
| 
 | ||||
| 		// Nonces were reset, discard any events that became stale
 | ||||
| 		for addr := range events { | ||||
| 			events[addr].Forward(pool.pendingState.GetNonce(addr)) | ||||
| 			events[addr].Forward(pool.pendingNonces.get(addr)) | ||||
| 			if events[addr].Len() == 0 { | ||||
| 				delete(events, addr) | ||||
| 			} | ||||
| @ -1023,7 +1024,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt | ||||
| 	// Update all accounts to the latest known pending nonce
 | ||||
| 	for addr, list := range pool.pending { | ||||
| 		txs := list.Flatten() // Heavy but will be cached and is needed by the miner anyway
 | ||||
| 		pool.pendingState.SetNonce(addr, txs[len(txs)-1].Nonce()+1) | ||||
| 		pool.pendingNonces.set(addr, txs[len(txs)-1].Nonce()+1) | ||||
| 	} | ||||
| 	pool.mu.Unlock() | ||||
| 
 | ||||
| @ -1112,7 +1113,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { | ||||
| 		return | ||||
| 	} | ||||
| 	pool.currentState = statedb | ||||
| 	pool.pendingState = state.ManageState(statedb) | ||||
| 	pool.pendingNonces = newTxNoncer(statedb) | ||||
| 	pool.currentMaxGas = newHead.GasLimit | ||||
| 
 | ||||
| 	// Inject any transactions discarded due to reorgs
 | ||||
| @ -1151,7 +1152,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans | ||||
| 		queuedNofundsMeter.Mark(int64(len(drops))) | ||||
| 
 | ||||
| 		// Gather all executable transactions and promote them
 | ||||
| 		readies := list.Ready(pool.pendingState.GetNonce(addr)) | ||||
| 		readies := list.Ready(pool.pendingNonces.get(addr)) | ||||
| 		for _, tx := range readies { | ||||
| 			hash := tx.Hash() | ||||
| 			if pool.promoteTx(addr, hash, tx) { | ||||
| @ -1231,8 +1232,8 @@ func (pool *TxPool) truncatePending() { | ||||
| 						pool.all.Remove(hash) | ||||
| 
 | ||||
| 						// Update the account nonce to the dropped transaction
 | ||||
| 						if nonce := tx.Nonce(); pool.pendingState.GetNonce(offenders[i]) > nonce { | ||||
| 							pool.pendingState.SetNonce(offenders[i], nonce) | ||||
| 						if nonce := tx.Nonce(); pool.pendingNonces.get(offenders[i]) > nonce { | ||||
| 							pool.pendingNonces.set(offenders[i], nonce) | ||||
| 						} | ||||
| 						log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) | ||||
| 					} | ||||
| @ -1260,8 +1261,8 @@ func (pool *TxPool) truncatePending() { | ||||
| 					pool.all.Remove(hash) | ||||
| 
 | ||||
| 					// Update the account nonce to the dropped transaction
 | ||||
| 					if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { | ||||
| 						pool.pendingState.SetNonce(addr, nonce) | ||||
| 					if nonce := tx.Nonce(); pool.pendingNonces.get(addr) > nonce { | ||||
| 						pool.pendingNonces.set(addr, nonce) | ||||
| 					} | ||||
| 					log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) | ||||
| 				} | ||||
|  | ||||
| @ -109,7 +109,7 @@ func validateTxPoolInternals(pool *TxPool) error { | ||||
| 				last = nonce | ||||
| 			} | ||||
| 		} | ||||
| 		if nonce := pool.pendingState.GetNonce(addr); nonce != last+1 { | ||||
| 		if nonce := pool.Nonce(addr); nonce != last+1 { | ||||
| 			return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1) | ||||
| 		} | ||||
| 	} | ||||
| @ -195,14 +195,14 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { | ||||
| 	pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) | ||||
| 	defer pool.Stop() | ||||
| 
 | ||||
| 	nonce := pool.State().GetNonce(address) | ||||
| 	nonce := pool.Nonce(address) | ||||
| 	if nonce != 0 { | ||||
| 		t.Fatalf("Invalid nonce, want 0, got %d", nonce) | ||||
| 	} | ||||
| 
 | ||||
| 	pool.addRemotesSync([]*types.Transaction{tx0, tx1}) | ||||
| 
 | ||||
| 	nonce = pool.State().GetNonce(address) | ||||
| 	nonce = pool.Nonce(address) | ||||
| 	if nonce != 2 { | ||||
| 		t.Fatalf("Invalid nonce, want 2, got %d", nonce) | ||||
| 	} | ||||
| @ -215,7 +215,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Could not fetch pending transactions: %v", err) | ||||
| 	} | ||||
| 	nonce = pool.State().GetNonce(address) | ||||
| 	nonce = pool.Nonce(address) | ||||
| 	if nonce != 2 { | ||||
| 		t.Fatalf("Invalid nonce, want 2, got %d", nonce) | ||||
| 	} | ||||
| @ -451,7 +451,7 @@ func TestTransactionNonceRecovery(t *testing.T) { | ||||
| 	// simulate some weird re-order of transactions and missing nonce(s)
 | ||||
| 	pool.currentState.SetNonce(addr, n-1) | ||||
| 	<-pool.requestReset(nil, nil) | ||||
| 	if fn := pool.pendingState.GetNonce(addr); fn != n-1 { | ||||
| 	if fn := pool.Nonce(addr); fn != n-1 { | ||||
| 		t.Errorf("expected nonce to be %d, got %d", n-1, fn) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -185,7 +185,7 @@ func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) | ||||
| } | ||||
| 
 | ||||
| func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { | ||||
| 	return b.eth.txPool.State().GetNonce(addr), nil | ||||
| 	return b.eth.txPool.Nonce(addr), nil | ||||
| } | ||||
| 
 | ||||
| func (b *EthAPIBackend) Stats() (pending int, queued int) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user