Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
a966425a
Unverified
Commit
a966425a
authored
Jul 09, 2019
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: kill off managed state, use own tiny noncer for txpool
parent
5873c01c
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
77 additions
and
289 deletions
+77
-289
managed_state.go
core/state/managed_state.go
+0
-143
managed_state_test.go
core/state/managed_state_test.go
+0
-123
tx_noncer.go
core/tx_noncer.go
+53
-0
tx_pool.go
core/tx_pool.go
+18
-17
tx_pool_test.go
core/tx_pool_test.go
+5
-5
api_backend.go
eth/api_backend.go
+1
-1
No files found.
core/state/managed_state.go
deleted
100644 → 0
View file @
5873c01c
// 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
}
}
core/state/managed_state_test.go
deleted
100644 → 0
View file @
5873c01c
// 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
))
}
}
core/tx_noncer.go
0 → 100644
View file @
a966425a
// 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
}
core/tx_pool.go
View file @
a966425a
...
...
@@ -217,9 +217,9 @@ type TxPool struct {
signer
types
.
Signer
mu
sync
.
RWMutex
currentState
*
state
.
StateDB
// Current state in the blockchain head
pending
State
*
state
.
ManagedState
// Pending state tracking virtual nonces
currentMaxGas
uint64
// Current gas limit for transaction caps
currentState
*
state
.
StateDB
// Current state in the blockchain head
pending
Nonces
*
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
.
pending
State
return
pool
.
pending
Nonces
.
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
.
pending
State
.
SetNonce
(
addr
,
tx
.
Nonce
()
+
1
)
pool
.
pending
Nonces
.
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
.
pending
State
.
GetNonce
(
addr
)
>
nonce
{
pool
.
pending
State
.
SetNonce
(
addr
,
nonce
)
if
nonce
:=
tx
.
Nonce
();
pool
.
pending
Nonces
.
get
(
addr
)
>
nonce
{
pool
.
pending
Nonces
.
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
.
pending
State
.
GetNonce
(
addr
))
events
[
addr
]
.
Forward
(
pool
.
pending
Nonces
.
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
.
pending
State
.
SetNonce
(
addr
,
txs
[
len
(
txs
)
-
1
]
.
Nonce
()
+
1
)
pool
.
pending
Nonces
.
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
.
pending
State
=
state
.
ManageState
(
statedb
)
pool
.
pending
Nonces
=
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
.
pending
State
.
GetNonce
(
addr
))
readies
:=
list
.
Ready
(
pool
.
pending
Nonces
.
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
.
pending
State
.
GetNonce
(
offenders
[
i
])
>
nonce
{
pool
.
pending
State
.
SetNonce
(
offenders
[
i
],
nonce
)
if
nonce
:=
tx
.
Nonce
();
pool
.
pending
Nonces
.
get
(
offenders
[
i
])
>
nonce
{
pool
.
pending
Nonces
.
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
.
pending
State
.
GetNonce
(
addr
)
>
nonce
{
pool
.
pending
State
.
SetNonce
(
addr
,
nonce
)
if
nonce
:=
tx
.
Nonce
();
pool
.
pending
Nonces
.
get
(
addr
)
>
nonce
{
pool
.
pending
Nonces
.
set
(
addr
,
nonce
)
}
log
.
Trace
(
"Removed fairness-exceeding pending transaction"
,
"hash"
,
hash
)
}
...
...
core/tx_pool_test.go
View file @
a966425a
...
...
@@ -109,7 +109,7 @@ func validateTxPoolInternals(pool *TxPool) error {
last
=
nonce
}
}
if
nonce
:=
pool
.
pendingState
.
Get
Nonce
(
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
()
.
Get
Nonce
(
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
()
.
Get
Nonce
(
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
()
.
Get
Nonce
(
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
.
Get
Nonce
(
addr
);
fn
!=
n
-
1
{
if
fn
:=
pool
.
Nonce
(
addr
);
fn
!=
n
-
1
{
t
.
Errorf
(
"expected nonce to be %d, got %d"
,
n
-
1
,
fn
)
}
}
...
...
eth/api_backend.go
View file @
a966425a
...
...
@@ -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
()
.
Get
Nonce
(
addr
),
nil
return
b
.
eth
.
txPool
.
Nonce
(
addr
),
nil
}
func
(
b
*
EthAPIBackend
)
Stats
()
(
pending
int
,
queued
int
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment