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
4bb25042
Unverified
Commit
4bb25042
authored
Sep 10, 2018
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
consensus/clique, core: chain maker clique + error tests
parent
10bac366
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
193 additions
and
73 deletions
+193
-73
clique.go
consensus/clique/clique.go
+32
-17
snapshot.go
consensus/clique/snapshot.go
+8
-8
snapshot_test.go
consensus/clique/snapshot_test.go
+144
-46
chain_makers.go
core/chain_makers.go
+8
-2
worker_test.go
miner/worker_test.go
+1
-0
No files found.
consensus/clique/clique.go
View file @
4bb25042
...
@@ -93,27 +93,33 @@ var (
...
@@ -93,27 +93,33 @@ var (
// errMissingSignature is returned if a block's extra-data section doesn't seem
// errMissingSignature is returned if a block's extra-data section doesn't seem
// to contain a 65 byte secp256k1 signature.
// to contain a 65 byte secp256k1 signature.
errMissingSignature
=
errors
.
New
(
"extra-data 65 byte s
uffix signature
missing"
)
errMissingSignature
=
errors
.
New
(
"extra-data 65 byte s
ignature suffix
missing"
)
// errExtraSigners is returned if non-checkpoint block contain signer data in
// errExtraSigners is returned if non-checkpoint block contain signer data in
// their extra-data fields.
// their extra-data fields.
errExtraSigners
=
errors
.
New
(
"non-checkpoint block contains extra signer list"
)
errExtraSigners
=
errors
.
New
(
"non-checkpoint block contains extra signer list"
)
// errInvalidCheckpointSigners is returned if a checkpoint block contains an
// errInvalidCheckpointSigners is returned if a checkpoint block contains an
// invalid list of signers (i.e. non divisible by 20 bytes, or not the correct
// invalid list of signers (i.e. non divisible by 20 bytes).
// ones).
errInvalidCheckpointSigners
=
errors
.
New
(
"invalid signer list on checkpoint block"
)
errInvalidCheckpointSigners
=
errors
.
New
(
"invalid signer list on checkpoint block"
)
// errMismatchingCheckpointSigners is returned if a checkpoint block contains a
// list of signers different than the one the local node calculated.
errMismatchingCheckpointSigners
=
errors
.
New
(
"mismatching signer list on checkpoint block"
)
// errInvalidMixDigest is returned if a block's mix digest is non-zero.
// errInvalidMixDigest is returned if a block's mix digest is non-zero.
errInvalidMixDigest
=
errors
.
New
(
"non-zero mix digest"
)
errInvalidMixDigest
=
errors
.
New
(
"non-zero mix digest"
)
// errInvalidUncleHash is returned if a block contains an non-empty uncle list.
// errInvalidUncleHash is returned if a block contains an non-empty uncle list.
errInvalidUncleHash
=
errors
.
New
(
"non empty uncle hash"
)
errInvalidUncleHash
=
errors
.
New
(
"non empty uncle hash"
)
// errInvalidDifficulty is returned if the difficulty of a block is not either
// errInvalidDifficulty is returned if the difficulty of a block neither 1 or 2.
// of 1 or 2, or if the value does not match the turn of the signer.
errInvalidDifficulty
=
errors
.
New
(
"invalid difficulty"
)
errInvalidDifficulty
=
errors
.
New
(
"invalid difficulty"
)
// errWrongDifficulty is returned if the difficulty of a block doesn't match the
// turn of the signer.
errWrongDifficulty
=
errors
.
New
(
"wrong difficulty"
)
// ErrInvalidTimestamp is returned if the timestamp of a block is lower than
// ErrInvalidTimestamp is returned if the timestamp of a block is lower than
// the previous block's timestamp + the minimum block period.
// the previous block's timestamp + the minimum block period.
ErrInvalidTimestamp
=
errors
.
New
(
"invalid timestamp"
)
ErrInvalidTimestamp
=
errors
.
New
(
"invalid timestamp"
)
...
@@ -122,8 +128,12 @@ var (
...
@@ -122,8 +128,12 @@ var (
// be modified via out-of-range or non-contiguous headers.
// be modified via out-of-range or non-contiguous headers.
errInvalidVotingChain
=
errors
.
New
(
"invalid voting chain"
)
errInvalidVotingChain
=
errors
.
New
(
"invalid voting chain"
)
// errUnauthorized is returned if a header is signed by a non-authorized entity.
// errUnauthorizedSigner is returned if a header is signed by a non-authorized entity.
errUnauthorized
=
errors
.
New
(
"unauthorized"
)
errUnauthorizedSigner
=
errors
.
New
(
"unauthorized signer"
)
// errRecentlySigned is returned if a header is signed by an authorized entity
// that already signed a header recently, thus is temporarily not allowed to.
errRecentlySigned
=
errors
.
New
(
"recently signed"
)
// errWaitTransactions is returned if an empty block is attempted to be sealed
// errWaitTransactions is returned if an empty block is attempted to be sealed
// on an instant chain (0 second period). It's important to refuse these as the
// on an instant chain (0 second period). It's important to refuse these as the
...
@@ -205,6 +215,9 @@ type Clique struct {
...
@@ -205,6 +215,9 @@ type Clique struct {
signer
common
.
Address
// Ethereum address of the signing key
signer
common
.
Address
// Ethereum address of the signing key
signFn
SignerFn
// Signer function to authorize hashes with
signFn
SignerFn
// Signer function to authorize hashes with
lock
sync
.
RWMutex
// Protects the signer fields
lock
sync
.
RWMutex
// Protects the signer fields
// The fields below are for testing only
fakeDiff
bool
// Skip difficulty verifications
}
}
// New creates a Clique proof-of-authority consensus engine with the initial
// New creates a Clique proof-of-authority consensus engine with the initial
...
@@ -359,7 +372,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type
...
@@ -359,7 +372,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type
}
}
extraSuffix
:=
len
(
header
.
Extra
)
-
extraSeal
extraSuffix
:=
len
(
header
.
Extra
)
-
extraSeal
if
!
bytes
.
Equal
(
header
.
Extra
[
extraVanity
:
extraSuffix
],
signers
)
{
if
!
bytes
.
Equal
(
header
.
Extra
[
extraVanity
:
extraSuffix
],
signers
)
{
return
err
Invalid
CheckpointSigners
return
err
Mismatching
CheckpointSigners
}
}
}
}
// All basic checks passed, verify the seal and return
// All basic checks passed, verify the seal and return
...
@@ -481,23 +494,25 @@ func (c *Clique) verifySeal(chain consensus.ChainReader, header *types.Header, p
...
@@ -481,23 +494,25 @@ func (c *Clique) verifySeal(chain consensus.ChainReader, header *types.Header, p
return
err
return
err
}
}
if
_
,
ok
:=
snap
.
Signers
[
signer
];
!
ok
{
if
_
,
ok
:=
snap
.
Signers
[
signer
];
!
ok
{
return
errUnauthorized
return
errUnauthorized
Signer
}
}
for
seen
,
recent
:=
range
snap
.
Recents
{
for
seen
,
recent
:=
range
snap
.
Recents
{
if
recent
==
signer
{
if
recent
==
signer
{
// Signer is among recents, only fail if the current block doesn't shift it out
// Signer is among recents, only fail if the current block doesn't shift it out
if
limit
:=
uint64
(
len
(
snap
.
Signers
)
/
2
+
1
);
seen
>
number
-
limit
{
if
limit
:=
uint64
(
len
(
snap
.
Signers
)
/
2
+
1
);
seen
>
number
-
limit
{
return
err
Unauthoriz
ed
return
err
RecentlySign
ed
}
}
}
}
}
}
// Ensure that the difficulty corresponds to the turn-ness of the signer
// Ensure that the difficulty corresponds to the turn-ness of the signer
if
!
c
.
fakeDiff
{
inturn
:=
snap
.
inturn
(
header
.
Number
.
Uint64
(),
signer
)
inturn
:=
snap
.
inturn
(
header
.
Number
.
Uint64
(),
signer
)
if
inturn
&&
header
.
Difficulty
.
Cmp
(
diffInTurn
)
!=
0
{
if
inturn
&&
header
.
Difficulty
.
Cmp
(
diffInTurn
)
!=
0
{
return
errInvalid
Difficulty
return
errWrong
Difficulty
}
}
if
!
inturn
&&
header
.
Difficulty
.
Cmp
(
diffNoTurn
)
!=
0
{
if
!
inturn
&&
header
.
Difficulty
.
Cmp
(
diffNoTurn
)
!=
0
{
return
errInvalidDifficulty
return
errWrongDifficulty
}
}
}
return
nil
return
nil
}
}
...
@@ -613,7 +628,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
...
@@ -613,7 +628,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
return
err
return
err
}
}
if
_
,
authorized
:=
snap
.
Signers
[
signer
];
!
authorized
{
if
_
,
authorized
:=
snap
.
Signers
[
signer
];
!
authorized
{
return
errUnauthorized
return
errUnauthorized
Signer
}
}
// If we're amongst the recent signers, wait for the next block
// If we're amongst the recent signers, wait for the next block
for
seen
,
recent
:=
range
snap
.
Recents
{
for
seen
,
recent
:=
range
snap
.
Recents
{
...
...
consensus/clique/snapshot.go
View file @
4bb25042
...
@@ -57,12 +57,12 @@ type Snapshot struct {
...
@@ -57,12 +57,12 @@ type Snapshot struct {
Tally
map
[
common
.
Address
]
Tally
`json:"tally"`
// Current vote tally to avoid recalculating
Tally
map
[
common
.
Address
]
Tally
`json:"tally"`
// Current vote tally to avoid recalculating
}
}
// signers implements the sort interface to allow sorting a list of addresses
// signers
Ascending
implements the sort interface to allow sorting a list of addresses
type
signers
[]
common
.
Address
type
signers
Ascending
[]
common
.
Address
func
(
s
signers
)
Len
()
int
{
return
len
(
s
)
}
func
(
s
signers
Ascending
)
Len
()
int
{
return
len
(
s
)
}
func
(
s
signers
)
Less
(
i
,
j
int
)
bool
{
return
bytes
.
Compare
(
s
[
i
][
:
],
s
[
j
][
:
])
<
0
}
func
(
s
signers
Ascending
)
Less
(
i
,
j
int
)
bool
{
return
bytes
.
Compare
(
s
[
i
][
:
],
s
[
j
][
:
])
<
0
}
func
(
s
signers
)
Swap
(
i
,
j
int
)
{
s
[
i
],
s
[
j
]
=
s
[
j
],
s
[
i
]
}
func
(
s
signers
Ascending
)
Swap
(
i
,
j
int
)
{
s
[
i
],
s
[
j
]
=
s
[
j
],
s
[
i
]
}
// newSnapshot creates a new snapshot with the specified startup parameters. This
// newSnapshot creates a new snapshot with the specified startup parameters. This
// method does not initialize the set of recent signers, so only ever use if for
// method does not initialize the set of recent signers, so only ever use if for
...
@@ -214,11 +214,11 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
...
@@ -214,11 +214,11 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
return
nil
,
err
return
nil
,
err
}
}
if
_
,
ok
:=
snap
.
Signers
[
signer
];
!
ok
{
if
_
,
ok
:=
snap
.
Signers
[
signer
];
!
ok
{
return
nil
,
errUnauthorized
return
nil
,
errUnauthorized
Signer
}
}
for
_
,
recent
:=
range
snap
.
Recents
{
for
_
,
recent
:=
range
snap
.
Recents
{
if
recent
==
signer
{
if
recent
==
signer
{
return
nil
,
err
Unauthoriz
ed
return
nil
,
err
RecentlySign
ed
}
}
}
}
snap
.
Recents
[
number
]
=
signer
snap
.
Recents
[
number
]
=
signer
...
@@ -298,7 +298,7 @@ func (s *Snapshot) signers() []common.Address {
...
@@ -298,7 +298,7 @@ func (s *Snapshot) signers() []common.Address {
for
sig
:=
range
s
.
Signers
{
for
sig
:=
range
s
.
Signers
{
sigs
=
append
(
sigs
,
sig
)
sigs
=
append
(
sigs
,
sig
)
}
}
sort
.
Sort
(
signers
(
sigs
))
sort
.
Sort
(
signers
Ascending
(
sigs
))
return
sigs
return
sigs
}
}
...
...
consensus/clique/snapshot_test.go
View file @
4bb25042
...
@@ -19,24 +19,18 @@ package clique
...
@@ -19,24 +19,18 @@ package clique
import
(
import
(
"bytes"
"bytes"
"crypto/ecdsa"
"crypto/ecdsa"
"
math/big
"
"
sort
"
"testing"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params"
)
)
type
testerVote
struct
{
signer
string
voted
string
auth
bool
}
// testerAccountPool is a pool to maintain currently active tester accounts,
// testerAccountPool is a pool to maintain currently active tester accounts,
// mapped from textual names used in the tests below to actual Ethereum private
// mapped from textual names used in the tests below to actual Ethereum private
// keys capable of signing transactions.
// keys capable of signing transactions.
...
@@ -50,17 +44,26 @@ func newTesterAccountPool() *testerAccountPool {
...
@@ -50,17 +44,26 @@ func newTesterAccountPool() *testerAccountPool {
}
}
}
}
func
(
ap
*
testerAccountPool
)
sign
(
header
*
types
.
Header
,
signer
string
)
{
// checkpoint creates a Clique checkpoint signer section from the provided list
// Ensure we have a persistent key for the signer
// of authorized signers and embeds it into the provided header.
if
ap
.
accounts
[
signer
]
==
nil
{
func
(
ap
*
testerAccountPool
)
checkpoint
(
header
*
types
.
Header
,
signers
[]
string
)
{
ap
.
accounts
[
signer
],
_
=
crypto
.
GenerateKey
()
auths
:=
make
([]
common
.
Address
,
len
(
signers
))
for
i
,
signer
:=
range
signers
{
auths
[
i
]
=
ap
.
address
(
signer
)
}
sort
.
Sort
(
signersAscending
(
auths
))
for
i
,
auth
:=
range
auths
{
copy
(
header
.
Extra
[
extraVanity
+
i
*
common
.
AddressLength
:
],
auth
.
Bytes
())
}
}
// Sign the header and embed the signature in extra data
sig
,
_
:=
crypto
.
Sign
(
sigHash
(
header
)
.
Bytes
(),
ap
.
accounts
[
signer
])
copy
(
header
.
Extra
[
len
(
header
.
Extra
)
-
65
:
],
sig
)
}
}
// address retrieves the Ethereum address of a tester account by label, creating
// a new account if no previous one exists yet.
func
(
ap
*
testerAccountPool
)
address
(
account
string
)
common
.
Address
{
func
(
ap
*
testerAccountPool
)
address
(
account
string
)
common
.
Address
{
// Return the zero account for non-addresses
if
account
==
""
{
return
common
.
Address
{}
}
// Ensure we have a persistent key for the account
// Ensure we have a persistent key for the account
if
ap
.
accounts
[
account
]
==
nil
{
if
ap
.
accounts
[
account
]
==
nil
{
ap
.
accounts
[
account
],
_
=
crypto
.
GenerateKey
()
ap
.
accounts
[
account
],
_
=
crypto
.
GenerateKey
()
...
@@ -69,32 +72,38 @@ func (ap *testerAccountPool) address(account string) common.Address {
...
@@ -69,32 +72,38 @@ func (ap *testerAccountPool) address(account string) common.Address {
return
crypto
.
PubkeyToAddress
(
ap
.
accounts
[
account
]
.
PublicKey
)
return
crypto
.
PubkeyToAddress
(
ap
.
accounts
[
account
]
.
PublicKey
)
}
}
// testerChainReader implements consensus.ChainReader to access the genesis
// sign calculates a Clique digital signature for the given block and embeds it
// block. All other methods and requests will panic.
// back into the header.
type
testerChainReader
struct
{
func
(
ap
*
testerAccountPool
)
sign
(
header
*
types
.
Header
,
signer
string
)
{
db
ethdb
.
Database
// Ensure we have a persistent key for the signer
if
ap
.
accounts
[
signer
]
==
nil
{
ap
.
accounts
[
signer
],
_
=
crypto
.
GenerateKey
()
}
// Sign the header and embed the signature in extra data
sig
,
_
:=
crypto
.
Sign
(
sigHash
(
header
)
.
Bytes
(),
ap
.
accounts
[
signer
])
copy
(
header
.
Extra
[
len
(
header
.
Extra
)
-
extraSeal
:
],
sig
)
}
}
func
(
r
*
testerChainReader
)
Config
()
*
params
.
ChainConfig
{
return
params
.
AllCliqueProtocolChanges
}
// testerVote represents a single block signed by a parcitular account, where
func
(
r
*
testerChainReader
)
CurrentHeader
()
*
types
.
Header
{
panic
(
"not supported"
)
}
// the account may or may not have cast a Clique vote.
func
(
r
*
testerChainReader
)
GetHeader
(
common
.
Hash
,
uint64
)
*
types
.
Header
{
panic
(
"not supported"
)
}
type
testerVote
struct
{
func
(
r
*
testerChainReader
)
GetBlock
(
common
.
Hash
,
uint64
)
*
types
.
Block
{
panic
(
"not supported"
)
}
signer
string
func
(
r
*
testerChainReader
)
GetHeaderByHash
(
common
.
Hash
)
*
types
.
Header
{
panic
(
"not supported"
)
}
voted
string
func
(
r
*
testerChainReader
)
GetHeaderByNumber
(
number
uint64
)
*
types
.
Header
{
auth
bool
if
number
==
0
{
checkpoint
[]
string
return
rawdb
.
ReadHeader
(
r
.
db
,
rawdb
.
ReadCanonicalHash
(
r
.
db
,
0
),
0
)
newbatch
bool
}
return
nil
}
}
// Tests that voting is evaluated correctly for various simple and complex scenarios.
// Tests that Clique signer voting is evaluated correctly for various simple and
func
TestVoting
(
t
*
testing
.
T
)
{
// complex scenarios, as well as that a few special corner cases fail correctly.
func
TestClique
(
t
*
testing
.
T
)
{
// Define the various voting scenarios to test
// Define the various voting scenarios to test
tests
:=
[]
struct
{
tests
:=
[]
struct
{
epoch
uint64
epoch
uint64
signers
[]
string
signers
[]
string
votes
[]
testerVote
votes
[]
testerVote
results
[]
string
results
[]
string
failure
error
}{
}{
{
{
// Single signer, no votes cast
// Single signer, no votes cast
...
@@ -322,10 +331,49 @@ func TestVoting(t *testing.T) {
...
@@ -322,10 +331,49 @@ func TestVoting(t *testing.T) {
votes
:
[]
testerVote
{
votes
:
[]
testerVote
{
{
signer
:
"A"
,
voted
:
"C"
,
auth
:
true
},
{
signer
:
"A"
,
voted
:
"C"
,
auth
:
true
},
{
signer
:
"B"
},
{
signer
:
"B"
},
{
signer
:
"A"
},
// Checkpoint block, (don't vote here, it's validated outside of snapshots)
{
signer
:
"A"
,
checkpoint
:
[]
string
{
"A"
,
"B"
}},
{
signer
:
"B"
,
voted
:
"C"
,
auth
:
true
},
{
signer
:
"B"
,
voted
:
"C"
,
auth
:
true
},
},
},
results
:
[]
string
{
"A"
,
"B"
},
results
:
[]
string
{
"A"
,
"B"
},
},
{
// An unauthorized signer should not be able to sign blocks
signers
:
[]
string
{
"A"
},
votes
:
[]
testerVote
{
{
signer
:
"B"
},
},
failure
:
errUnauthorizedSigner
,
},
{
// An authorized signer that signed recenty should not be able to sign again
signers
:
[]
string
{
"A"
,
"B"
},
votes
:
[]
testerVote
{
{
signer
:
"A"
},
{
signer
:
"A"
},
},
failure
:
errRecentlySigned
,
},
{
// Recent signatures should not reset on checkpoint blocks imported in a batch
epoch
:
3
,
signers
:
[]
string
{
"A"
,
"B"
,
"C"
},
votes
:
[]
testerVote
{
{
signer
:
"A"
},
{
signer
:
"B"
},
{
signer
:
"A"
,
checkpoint
:
[]
string
{
"A"
,
"B"
,
"C"
}},
{
signer
:
"A"
},
},
failure
:
errRecentlySigned
,
},
{
// Recent signatures should not reset on checkpoint blocks imported in a new
// batch (https://github.com/ethereum/go-ethereum/issues/17593). Whilst this
// seems overly specific and weird, it was a Rinkeby consensus split.
epoch
:
3
,
signers
:
[]
string
{
"A"
,
"B"
,
"C"
},
votes
:
[]
testerVote
{
{
signer
:
"A"
},
{
signer
:
"B"
},
{
signer
:
"A"
,
checkpoint
:
[]
string
{
"A"
,
"B"
,
"C"
}},
{
signer
:
"A"
,
newbatch
:
true
},
},
failure
:
errRecentlySigned
,
},
},
}
}
// Run through the scenarios and test them
// Run through the scenarios and test them
...
@@ -356,28 +404,78 @@ func TestVoting(t *testing.T) {
...
@@ -356,28 +404,78 @@ func TestVoting(t *testing.T) {
genesis
.
Commit
(
db
)
genesis
.
Commit
(
db
)
// Assemble a chain of headers from the cast votes
// Assemble a chain of headers from the cast votes
headers
:=
make
([]
*
types
.
Header
,
len
(
tt
.
votes
))
config
:=
*
params
.
TestChainConfig
for
j
,
vote
:=
range
tt
.
votes
{
config
.
Clique
=
&
params
.
CliqueConfig
{
headers
[
j
]
=
&
types
.
Header
{
Period
:
1
,
Number
:
big
.
NewInt
(
int64
(
j
)
+
1
),
Epoch
:
tt
.
epoch
,
Time
:
big
.
NewInt
(
int64
(
j
)
*
15
),
}
Coinbase
:
accounts
.
address
(
vote
.
voted
),
engine
:=
New
(
config
.
Clique
,
db
)
Extra
:
make
([]
byte
,
extraVanity
+
extraSeal
),
engine
.
fakeDiff
=
true
blocks
,
_
:=
core
.
GenerateChain
(
&
config
,
genesis
.
ToBlock
(
db
),
engine
,
db
,
len
(
tt
.
votes
),
func
(
j
int
,
gen
*
core
.
BlockGen
)
{
// Cast the vote contained in this block
gen
.
SetCoinbase
(
accounts
.
address
(
tt
.
votes
[
j
]
.
voted
))
if
tt
.
votes
[
j
]
.
auth
{
var
nonce
types
.
BlockNonce
copy
(
nonce
[
:
],
nonceAuthVote
)
gen
.
SetNonce
(
nonce
)
}
}
})
// Iterate through the blocks and seal them individually
for
j
,
block
:=
range
blocks
{
// Geth the header and prepare it for signing
header
:=
block
.
Header
()
if
j
>
0
{
if
j
>
0
{
headers
[
j
]
.
ParentHash
=
headers
[
j
-
1
]
.
Hash
()
header
.
ParentHash
=
blocks
[
j
-
1
]
.
Hash
()
}
header
.
Extra
=
make
([]
byte
,
extraVanity
+
extraSeal
)
if
auths
:=
tt
.
votes
[
j
]
.
checkpoint
;
auths
!=
nil
{
header
.
Extra
=
make
([]
byte
,
extraVanity
+
len
(
auths
)
*
common
.
AddressLength
+
extraSeal
)
accounts
.
checkpoint
(
header
,
auths
)
}
}
if
vote
.
auth
{
header
.
Difficulty
=
diffInTurn
// Ignored, we just need a valid number
copy
(
headers
[
j
]
.
Nonce
[
:
],
nonceAuthVote
)
// Generate the signature, embed it into the header and the block
accounts
.
sign
(
header
,
tt
.
votes
[
j
]
.
signer
)
blocks
[
j
]
=
block
.
WithSeal
(
header
)
}
// Split the blocks up into individual import batches (cornercase testing)
batches
:=
[][]
*
types
.
Block
{
nil
}
for
j
,
block
:=
range
blocks
{
if
tt
.
votes
[
j
]
.
newbatch
{
batches
=
append
(
batches
,
nil
)
}
}
accounts
.
sign
(
headers
[
j
],
vote
.
signer
)
batches
[
len
(
batches
)
-
1
]
=
append
(
batches
[
len
(
batches
)
-
1
],
block
)
}
}
// Pass all the headers through clique and ensure tallying succeeds
// Pass all the headers through clique and ensure tallying succeeds
head
:=
headers
[
len
(
headers
)
-
1
]
chain
,
err
:=
core
.
NewBlockChain
(
db
,
nil
,
&
config
,
engine
,
vm
.
Config
{})
if
err
!=
nil
{
t
.
Errorf
(
"test %d: failed to create test chain: %v"
,
i
,
err
)
continue
}
failed
:=
false
for
j
:=
0
;
j
<
len
(
batches
)
-
1
;
j
++
{
if
k
,
err
:=
chain
.
InsertChain
(
batches
[
j
]);
err
!=
nil
{
t
.
Errorf
(
"test %d: failed to import batch %d, block %d: %v"
,
i
,
j
,
k
,
err
)
failed
=
true
break
}
}
if
failed
{
continue
}
if
_
,
err
=
chain
.
InsertChain
(
batches
[
len
(
batches
)
-
1
]);
err
!=
tt
.
failure
{
t
.
Errorf
(
"test %d: failure mismatch: have %v, want %v"
,
i
,
err
,
tt
.
failure
)
}
if
tt
.
failure
!=
nil
{
continue
}
// No failure was produced or requested, generate the final voting snapshot
head
:=
blocks
[
len
(
blocks
)
-
1
]
snap
,
err
:=
New
(
&
params
.
CliqueConfig
{
Epoch
:
tt
.
epoch
},
db
)
.
snapshot
(
&
testerChainReader
{
db
:
db
},
head
.
Number
.
Uint64
(),
head
.
Hash
(),
headers
)
snap
,
err
:=
engine
.
snapshot
(
chain
,
head
.
NumberU64
(),
head
.
Hash
(),
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"test %d: failed to
creat
e voting snapshot: %v"
,
i
,
err
)
t
.
Errorf
(
"test %d: failed to
retriev
e voting snapshot: %v"
,
i
,
err
)
continue
continue
}
}
// Verify the final list of signers against the expected ones
// Verify the final list of signers against the expected ones
...
...
core/chain_makers.go
View file @
4bb25042
...
@@ -67,6 +67,11 @@ func (b *BlockGen) SetExtra(data []byte) {
...
@@ -67,6 +67,11 @@ func (b *BlockGen) SetExtra(data []byte) {
b
.
header
.
Extra
=
data
b
.
header
.
Extra
=
data
}
}
// SetNonce sets the nonce field of the generated block.
func
(
b
*
BlockGen
)
SetNonce
(
nonce
types
.
BlockNonce
)
{
b
.
header
.
Nonce
=
nonce
}
// AddTx adds a transaction to the generated block. If no coinbase has
// AddTx adds a transaction to the generated block. If no coinbase has
// been set, the block's coinbase is set to the zero address.
// been set, the block's coinbase is set to the zero address.
//
//
...
@@ -190,13 +195,14 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
...
@@ -190,13 +195,14 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if
config
.
DAOForkSupport
&&
config
.
DAOForkBlock
!=
nil
&&
config
.
DAOForkBlock
.
Cmp
(
b
.
header
.
Number
)
==
0
{
if
config
.
DAOForkSupport
&&
config
.
DAOForkBlock
!=
nil
&&
config
.
DAOForkBlock
.
Cmp
(
b
.
header
.
Number
)
==
0
{
misc
.
ApplyDAOHardFork
(
statedb
)
misc
.
ApplyDAOHardFork
(
statedb
)
}
}
// Execute any user modifications to the block
and finalize it
// Execute any user modifications to the block
if
gen
!=
nil
{
if
gen
!=
nil
{
gen
(
i
,
b
)
gen
(
i
,
b
)
}
}
if
b
.
engine
!=
nil
{
if
b
.
engine
!=
nil
{
// Finalize and seal the block
block
,
_
:=
b
.
engine
.
Finalize
(
b
.
chainReader
,
b
.
header
,
statedb
,
b
.
txs
,
b
.
uncles
,
b
.
receipts
)
block
,
_
:=
b
.
engine
.
Finalize
(
b
.
chainReader
,
b
.
header
,
statedb
,
b
.
txs
,
b
.
uncles
,
b
.
receipts
)
// Write state changes to db
// Write state changes to db
root
,
err
:=
statedb
.
Commit
(
config
.
IsEIP158
(
b
.
header
.
Number
))
root
,
err
:=
statedb
.
Commit
(
config
.
IsEIP158
(
b
.
header
.
Number
))
if
err
!=
nil
{
if
err
!=
nil
{
...
...
miner/worker_test.go
View file @
4bb25042
...
@@ -161,6 +161,7 @@ func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, eng
...
@@ -161,6 +161,7 @@ func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, eng
t
.
Errorf
(
"account balance mismatch: have %d, want %d"
,
balance
,
1000
)
t
.
Errorf
(
"account balance mismatch: have %d, want %d"
,
balance
,
1000
)
}
}
b
.
txPool
.
AddLocals
(
newTxs
)
b
.
txPool
.
AddLocals
(
newTxs
)
// Ensure the new tx events has been processed
// Ensure the new tx events has been processed
time
.
Sleep
(
100
*
time
.
Millisecond
)
time
.
Sleep
(
100
*
time
.
Millisecond
)
block
,
state
=
w
.
pending
()
block
,
state
=
w
.
pending
()
...
...
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