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
940e3170
Unverified
Commit
940e3170
authored
Feb 08, 2019
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: fix pruner panic when importing low-diff-large-sidechain
parent
da1efdae
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
44 additions
and
86 deletions
+44
-86
blockchain.go
core/blockchain.go
+17
-11
blockchain_test.go
core/blockchain_test.go
+25
-18
chain_makers.go
core/chain_makers.go
+2
-57
No files found.
core/blockchain.go
View file @
940e3170
...
@@ -979,11 +979,16 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
...
@@ -979,11 +979,16 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
triedb
.
Cap
(
limit
-
ethdb
.
IdealBatchSize
)
triedb
.
Cap
(
limit
-
ethdb
.
IdealBatchSize
)
}
}
// Find the next state trie we need to commit
// Find the next state trie we need to commit
header
:=
bc
.
GetHeaderByNumber
(
current
-
triesInMemory
)
chosen
:=
current
-
triesInMemory
chosen
:=
header
.
Number
.
Uint64
()
// If we exceeded out time allowance, flush an entire trie to disk
// If we exceeded out time allowance, flush an entire trie to disk
if
bc
.
gcproc
>
bc
.
cacheConfig
.
TrieTimeLimit
{
if
bc
.
gcproc
>
bc
.
cacheConfig
.
TrieTimeLimit
{
// If the header is missing (canonical chain behind), we're reorging a low
// diff sidechain. Suspend committing until this operation is completed.
header
:=
bc
.
GetHeaderByNumber
(
chosen
)
if
header
==
nil
{
log
.
Warn
(
"Reorg in progress, trie commit postponed"
,
"number"
,
chosen
)
}
else
{
// If we're exceeding limits but haven't reached a large enough memory gap,
// If we're exceeding limits but haven't reached a large enough memory gap,
// warn the user that the system is becoming unstable.
// warn the user that the system is becoming unstable.
if
chosen
<
lastWrite
+
triesInMemory
&&
bc
.
gcproc
>=
2
*
bc
.
cacheConfig
.
TrieTimeLimit
{
if
chosen
<
lastWrite
+
triesInMemory
&&
bc
.
gcproc
>=
2
*
bc
.
cacheConfig
.
TrieTimeLimit
{
...
@@ -994,6 +999,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
...
@@ -994,6 +999,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
lastWrite
=
chosen
lastWrite
=
chosen
bc
.
gcproc
=
0
bc
.
gcproc
=
0
}
}
}
// Garbage collect anything below our required write retention
// Garbage collect anything below our required write retention
for
!
bc
.
triegc
.
Empty
()
{
for
!
bc
.
triegc
.
Empty
()
{
root
,
number
:=
bc
.
triegc
.
Pop
()
root
,
number
:=
bc
.
triegc
.
Pop
()
...
@@ -1324,7 +1330,7 @@ func (bc *BlockChain) insertSidechain(block *types.Block, it *insertIterator) (i
...
@@ -1324,7 +1330,7 @@ func (bc *BlockChain) insertSidechain(block *types.Block, it *insertIterator) (i
if
err
:=
bc
.
WriteBlockWithoutState
(
block
,
externTd
);
err
!=
nil
{
if
err
:=
bc
.
WriteBlockWithoutState
(
block
,
externTd
);
err
!=
nil
{
return
it
.
index
,
nil
,
nil
,
err
return
it
.
index
,
nil
,
nil
,
err
}
}
log
.
Debug
(
"In
ser
ted sidechain block"
,
"number"
,
block
.
Number
(),
"hash"
,
block
.
Hash
(),
log
.
Debug
(
"In
jec
ted sidechain block"
,
"number"
,
block
.
Number
(),
"hash"
,
block
.
Hash
(),
"diff"
,
block
.
Difficulty
(),
"elapsed"
,
common
.
PrettyDuration
(
time
.
Since
(
start
)),
"diff"
,
block
.
Difficulty
(),
"elapsed"
,
common
.
PrettyDuration
(
time
.
Since
(
start
)),
"txs"
,
len
(
block
.
Transactions
()),
"gas"
,
block
.
GasUsed
(),
"uncles"
,
len
(
block
.
Uncles
()),
"txs"
,
len
(
block
.
Transactions
()),
"gas"
,
block
.
GasUsed
(),
"uncles"
,
len
(
block
.
Uncles
()),
"root"
,
block
.
Root
())
"root"
,
block
.
Root
())
...
...
core/blockchain_test.go
View file @
940e3170
...
@@ -1487,16 +1487,22 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
...
@@ -1487,16 +1487,22 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
// Tests that importing a very large side fork, which is larger than the canon chain,
// Tests that importing a very large side fork, which is larger than the canon chain,
// but where the difficulty per block is kept low: this means that it will not
// but where the difficulty per block is kept low: this means that it will not
// overtake the 'canon' chain until after it's passed canon by about 200 blocks.
// overtake the 'canon' chain until after it's passed canon by about 200 blocks.
func
TestLargeOldSidechainWithALowTdChain
(
t
*
testing
.
T
)
{
//
// Details at:
// - https://github.com/ethereum/go-ethereum/issues/18977
// - https://github.com/ethereum/go-ethereum/pull/18988
func
TestLowDiffLongChain
(
t
*
testing
.
T
)
{
// Generate a canonical chain to act as the main dataset
// Generate a canonical chain to act as the main dataset
engine
:=
ethash
.
NewFaker
()
engine
:=
ethash
.
NewFaker
()
db
:=
ethdb
.
NewMemDatabase
()
db
:=
ethdb
.
NewMemDatabase
()
genesis
:=
new
(
Genesis
)
.
MustCommit
(
db
)
genesis
:=
new
(
Genesis
)
.
MustCommit
(
db
)
// We must use a pretty long chain to ensure that the fork
// doesn't overtake us until after at least 128 blocks post tip
// We must use a pretty long chain to ensure that the fork doesn't overtake us
blocks
,
_
:=
generateChain
(
params
.
TestChainConfig
,
genesis
,
engine
,
db
,
6
*
triesInMemory
,
func
(
i
int
,
b
*
BlockGen
)
{
b
.
SetCoinbase
(
common
.
Address
{
1
})
},
makeHeaderWithLargeDifficulty
)
// until after at least 128 blocks post tip
blocks
,
_
:=
GenerateChain
(
params
.
TestChainConfig
,
genesis
,
engine
,
db
,
6
*
triesInMemory
,
func
(
i
int
,
b
*
BlockGen
)
{
b
.
SetCoinbase
(
common
.
Address
{
1
})
b
.
OffsetTime
(
-
9
)
})
// Import the canonical chain
// Import the canonical chain
diskdb
:=
ethdb
.
NewMemDatabase
()
diskdb
:=
ethdb
.
NewMemDatabase
()
...
@@ -1506,19 +1512,14 @@ func TestLargeOldSidechainWithALowTdChain(t *testing.T) {
...
@@ -1506,19 +1512,14 @@ func TestLargeOldSidechainWithALowTdChain(t *testing.T) {
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create tester chain: %v"
,
err
)
t
.
Fatalf
(
"failed to create tester chain: %v"
,
err
)
}
}
for
i
:=
0
;
i
<
len
(
blocks
);
i
++
{
if
n
,
err
:=
chain
.
InsertChain
(
blocks
);
err
!=
nil
{
if
_
,
err
:=
chain
.
InsertChain
(
blocks
[
i
:
i
+
1
]);
err
!=
nil
{
t
.
Fatalf
(
"block %d: failed to insert into chain: %v"
,
n
,
err
)
t
.
Fatalf
(
"block %d: failed to insert into chain: %v"
,
i
,
err
)
}
}
}
// Dereference all the recent tries and ensure no past trie is left in
for
i
:=
0
;
i
<
triesInMemory
;
i
++
{
chain
.
stateCache
.
TrieDB
()
.
Dereference
(
blocks
[
len
(
blocks
)
-
1
-
i
]
.
Root
())
}
// Generate fork chain, starting from an early block
// Generate fork chain, starting from an early block
parent
:=
blocks
[
10
]
parent
:=
blocks
[
10
]
fork
,
_
:=
generateChain
(
params
.
TestChainConfig
,
parent
,
engine
,
db
,
256
+
6
*
triesInMemory
,
func
(
i
int
,
b
*
BlockGen
)
{
b
.
SetCoinbase
(
common
.
Address
{
2
})
},
makeHeaderWithSmallDifficulty
)
fork
,
_
:=
GenerateChain
(
params
.
TestChainConfig
,
parent
,
engine
,
db
,
8
*
triesInMemory
,
func
(
i
int
,
b
*
BlockGen
)
{
b
.
SetCoinbase
(
common
.
Address
{
2
})
})
// And now import the fork
// And now import the fork
if
i
,
err
:=
chain
.
InsertChain
(
fork
);
err
!=
nil
{
if
i
,
err
:=
chain
.
InsertChain
(
fork
);
err
!=
nil
{
...
@@ -1528,6 +1529,12 @@ func TestLargeOldSidechainWithALowTdChain(t *testing.T) {
...
@@ -1528,6 +1529,12 @@ func TestLargeOldSidechainWithALowTdChain(t *testing.T) {
if
got
:=
fork
[
len
(
fork
)
-
1
]
.
Hash
();
got
!=
head
.
Hash
()
{
if
got
:=
fork
[
len
(
fork
)
-
1
]
.
Hash
();
got
!=
head
.
Hash
()
{
t
.
Fatalf
(
"head wrong, expected %x got %x"
,
head
.
Hash
(),
got
)
t
.
Fatalf
(
"head wrong, expected %x got %x"
,
head
.
Hash
(),
got
)
}
}
td
:=
chain
.
GetTd
(
head
.
Hash
(),
head
.
NumberU64
())
// Sanity check that all the canonical numbers are present
fmt
.
Printf
(
"td %v"
,
td
)
header
:=
chain
.
CurrentHeader
()
for
number
:=
head
.
NumberU64
();
number
>
0
;
number
--
{
if
hash
:=
chain
.
GetHeaderByNumber
(
number
)
.
Hash
();
hash
!=
header
.
Hash
()
{
t
.
Fatalf
(
"header %d: canonical hash mismatch: have %x, want %x"
,
number
,
hash
,
header
.
Hash
())
}
header
=
chain
.
GetHeader
(
header
.
ParentHash
,
number
-
1
)
}
}
}
core/chain_makers.go
View file @
940e3170
...
@@ -48,8 +48,6 @@ type BlockGen struct {
...
@@ -48,8 +48,6 @@ type BlockGen struct {
engine
consensus
.
Engine
engine
consensus
.
Engine
}
}
type
headerGenFn
func
(
chain
consensus
.
ChainReader
,
parent
*
types
.
Block
,
state
*
state
.
StateDB
,
engine
consensus
.
Engine
)
*
types
.
Header
// SetCoinbase sets the coinbase of the generated block.
// SetCoinbase sets the coinbase of the generated block.
// It can be called at most once.
// It can be called at most once.
func
(
b
*
BlockGen
)
SetCoinbase
(
addr
common
.
Address
)
{
func
(
b
*
BlockGen
)
SetCoinbase
(
addr
common
.
Address
)
{
...
@@ -151,7 +149,7 @@ func (b *BlockGen) PrevBlock(index int) *types.Block {
...
@@ -151,7 +149,7 @@ func (b *BlockGen) PrevBlock(index int) *types.Block {
// associated difficulty. It's useful to test scenarios where forking is not
// associated difficulty. It's useful to test scenarios where forking is not
// tied to chain length directly.
// tied to chain length directly.
func
(
b
*
BlockGen
)
OffsetTime
(
seconds
int64
)
{
func
(
b
*
BlockGen
)
OffsetTime
(
seconds
int64
)
{
b
.
header
.
Time
.
Add
(
b
.
header
.
Time
,
new
(
big
.
Int
)
.
SetInt64
(
seconds
))
b
.
header
.
Time
.
Add
(
b
.
header
.
Time
,
big
.
NewInt
(
seconds
))
if
b
.
header
.
Time
.
Cmp
(
b
.
parent
.
Header
()
.
Time
)
<=
0
{
if
b
.
header
.
Time
.
Cmp
(
b
.
parent
.
Header
()
.
Time
)
<=
0
{
panic
(
"block time out of range"
)
panic
(
"block time out of range"
)
}
}
...
@@ -172,10 +170,6 @@ func (b *BlockGen) OffsetTime(seconds int64) {
...
@@ -172,10 +170,6 @@ func (b *BlockGen) OffsetTime(seconds int64) {
// values. Inserting them into BlockChain requires use of FakePow or
// values. Inserting them into BlockChain requires use of FakePow or
// a similar non-validating proof of work implementation.
// a similar non-validating proof of work implementation.
func
GenerateChain
(
config
*
params
.
ChainConfig
,
parent
*
types
.
Block
,
engine
consensus
.
Engine
,
db
ethdb
.
Database
,
n
int
,
gen
func
(
int
,
*
BlockGen
))
([]
*
types
.
Block
,
[]
types
.
Receipts
)
{
func
GenerateChain
(
config
*
params
.
ChainConfig
,
parent
*
types
.
Block
,
engine
consensus
.
Engine
,
db
ethdb
.
Database
,
n
int
,
gen
func
(
int
,
*
BlockGen
))
([]
*
types
.
Block
,
[]
types
.
Receipts
)
{
return
generateChain
(
config
,
parent
,
engine
,
db
,
n
,
gen
,
makeHeader
)
}
func
generateChain
(
config
*
params
.
ChainConfig
,
parent
*
types
.
Block
,
engine
consensus
.
Engine
,
db
ethdb
.
Database
,
n
int
,
gen
func
(
int
,
*
BlockGen
),
headerGen
headerGenFn
)
([]
*
types
.
Block
,
[]
types
.
Receipts
)
{
if
config
==
nil
{
if
config
==
nil
{
config
=
params
.
TestChainConfig
config
=
params
.
TestChainConfig
}
}
...
@@ -183,8 +177,7 @@ func generateChain(config *params.ChainConfig, parent *types.Block, engine conse
...
@@ -183,8 +177,7 @@ func generateChain(config *params.ChainConfig, parent *types.Block, engine conse
chainreader
:=
&
fakeChainReader
{
config
:
config
}
chainreader
:=
&
fakeChainReader
{
config
:
config
}
genblock
:=
func
(
i
int
,
parent
*
types
.
Block
,
statedb
*
state
.
StateDB
)
(
*
types
.
Block
,
types
.
Receipts
)
{
genblock
:=
func
(
i
int
,
parent
*
types
.
Block
,
statedb
*
state
.
StateDB
)
(
*
types
.
Block
,
types
.
Receipts
)
{
b
:=
&
BlockGen
{
i
:
i
,
chain
:
blocks
,
parent
:
parent
,
statedb
:
statedb
,
config
:
config
,
engine
:
engine
}
b
:=
&
BlockGen
{
i
:
i
,
chain
:
blocks
,
parent
:
parent
,
statedb
:
statedb
,
config
:
config
,
engine
:
engine
}
//b.header = makeHeader(chainreader, parent, statedb, b.engine)
b
.
header
=
makeHeader
(
chainreader
,
parent
,
statedb
,
b
.
engine
)
b
.
header
=
headerGen
(
chainreader
,
parent
,
statedb
,
b
.
engine
)
// Mutate the state and block according to any hard-fork specs
// Mutate the state and block according to any hard-fork specs
if
daoBlock
:=
config
.
DAOForkBlock
;
daoBlock
!=
nil
{
if
daoBlock
:=
config
.
DAOForkBlock
;
daoBlock
!=
nil
{
...
@@ -255,54 +248,6 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
...
@@ -255,54 +248,6 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
}
}
}
}
func
makeHeaderWithLargeDifficulty
(
chain
consensus
.
ChainReader
,
parent
*
types
.
Block
,
state
*
state
.
StateDB
,
engine
consensus
.
Engine
)
*
types
.
Header
{
var
time
*
big
.
Int
if
parent
.
Time
()
==
nil
{
time
=
big
.
NewInt
(
1
)
}
else
{
time
=
new
(
big
.
Int
)
.
Add
(
parent
.
Time
(),
big
.
NewInt
(
1
))
// block time is fixed at 10 seconds
}
return
&
types
.
Header
{
Root
:
state
.
IntermediateRoot
(
chain
.
Config
()
.
IsEIP158
(
parent
.
Number
())),
ParentHash
:
parent
.
Hash
(),
Coinbase
:
parent
.
Coinbase
(),
Difficulty
:
engine
.
CalcDifficulty
(
chain
,
time
.
Uint64
(),
&
types
.
Header
{
Number
:
parent
.
Number
(),
Time
:
new
(
big
.
Int
)
.
Sub
(
time
,
big
.
NewInt
(
1
)),
Difficulty
:
parent
.
Difficulty
(),
UncleHash
:
parent
.
UncleHash
(),
}),
GasLimit
:
CalcGasLimit
(
parent
,
parent
.
GasLimit
(),
parent
.
GasLimit
()),
Number
:
new
(
big
.
Int
)
.
Add
(
parent
.
Number
(),
common
.
Big1
),
Time
:
time
,
}
}
func
makeHeaderWithSmallDifficulty
(
chain
consensus
.
ChainReader
,
parent
*
types
.
Block
,
state
*
state
.
StateDB
,
engine
consensus
.
Engine
)
*
types
.
Header
{
var
time
*
big
.
Int
if
parent
.
Time
()
==
nil
{
time
=
big
.
NewInt
(
30
)
}
else
{
time
=
new
(
big
.
Int
)
.
Add
(
parent
.
Time
(),
big
.
NewInt
(
30
))
// block time is fixed at 10 seconds
}
return
&
types
.
Header
{
Root
:
state
.
IntermediateRoot
(
chain
.
Config
()
.
IsEIP158
(
parent
.
Number
())),
ParentHash
:
parent
.
Hash
(),
Coinbase
:
parent
.
Coinbase
(),
Difficulty
:
engine
.
CalcDifficulty
(
chain
,
time
.
Uint64
(),
&
types
.
Header
{
Number
:
parent
.
Number
(),
Time
:
new
(
big
.
Int
)
.
Sub
(
time
,
big
.
NewInt
(
30
)),
Difficulty
:
parent
.
Difficulty
(),
UncleHash
:
parent
.
UncleHash
(),
}),
GasLimit
:
CalcGasLimit
(
parent
,
parent
.
GasLimit
(),
parent
.
GasLimit
()),
Number
:
new
(
big
.
Int
)
.
Add
(
parent
.
Number
(),
common
.
Big1
),
Time
:
time
,
}
}
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
func
makeHeaderChain
(
parent
*
types
.
Header
,
n
int
,
engine
consensus
.
Engine
,
db
ethdb
.
Database
,
seed
int
)
[]
*
types
.
Header
{
func
makeHeaderChain
(
parent
*
types
.
Header
,
n
int
,
engine
consensus
.
Engine
,
db
ethdb
.
Database
,
seed
int
)
[]
*
types
.
Header
{
blocks
:=
makeBlockChain
(
types
.
NewBlockWithHeader
(
parent
),
n
,
engine
,
db
,
seed
)
blocks
:=
makeBlockChain
(
types
.
NewBlockWithHeader
(
parent
),
n
,
engine
,
db
,
seed
)
...
...
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