Skip to content

Commit

Permalink
Merge pull request ethereum#17622 from karalabe/chain-maker-seal
Browse files Browse the repository at this point in the history
 consensus/clique, core: chain maker clique + error tests
  • Loading branch information
karalabe authored Sep 17, 2018
2 parents 7c71e93 + 4bb2504 commit cc21928
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 73 deletions.
49 changes: 32 additions & 17 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,27 +93,33 @@ var (

// errMissingSignature is returned if a block's extra-data section doesn't seem
// to contain a 65 byte secp256k1 signature.
errMissingSignature = errors.New("extra-data 65 byte suffix signature missing")
errMissingSignature = errors.New("extra-data 65 byte signature suffix missing")

// errExtraSigners is returned if non-checkpoint block contain signer data in
// their extra-data fields.
errExtraSigners = errors.New("non-checkpoint block contains extra signer list")

// errInvalidCheckpointSigners is returned if a checkpoint block contains an
// invalid list of signers (i.e. non divisible by 20 bytes, or not the correct
// ones).
// invalid list of signers (i.e. non divisible by 20 bytes).
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 = errors.New("non-zero mix digest")

// errInvalidUncleHash is returned if a block contains an non-empty uncle list.
errInvalidUncleHash = errors.New("non empty uncle hash")

// errInvalidDifficulty is returned if the difficulty of a block is not either
// of 1 or 2, or if the value does not match the turn of the signer.
// errInvalidDifficulty is returned if the difficulty of a block neither 1 or 2.
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
// the previous block's timestamp + the minimum block period.
ErrInvalidTimestamp = errors.New("invalid timestamp")
Expand All @@ -122,8 +128,12 @@ var (
// be modified via out-of-range or non-contiguous headers.
errInvalidVotingChain = errors.New("invalid voting chain")

// errUnauthorized is returned if a header is signed by a non-authorized entity.
errUnauthorized = errors.New("unauthorized")
// errUnauthorizedSigner is returned if a header is signed by a non-authorized entity.
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
// on an instant chain (0 second period). It's important to refuse these as the
Expand Down Expand Up @@ -205,6 +215,9 @@ type Clique struct {
signer common.Address // Ethereum address of the signing key
signFn SignerFn // Signer function to authorize hashes with
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
Expand Down Expand Up @@ -359,7 +372,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type
}
extraSuffix := len(header.Extra) - extraSeal
if !bytes.Equal(header.Extra[extraVanity:extraSuffix], signers) {
return errInvalidCheckpointSigners
return errMismatchingCheckpointSigners
}
}
// All basic checks passed, verify the seal and return
Expand Down Expand Up @@ -481,23 +494,25 @@ func (c *Clique) verifySeal(chain consensus.ChainReader, header *types.Header, p
return err
}
if _, ok := snap.Signers[signer]; !ok {
return errUnauthorized
return errUnauthorizedSigner
}
for seen, recent := range snap.Recents {
if recent == signer {
// 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 {
return errUnauthorized
return errRecentlySigned
}
}
}
// Ensure that the difficulty corresponds to the turn-ness of the signer
inturn := snap.inturn(header.Number.Uint64(), signer)
if inturn && header.Difficulty.Cmp(diffInTurn) != 0 {
return errInvalidDifficulty
}
if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 {
return errInvalidDifficulty
if !c.fakeDiff {
inturn := snap.inturn(header.Number.Uint64(), signer)
if inturn && header.Difficulty.Cmp(diffInTurn) != 0 {
return errWrongDifficulty
}
if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 {
return errWrongDifficulty
}
}
return nil
}
Expand Down Expand Up @@ -613,7 +628,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
return err
}
if _, authorized := snap.Signers[signer]; !authorized {
return errUnauthorized
return errUnauthorizedSigner
}
// If we're amongst the recent signers, wait for the next block
for seen, recent := range snap.Recents {
Expand Down
16 changes: 8 additions & 8 deletions consensus/clique/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ type Snapshot struct {
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
type signers []common.Address
// signersAscending implements the sort interface to allow sorting a list of addresses
type signersAscending []common.Address

func (s signers) Len() int { return len(s) }
func (s signers) 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 signersAscending) Len() int { return len(s) }
func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

// 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
Expand Down Expand Up @@ -214,11 +214,11 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
return nil, err
}
if _, ok := snap.Signers[signer]; !ok {
return nil, errUnauthorized
return nil, errUnauthorizedSigner
}
for _, recent := range snap.Recents {
if recent == signer {
return nil, errUnauthorized
return nil, errRecentlySigned
}
}
snap.Recents[number] = signer
Expand Down Expand Up @@ -298,7 +298,7 @@ func (s *Snapshot) signers() []common.Address {
for sig := range s.Signers {
sigs = append(sigs, sig)
}
sort.Sort(signers(sigs))
sort.Sort(signersAscending(sigs))
return sigs
}

Expand Down
Loading

0 comments on commit cc21928

Please sign in to comment.