fix block time bug

This commit is contained in:
Jaynti Kanani 2019-06-21 17:40:23 +05:30
parent ad198aeefd
commit f12ae309cf
No known key found for this signature in database
GPG key ID: 4396982C976BAE5E
4 changed files with 381 additions and 254 deletions

View file

@ -8,7 +8,6 @@ import (
"io"
"math"
"math/big"
"math/rand"
"strings"
"sync"
"time"
@ -39,7 +38,7 @@ const (
inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
inmemorySignatures = 4096 // Number of recent block signatures to keep in memory
wiggleTime = 500 * time.Millisecond // Random delay (per signer) to allow concurrent signers
wiggleTime = 1000 * time.Millisecond // Random delay (per signer) to allow concurrent signers
)
// Bor protocol constants.
@ -116,9 +115,9 @@ var (
// the previous block's timestamp + the minimum block period.
ErrInvalidTimestamp = errors.New("invalid timestamp")
// errInvalidVotingChain is returned if an authorization list is attempted to
// errOutOfRangeChain is returned if an authorization list is attempted to
// be modified via out-of-range or non-contiguous headers.
errInvalidVotingChain = errors.New("invalid voting chain")
errOutOfRangeChain = errors.New("out of range or non-contiguous chain")
// errUnauthorizedSigner is returned if a header is signed by a non-authorized entity.
errUnauthorizedSigner = errors.New("unauthorized signer")
@ -191,21 +190,26 @@ func encodeSigHeader(w io.Writer, header *types.Header) {
// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
// that a new block should have based on the previous blocks in the chain and the
// current signer.
func CalcDifficulty(snap *Snapshot, signer common.Address, producerPeriod uint64) *big.Int {
if snap.inturn(snap.Number+1, signer, producerPeriod) {
return new(big.Int).Set(diffInTurn)
}
return new(big.Int).Set(diffNoTurn)
func CalcDifficulty(snap *Snapshot, signer common.Address, epoch uint64) *big.Int {
return big.NewInt(0).SetUint64(snap.inturn(snap.Number+1, signer, epoch))
}
// CalcProducerDelay is the producer delay algorithm based on block time.
func CalcProducerDelay(snap *Snapshot, producerInterval uint64, producerDelay uint64) uint64 {
isFirstBlock := (snap.Number + 1) % producerInterval
if isFirstBlock == 0 {
func CalcProducerDelay(snap *Snapshot, signer common.Address, period uint64, epoch uint64, producerDelay uint64) uint64 {
// lastSigner := snap.Recents[snap.Number]
// proposer := snap.ValidatorSet.GetProposer()
// if block is epoch start block, proposer will be inturn signer
if (snap.Number+1)%epoch == 0 {
fmt.Println("==>", "producerDelay", producerDelay, "(snap.Number+1)%epoch", (snap.Number+1)%epoch)
return producerDelay
// if block is not epoch block, last block signer will be inturn
// } else if bytes.Compare(lastSigner.Bytes(), signer.Bytes()) != 0 {
// return producerDelay
}
return 0
return period
}
// BorRLP returns the rlp bytes which needs to be signed for the bor
@ -235,7 +239,8 @@ type Bor struct {
signFn SignerFn // Signer function to authorize hashes with
lock sync.RWMutex // Protects the signer fields
ethAPI *ethapi.PublicBlockChainAPI
ethAPI *ethapi.PublicBlockChainAPI
validatorSetABI abi.ABI
// The fields below are for testing only
fakeDiff bool // Skip difficulty verifications
@ -248,18 +253,21 @@ func New(config *params.BorConfig, db ethdb.Database, ethAPI *ethapi.PublicBlock
if conf.Epoch == 0 {
conf.Epoch = epochLength
}
// Allocate the snapshot caches and create the engine
recents, _ := lru.NewARC(inmemorySnapshots)
signatures, _ := lru.NewARC(inmemorySignatures)
return &Bor{
config: &conf,
db: db,
ethAPI: ethAPI,
recents: recents,
signatures: signatures,
proposals: make(map[common.Address]bool),
validatorSetABI, _ := abi.JSON(strings.NewReader(validatorset.ValidatorsetABI))
c := &Bor{
config: &conf,
db: db,
ethAPI: ethAPI,
recents: recents,
signatures: signatures,
proposals: make(map[common.Address]bool),
validatorSetABI: validatorSetABI,
}
return c
}
// Author implements consensus.Engine, returning the Ethereum address recovered
@ -381,20 +389,22 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainReader, header *types.H
return ErrInvalidTimestamp
}
// Retrieve the snapshot needed to verify this header and cache it
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
if err != nil {
return err
}
// snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
// if err != nil {
// return err
// }
// If the block is a checkpoint block, verify the signer list
// TODO verify signers
if number%c.config.Epoch == 0 {
signers := make([]byte, len(snap.Signers)*common.AddressLength)
for i, signer := range snap.signers() {
copy(signers[i*common.AddressLength:], signer[:])
}
extraSuffix := len(header.Extra) - extraSeal
if !bytes.Equal(header.Extra[extraVanity:extraSuffix], signers) {
return errMismatchingCheckpointSigners
}
// signers := make([]byte, len(snap.Signers)*common.AddressLength)
// for i, signer := range snap.signers() {
// copy(signers[i*common.AddressLength:], signer[:])
// }
// extraSuffix := len(header.Extra) - extraSeal
// if !bytes.Equal(header.Extra[extraVanity:extraSuffix], signers) {
// return errMismatchingCheckpointSigners
// }
}
// All basic checks passed, verify the seal and return
return c.verifySeal(chain, header, parents)
@ -415,7 +425,7 @@ func (c *Bor) snapshot(chain consensus.ChainReader, number uint64, hash common.H
}
// If an on-disk checkpoint snapshot can be found, use that
if number%voteSnapshotInterval == 0 {
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash); err == nil {
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash, c.ethAPI); err == nil {
log.Trace("Loaded voting snapshot from disk", "number", number, "hash", hash)
snap = s
break
@ -428,15 +438,19 @@ func (c *Bor) snapshot(chain consensus.ChainReader, number uint64, hash common.H
if checkpoint != nil {
hash := checkpoint.Hash()
// validatorSet := new(ValidatorSet)
// TODO populate validator set
c.GetCurrentValidators(number)
// current validators
validators, err := c.GetCurrentValidators(number)
if err != nil {
// Handle error
}
// TODO remove signer
signers := make([]common.Address, (len(checkpoint.Extra)-extraVanity-extraSeal)/common.AddressLength)
for i := 0; i < len(signers); i++ {
copy(signers[i][:], checkpoint.Extra[extraVanity+i*common.AddressLength:])
}
snap = newSnapshot(c.config, c.signatures, number, hash, signers)
snap = newSnapshot(c.config, c.signatures, number, hash, validators, c.ethAPI)
if err := snap.store(c.db); err != nil {
return nil, err
}
@ -519,30 +533,43 @@ func (c *Bor) verifySeal(chain consensus.ChainReader, header *types.Header, pare
if err != nil {
return err
}
if _, ok := snap.Signers[signer]; !ok {
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
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 errRecentlySigned
}
// check if signer is correct
validators := snap.ValidatorSet.Validators
// proposer will be the last signer if block is not epoch block
proposer := snap.ValidatorSet.GetProposer().Address
if number%c.config.Epoch != 0 {
// proposer = snap.Recents[number-1]
}
proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
signerIndex, _ := snap.ValidatorSet.GetByAddress(signer)
limit := len(validators) - (len(validators)/2 + 1)
// temp index
tempIndex := signerIndex
if proposerIndex != tempIndex && limit > 0 {
if tempIndex < proposerIndex {
tempIndex = tempIndex + len(validators)
}
if tempIndex-proposerIndex > limit {
return errRecentlySigned
}
}
// Ensure that the difficulty corresponds to the turn-ness of the signer
if !c.fakeDiff {
inturn := snap.inturn(header.Number.Uint64(), signer, c.config.ProducerInterval)
if inturn && header.Difficulty.Cmp(diffInTurn) != 0 {
return errWrongDifficulty
}
if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 {
difficulty := snap.inturn(header.Number.Uint64(), signer, c.config.Epoch)
if header.Difficulty.Uint64() != difficulty {
return errWrongDifficulty
}
}
log.Info("==> New block", "number", header.Number, "hash", header.Hash().Hex(), "signer", signer.Hex())
fmt.Println("==> New block", "number", header.Number, "hash", header.Hash().Hex(), "signer", signer.Hex(), "proposer", proposer.Hex())
return nil
}
@ -559,29 +586,9 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
if err != nil {
return err
}
if number%c.config.Epoch != 0 {
c.lock.RLock()
// Gather all the proposals that make sense voting on
addresses := make([]common.Address, 0, len(c.proposals))
for address, authorize := range c.proposals {
if snap.validVote(address, authorize) {
addresses = append(addresses, address)
}
}
// If there's pending proposals, cast a vote on them
if len(addresses) > 0 {
header.Coinbase = addresses[rand.Intn(len(addresses))]
if c.proposals[header.Coinbase] {
copy(header.Nonce[:], nonceAuthVote)
} else {
copy(header.Nonce[:], nonceDropVote)
}
}
c.lock.RUnlock()
}
// Set the correct difficulty
header.Difficulty = CalcDifficulty(snap, c.signer, c.config.ProducerInterval)
header.Difficulty = CalcDifficulty(snap, c.signer, c.config.Epoch)
// Ensure the extra data has all it's components
if len(header.Extra) < extraVanity {
@ -604,10 +611,12 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
if parent == nil {
return consensus.ErrUnknownAncestor
}
header.Time = parent.Time + c.config.Period + CalcProducerDelay(snap, c.config.ProducerInterval, c.config.ProducerDelay)
header.Time = parent.Time + CalcProducerDelay(snap, c.signer, c.config.Period, c.config.Epoch, c.config.ProducerDelay)
if header.Time < uint64(time.Now().Unix()) {
header.Time = uint64(time.Now().Unix())
}
fmt.Println("parent.Time", parent.Time, "header.Time", header.Time, "number", header.Number)
return nil
}
@ -660,43 +669,52 @@ func (c *Bor) Seal(chain consensus.ChainReader, block *types.Block, results chan
signer, signFn := c.signer, c.signFn
c.lock.RUnlock()
// Bail out if we're unauthorized to sign a block
snap, err := c.snapshot(chain, number-1, header.ParentHash, nil)
if err != nil {
return err
}
if _, authorized := snap.Signers[signer]; !authorized {
// Bail out if we're unauthorized to sign a block
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
return errUnauthorizedSigner
}
// If we're amongst the recent signers, wait for the next block
for seen, recent := range snap.Recents {
count := 0
if recent == signer {
// count on how many times signer has been seen
count = count + 1
// Signer is among recents, only wait if the current block doesn't shift it out
if limit := uint64(len(snap.Signers)/2 + 1); number < limit || seen > number-limit {
log.Info("Signed recently, must wait for others")
// return nil
}
}
validators := snap.ValidatorSet.Validators
// proposer will be the last signer if block is not epoch block
proposer := snap.ValidatorSet.GetProposer().Address
if number%c.config.Epoch != 0 {
// proposer = snap.Recents[number-1]
}
proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
signerIndex, _ := snap.ValidatorSet.GetByAddress(signer)
limit := len(validators) - (len(validators)/2 + 1)
// temp index
tempIndex := signerIndex
if tempIndex < proposerIndex {
tempIndex = tempIndex + len(validators)
}
fmt.Println("Block temp index", "number", number, "tempIndex", tempIndex, "proposerIndex", proposerIndex)
if limit > 0 && tempIndex-proposerIndex > limit {
log.Info("Signed recently, must wait for others")
return nil
}
// Sweet, the protocol permits us to sign the block, wait for our time
delay := time.Unix(int64(header.Time), 0).Sub(time.Now()) // nolint: gosimple
if header.Difficulty.Cmp(diffNoTurn) == 0 {
// It's not our turn explicitly to sign, delay it a bit
wiggle := time.Duration(len(snap.Signers)/2+1) * wiggleTime
delay += time.Duration(rand.Int63n(int64(wiggle)))
wiggle := time.Duration(wiggleTime) * time.Duration(tempIndex-proposerIndex)
delay += wiggle
fmt.Println("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle))
fmt.Println("--> Sealing block with", "number", number, "delay", delay, "headerDifficulty", header.Difficulty, "signer", signer.Hex(), "proposer", proposer.Hex())
log.Trace("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle))
}
// Sign all the things!
sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header))
if err != nil {
return err
}
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
// Wait until sealing is terminated or delay timeout.
log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay))
go func() {
@ -724,7 +742,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *t
if err != nil {
return nil
}
return CalcDifficulty(snap, c.signer, c.config.ProducerInterval)
return CalcDifficulty(snap, c.signer, c.config.Epoch)
}
// SealHash returns the hash of a block prior to it being sealed.
@ -750,6 +768,11 @@ func (c *Bor) Close() error {
// GetCurrentValidators get current validators
func (c *Bor) GetCurrentValidators(number uint64) ([]*Validator, error) {
return GetValidators(number, c.config.ValidatorContract, c.ethAPI)
}
// GetValidators get current validators
func GetValidators(number uint64, validatorContract string, ethAPI *ethapi.PublicBlockChainAPI) ([]*Validator, error) {
blockNr := rpc.BlockNumber(number)
// validator set ABI
@ -765,9 +788,9 @@ func (c *Bor) GetCurrentValidators(number uint64) ([]*Validator, error) {
// call
msgData := (hexutil.Bytes)(data)
toAddress := common.HexToAddress(c.config.ValidatorContract)
toAddress := common.HexToAddress(validatorContract)
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{
result, err := ethAPI.Call(ctx, ethapi.CallArgs{
Gas: &gas,
To: &toAddress,
Data: &msgData,
@ -800,3 +823,37 @@ func (c *Bor) GetCurrentValidators(number uint64) ([]*Validator, error) {
}
return valz, nil
}
func validatorContains(a []*Validator, x *Validator) (*Validator, bool) {
for _, n := range a {
if bytes.Compare(n.Address.Bytes(), x.Address.Bytes()) == 0 {
return n, true
}
}
return nil, false
}
func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator) *ValidatorSet {
v := oldValidatorSet
oldVals := v.Validators
var changes []*Validator
for _, ov := range oldVals {
if f, ok := validatorContains(newVals, ov); ok {
ov.VotingPower = f.VotingPower
} else {
ov.VotingPower = 0
}
changes = append(changes, ov)
}
for _, nv := range newVals {
if _, ok := validatorContains(changes, nv); !ok {
changes = append(changes, nv)
}
}
v.UpdateWithChangeSet(changes)
return v
}

View file

@ -19,11 +19,12 @@ package bor
import (
"bytes"
"encoding/json"
"sort"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/params"
lru "github.com/hashicorp/golang-lru"
)
@ -47,14 +48,15 @@ type Tally struct {
// Snapshot is the state of the authorization voting at a given point in time.
type Snapshot struct {
config *params.BorConfig // Consensus engine parameters to fine tune behavior
sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
ethAPI *ethapi.PublicBlockChainAPI
sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
Number uint64 `json:"number"` // Block number where the snapshot was created
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
Signers map[common.Address]struct{} `json:"signers"` // Set of authorized signers at this moment
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
Votes []*Vote `json:"votes"` // List of votes cast in chronological order
Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating
Number uint64 `json:"number"` // Block number where the snapshot was created
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
ValidatorSet *ValidatorSet `json:"validatorSet"` // Validator set at this moment
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
// Votes []*Vote `json:"votes"` // List of votes cast in chronological order
// Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating
}
// signersAscending implements the sort interface to allow sorting a list of addresses
@ -67,24 +69,23 @@ 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
// the genesis block.
func newSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, signers []common.Address) *Snapshot {
func newSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, validators []*Validator, ethAPI *ethapi.PublicBlockChainAPI) *Snapshot {
snap := &Snapshot{
config: config,
sigcache: sigcache,
Number: number,
Hash: hash,
Signers: make(map[common.Address]struct{}),
Recents: make(map[uint64]common.Address),
Tally: make(map[common.Address]Tally),
}
for _, signer := range signers {
snap.Signers[signer] = struct{}{}
config: config,
ethAPI: ethAPI,
sigcache: sigcache,
Number: number,
Hash: hash,
ValidatorSet: NewValidatorSet(validators),
Recents: make(map[uint64]common.Address),
// Tally: make(map[common.Address]Tally),
}
fmt.Println("New validator set", "number", number, "proposer", snap.ValidatorSet.Proposer.Address.Hex())
return snap
}
// loadSnapshot loads an existing snapshot from the database.
func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash, ethAPI *ethapi.PublicBlockChainAPI) (*Snapshot, error) {
blob, err := db.Get(append([]byte("bor-"), hash[:]...))
if err != nil {
return nil, err
@ -95,6 +96,7 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
}
snap.config = config
snap.sigcache = sigcache
snap.ethAPI = ethAPI
return snap, nil
}
@ -111,75 +113,71 @@ func (s *Snapshot) store(db ethdb.Database) error {
// copy creates a deep copy of the snapshot, though not the individual votes.
func (s *Snapshot) copy() *Snapshot {
cpy := &Snapshot{
config: s.config,
sigcache: s.sigcache,
Number: s.Number,
Hash: s.Hash,
Signers: make(map[common.Address]struct{}),
Recents: make(map[uint64]common.Address),
Votes: make([]*Vote, len(s.Votes)),
Tally: make(map[common.Address]Tally),
}
for signer := range s.Signers {
cpy.Signers[signer] = struct{}{}
config: s.config,
ethAPI: s.ethAPI,
sigcache: s.sigcache,
Number: s.Number,
Hash: s.Hash,
ValidatorSet: s.ValidatorSet.Copy(),
Recents: make(map[uint64]common.Address),
// Votes: make([]*Vote, len(s.Votes)),
// Tally: make(map[common.Address]Tally),
}
for block, signer := range s.Recents {
cpy.Recents[block] = signer
}
for address, tally := range s.Tally {
cpy.Tally[address] = tally
}
copy(cpy.Votes, s.Votes)
// for address, tally := range s.Tally {
// cpy.Tally[address] = tally
// }
// copy(cpy.Votes, s.Votes)
return cpy
}
// validVote returns whether it makes sense to cast the specified vote in the
// given snapshot context (e.g. don't try to add an already authorized signer).
func (s *Snapshot) validVote(address common.Address, authorize bool) bool {
_, signer := s.Signers[address]
return (signer && !authorize) || (!signer && authorize)
}
// // validVote returns whether it makes sense to cast the specified vote in the
// // given snapshot context (e.g. don't try to add an already authorized signer).
// func (s *Snapshot) validVote(address common.Address, authorize bool) bool {
// _, signer := s.Signers[address]
// return (signer && !authorize) || (!signer && authorize)
// }
// cast adds a new vote into the tally.
func (s *Snapshot) cast(address common.Address, authorize bool) bool {
// Ensure the vote is meaningful
if !s.validVote(address, authorize) {
return false
}
// Cast the vote into an existing or new tally
if old, ok := s.Tally[address]; ok {
old.Votes++
s.Tally[address] = old
} else {
s.Tally[address] = Tally{Authorize: authorize, Votes: 1}
}
return true
}
// // cast adds a new vote into the tally.
// func (s *Snapshot) cast(address common.Address, authorize bool) bool {
// // Ensure the vote is meaningful
// if !s.validVote(address, authorize) {
// return false
// }
// // Cast the vote into an existing or new tally
// if old, ok := s.Tally[address]; ok {
// old.Votes++
// s.Tally[address] = old
// } else {
// s.Tally[address] = Tally{Authorize: authorize, Votes: 1}
// }
// return true
// }
// uncast removes a previously cast vote from the tally.
func (s *Snapshot) uncast(address common.Address, authorize bool) bool {
// If there's no tally, it's a dangling vote, just drop
tally, ok := s.Tally[address]
if !ok {
return false
}
// Ensure we only revert counted votes
if tally.Authorize != authorize {
return false
}
// Otherwise revert the vote
if tally.Votes > 1 {
tally.Votes--
s.Tally[address] = tally
} else {
delete(s.Tally, address)
}
return true
}
// // uncast removes a previously cast vote from the tally.
// func (s *Snapshot) uncast(address common.Address, authorize bool) bool {
// // If there's no tally, it's a dangling vote, just drop
// tally, ok := s.Tally[address]
// if !ok {
// return false
// }
// // Ensure we only revert counted votes
// if tally.Authorize != authorize {
// return false
// }
// // Otherwise revert the vote
// if tally.Votes > 1 {
// tally.Votes--
// s.Tally[address] = tally
// } else {
// delete(s.Tally, address)
// }
// return true
// }
// apply creates a new authorization snapshot by applying the given headers to
// the original one.
func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
// Allow passing in no headers for cleaner code
if len(headers) == 0 {
@ -188,11 +186,11 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
// Sanity check that the headers can be applied
for i := 0; i < len(headers)-1; i++ {
if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
return nil, errInvalidVotingChain
return nil, errOutOfRangeChain
}
}
if headers[0].Number.Uint64() != s.Number+1 {
return nil, errInvalidVotingChain
return nil, errOutOfRangeChain
}
// Iterate through the headers and create a new snapshot
snap := s.copy()
@ -200,91 +198,125 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
for _, header := range headers {
// Remove any votes on checkpoint blocks
number := header.Number.Uint64()
if number%s.config.Epoch == 0 {
snap.Votes = nil
snap.Tally = make(map[common.Address]Tally)
if (number+1)%s.config.Epoch == 0 {
// snap.Votes = nil
// snap.Tally = make(map[common.Address]Tally)
}
// Delete the oldest signer from the recent list to allow it signing again
if limit := uint64(len(snap.Signers)/2 + 1); number >= limit {
delete(snap.Recents, number-limit)
if number >= s.config.Epoch && number-s.config.Epoch >= 0 {
delete(snap.Recents, number-s.config.Epoch)
}
// Resolve the authorization key and check against signers
signer, err := ecrecover(header, s.sigcache)
if err != nil {
return nil, err
}
if _, ok := snap.Signers[signer]; !ok {
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
return nil, errUnauthorizedSigner
}
for _, recent := range snap.Recents {
if recent == signer {
// return nil, errRecentlySigned
//
// Check validator
//
validators := snap.ValidatorSet.Validators
// proposer will be the last signer if block is not epoch block
proposer := snap.ValidatorSet.GetProposer().Address
// if number%s.config.Epoch != 0 {
// proposer = snap.Recents[number-1]
// }
proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
signerIndex, _ := snap.ValidatorSet.GetByAddress(signer)
limit := len(validators) - (len(validators)/2 + 1)
// temp index
tempIndex := signerIndex
if proposerIndex != tempIndex && limit > 0 {
if tempIndex < proposerIndex {
tempIndex = tempIndex + len(validators)
}
if tempIndex-proposerIndex > limit {
return nil, errRecentlySigned
}
}
// add recents
snap.Recents[number] = signer
// Header authorized, discard any previous votes from the signer
for i, vote := range snap.Votes {
if vote.Signer == signer && vote.Address == header.Coinbase {
// Uncast the vote from the cached tally
snap.uncast(vote.Address, vote.Authorize)
// Uncast the vote from the chronological list
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
break // only one vote allowed
}
fmt.Println("Recent signer", "number", number, "signer", signer.Hex())
// change proposer on epoch
if number > 0 && (number+1)%s.config.Epoch == 0 {
newVals, _ := GetValidators(number, snap.config.ValidatorContract, snap.ethAPI)
v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals)
v.IncrementProposerPriority(1)
snap.ValidatorSet = v
fmt.Println("New validator set", "number", number, "proposer", v.Proposer.Address.Hex())
}
// // Header authorized, discard any previous votes from the signer
// for i, vote := range snap.Votes {
// if vote.Signer == signer && vote.Address == header.Coinbase {
// // Uncast the vote from the cached tally
// snap.uncast(vote.Address, vote.Authorize)
// // Uncast the vote from the chronological list
// snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
// break // only one vote allowed
// }
// }
// Tally up the new vote from the signer
var authorize bool
switch {
case bytes.Equal(header.Nonce[:], nonceAuthVote):
authorize = true
case bytes.Equal(header.Nonce[:], nonceDropVote):
authorize = false
default:
return nil, errInvalidVote
}
if snap.cast(header.Coinbase, authorize) {
snap.Votes = append(snap.Votes, &Vote{
Signer: signer,
Block: number,
Address: header.Coinbase,
Authorize: authorize,
})
}
// var authorize bool
// switch {
// case bytes.Equal(header.Nonce[:], nonceAuthVote):
// authorize = true
// case bytes.Equal(header.Nonce[:], nonceDropVote):
// authorize = false
// default:
// return nil, errInvalidVote
// }
// if snap.cast(header.Coinbase, authorize) {
// snap.Votes = append(snap.Votes, &Vote{
// Signer: signer,
// Block: number,
// Address: header.Coinbase,
// Authorize: authorize,
// })
// }
// If the vote passed, update the list of signers
if tally := snap.Tally[header.Coinbase]; tally.Votes > len(snap.Signers)/2 {
if tally.Authorize {
snap.Signers[header.Coinbase] = struct{}{}
} else {
delete(snap.Signers, header.Coinbase)
// if tally := snap.Tally[header.Coinbase]; tally.Votes > len(snap.Signers)/2 {
// if tally.Authorize {
// snap.Signers[header.Coinbase] = struct{}{}
// } else {
// delete(snap.Signers, header.Coinbase)
// Signer list shrunk, delete any leftover recent caches
if limit := uint64(len(snap.Signers)/2 + 1); number >= limit {
delete(snap.Recents, number-limit)
}
// Discard any previous votes the deauthorized signer cast
for i := 0; i < len(snap.Votes); i++ {
if snap.Votes[i].Signer == header.Coinbase {
// Uncast the vote from the cached tally
snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize)
// // Signer list shrunk, delete any leftover recent caches
// if limit := uint64(len(snap.Signers)/2 + 1); number >= limit {
// delete(snap.Recents, number-limit)
// }
// // Discard any previous votes the deauthorized signer cast
// for i := 0; i < len(snap.Votes); i++ {
// if snap.Votes[i].Signer == header.Coinbase {
// // Uncast the vote from the cached tally
// snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize)
// Uncast the vote from the chronological list
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
// // Uncast the vote from the chronological list
// snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
i--
}
}
}
// Discard any previous votes around the just changed account
for i := 0; i < len(snap.Votes); i++ {
if snap.Votes[i].Address == header.Coinbase {
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
i--
}
}
delete(snap.Tally, header.Coinbase)
}
// i--
// }
// }
// }
// // Discard any previous votes around the just changed account
// for i := 0; i < len(snap.Votes); i++ {
// if snap.Votes[i].Address == header.Coinbase {
// snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
// i--
// }
// }
// delete(snap.Tally, header.Coinbase)
// }
}
snap.Number += uint64(len(headers))
snap.Hash = headers[len(headers)-1].Hash()
@ -294,19 +326,54 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
// signers retrieves the list of authorized signers in ascending order.
func (s *Snapshot) signers() []common.Address {
sigs := make([]common.Address, 0, len(s.Signers))
for sig := range s.Signers {
sigs = append(sigs, sig)
sigs := make([]common.Address, 0, len(s.ValidatorSet.Validators))
for _, sig := range s.ValidatorSet.Validators {
sigs = append(sigs, sig.Address)
}
sort.Sort(signersAscending(sigs))
return sigs
}
// inturn returns if a signer at a given block height is in-turn or not.
func (s *Snapshot) inturn(number uint64, signer common.Address, producerPeriod uint64) bool {
signers, offset := s.signers(), 0
for offset < len(signers) && signers[offset] != signer {
offset++
func (s *Snapshot) inturn(number uint64, signer common.Address, epoch uint64) uint64 {
// if signer is empty
if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 {
return 1
}
return ((number / producerPeriod) % uint64(len(signers))) == uint64(offset)
validators := s.ValidatorSet.Validators
proposer := s.ValidatorSet.GetProposer().Address
totalValidators := len(validators)
// proposer will be the last signer if block is not epoch block
// proposer := snap.ValidatorSet.GetProposer().Address
// if number%epoch != 0 {
// proposer = snap.Recents[number-1]
// }
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
// temp index
tempIndex := signerIndex
if tempIndex < proposerIndex {
tempIndex = tempIndex + totalValidators
}
return uint64(totalValidators - (tempIndex - proposerIndex))
// signers, offset := s.signers(), 0
// for offset < len(signers) && signers[offset] != signer {
// offset++
// }
// return ((number / producerPeriod) % uint64(len(signers))) == uint64(offset)
// // if block is epoch start block, proposer will be inturn signer
// if s.Number%epoch == 0 {
// if bytes.Compare(proposer.Address.Bytes(), signer.Bytes()) == 0 {
// return true
// }
// // if block is not epoch block, last block signer will be inturn
// } else if bytes.Compare(lastSigner.Bytes(), signer.Bytes()) == 0 {
// return false
// }
// return false
}

View file

@ -228,7 +228,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
// The first thing the node will do is reconstruct the verification data for
// the head block (ethash cache or clique voting snapshot). Might as well do
// it in advance.
bc.engine.VerifyHeader(bc, bc.CurrentHeader(), true)
// bc.engine.VerifyHeader(bc, bc.CurrentHeader(), true)
if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 {
var (

View file

@ -183,7 +183,10 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
TrieTimeLimit: config.TrieTimeout,
}
)
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve)
eth.engine.VerifyHeader(eth.blockchain, eth.blockchain.CurrentHeader(), true) // TODO think on it
if err != nil {
return nil, err
}