mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-11 22:43:47 +00:00
fix block time bug
This commit is contained in:
parent
ad198aeefd
commit
f12ae309cf
4 changed files with 381 additions and 254 deletions
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -39,7 +38,7 @@ const (
|
||||||
inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
|
inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
|
||||||
inmemorySignatures = 4096 // Number of recent block signatures 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.
|
// Bor protocol constants.
|
||||||
|
|
@ -116,9 +115,9 @@ var (
|
||||||
// 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")
|
||||||
|
|
||||||
// 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.
|
// 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 is returned if a header is signed by a non-authorized entity.
|
||||||
errUnauthorizedSigner = errors.New("unauthorized signer")
|
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
|
// 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
|
// that a new block should have based on the previous blocks in the chain and the
|
||||||
// current signer.
|
// current signer.
|
||||||
func CalcDifficulty(snap *Snapshot, signer common.Address, producerPeriod uint64) *big.Int {
|
func CalcDifficulty(snap *Snapshot, signer common.Address, epoch uint64) *big.Int {
|
||||||
if snap.inturn(snap.Number+1, signer, producerPeriod) {
|
return big.NewInt(0).SetUint64(snap.inturn(snap.Number+1, signer, epoch))
|
||||||
return new(big.Int).Set(diffInTurn)
|
|
||||||
}
|
|
||||||
return new(big.Int).Set(diffNoTurn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalcProducerDelay is the producer delay algorithm based on block time.
|
// CalcProducerDelay is the producer delay algorithm based on block time.
|
||||||
func CalcProducerDelay(snap *Snapshot, producerInterval uint64, producerDelay uint64) uint64 {
|
func CalcProducerDelay(snap *Snapshot, signer common.Address, period uint64, epoch uint64, producerDelay uint64) uint64 {
|
||||||
isFirstBlock := (snap.Number + 1) % producerInterval
|
// lastSigner := snap.Recents[snap.Number]
|
||||||
if isFirstBlock == 0 {
|
// 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
|
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
|
// 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
|
signFn SignerFn // Signer function to authorize hashes with
|
||||||
lock sync.RWMutex // Protects the signer fields
|
lock sync.RWMutex // Protects the signer fields
|
||||||
|
|
||||||
ethAPI *ethapi.PublicBlockChainAPI
|
ethAPI *ethapi.PublicBlockChainAPI
|
||||||
|
validatorSetABI abi.ABI
|
||||||
|
|
||||||
// The fields below are for testing only
|
// The fields below are for testing only
|
||||||
fakeDiff bool // Skip difficulty verifications
|
fakeDiff bool // Skip difficulty verifications
|
||||||
|
|
@ -248,18 +253,21 @@ func New(config *params.BorConfig, db ethdb.Database, ethAPI *ethapi.PublicBlock
|
||||||
if conf.Epoch == 0 {
|
if conf.Epoch == 0 {
|
||||||
conf.Epoch = epochLength
|
conf.Epoch = epochLength
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the snapshot caches and create the engine
|
// Allocate the snapshot caches and create the engine
|
||||||
recents, _ := lru.NewARC(inmemorySnapshots)
|
recents, _ := lru.NewARC(inmemorySnapshots)
|
||||||
signatures, _ := lru.NewARC(inmemorySignatures)
|
signatures, _ := lru.NewARC(inmemorySignatures)
|
||||||
|
validatorSetABI, _ := abi.JSON(strings.NewReader(validatorset.ValidatorsetABI))
|
||||||
return &Bor{
|
c := &Bor{
|
||||||
config: &conf,
|
config: &conf,
|
||||||
db: db,
|
db: db,
|
||||||
ethAPI: ethAPI,
|
ethAPI: ethAPI,
|
||||||
recents: recents,
|
recents: recents,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
proposals: make(map[common.Address]bool),
|
proposals: make(map[common.Address]bool),
|
||||||
|
validatorSetABI: validatorSetABI,
|
||||||
}
|
}
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Author implements consensus.Engine, returning the Ethereum address recovered
|
// 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
|
return ErrInvalidTimestamp
|
||||||
}
|
}
|
||||||
// Retrieve the snapshot needed to verify this header and cache it
|
// Retrieve the snapshot needed to verify this header and cache it
|
||||||
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
|
// snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
|
||||||
// If the block is a checkpoint block, verify the signer list
|
// If the block is a checkpoint block, verify the signer list
|
||||||
|
// TODO verify signers
|
||||||
if number%c.config.Epoch == 0 {
|
if number%c.config.Epoch == 0 {
|
||||||
signers := make([]byte, len(snap.Signers)*common.AddressLength)
|
// signers := make([]byte, len(snap.Signers)*common.AddressLength)
|
||||||
for i, signer := range snap.signers() {
|
// for i, signer := range snap.signers() {
|
||||||
copy(signers[i*common.AddressLength:], signer[:])
|
// copy(signers[i*common.AddressLength:], signer[:])
|
||||||
}
|
// }
|
||||||
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 errMismatchingCheckpointSigners
|
// return errMismatchingCheckpointSigners
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
// All basic checks passed, verify the seal and return
|
// All basic checks passed, verify the seal and return
|
||||||
return c.verifySeal(chain, header, parents)
|
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 an on-disk checkpoint snapshot can be found, use that
|
||||||
if number%voteSnapshotInterval == 0 {
|
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)
|
log.Trace("Loaded voting snapshot from disk", "number", number, "hash", hash)
|
||||||
snap = s
|
snap = s
|
||||||
break
|
break
|
||||||
|
|
@ -428,15 +438,19 @@ func (c *Bor) snapshot(chain consensus.ChainReader, number uint64, hash common.H
|
||||||
if checkpoint != nil {
|
if checkpoint != nil {
|
||||||
hash := checkpoint.Hash()
|
hash := checkpoint.Hash()
|
||||||
|
|
||||||
// validatorSet := new(ValidatorSet)
|
// current validators
|
||||||
// TODO populate validator set
|
validators, err := c.GetCurrentValidators(number)
|
||||||
c.GetCurrentValidators(number)
|
if err != nil {
|
||||||
|
// Handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO remove signer
|
||||||
signers := make([]common.Address, (len(checkpoint.Extra)-extraVanity-extraSeal)/common.AddressLength)
|
signers := make([]common.Address, (len(checkpoint.Extra)-extraVanity-extraSeal)/common.AddressLength)
|
||||||
for i := 0; i < len(signers); i++ {
|
for i := 0; i < len(signers); i++ {
|
||||||
copy(signers[i][:], checkpoint.Extra[extraVanity+i*common.AddressLength:])
|
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 {
|
if err := snap.store(c.db); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -519,30 +533,43 @@ func (c *Bor) verifySeal(chain consensus.ChainReader, header *types.Header, pare
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, ok := snap.Signers[signer]; !ok {
|
|
||||||
|
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
||||||
return errUnauthorizedSigner
|
return errUnauthorizedSigner
|
||||||
}
|
}
|
||||||
for seen, recent := range snap.Recents {
|
|
||||||
if recent == signer {
|
// check if signer is correct
|
||||||
// Signer is among recents, only fail if the current block doesn't shift it out
|
validators := snap.ValidatorSet.Validators
|
||||||
if limit := uint64(len(snap.Signers)/2 + 1); seen > number-limit {
|
// proposer will be the last signer if block is not epoch block
|
||||||
// return errRecentlySigned
|
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
|
// Ensure that the difficulty corresponds to the turn-ness of the signer
|
||||||
if !c.fakeDiff {
|
if !c.fakeDiff {
|
||||||
inturn := snap.inturn(header.Number.Uint64(), signer, c.config.ProducerInterval)
|
difficulty := snap.inturn(header.Number.Uint64(), signer, c.config.Epoch)
|
||||||
if inturn && header.Difficulty.Cmp(diffInTurn) != 0 {
|
if header.Difficulty.Uint64() != difficulty {
|
||||||
return errWrongDifficulty
|
|
||||||
}
|
|
||||||
if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 {
|
|
||||||
return errWrongDifficulty
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -559,29 +586,9 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// 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
|
// Ensure the extra data has all it's components
|
||||||
if len(header.Extra) < extraVanity {
|
if len(header.Extra) < extraVanity {
|
||||||
|
|
@ -604,10 +611,12 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return consensus.ErrUnknownAncestor
|
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()) {
|
if header.Time < uint64(time.Now().Unix()) {
|
||||||
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -660,43 +669,52 @@ func (c *Bor) Seal(chain consensus.ChainReader, block *types.Block, results chan
|
||||||
signer, signFn := c.signer, c.signFn
|
signer, signFn := c.signer, c.signFn
|
||||||
c.lock.RUnlock()
|
c.lock.RUnlock()
|
||||||
|
|
||||||
// Bail out if we're unauthorized to sign a block
|
|
||||||
snap, err := c.snapshot(chain, number-1, header.ParentHash, nil)
|
snap, err := c.snapshot(chain, number-1, header.ParentHash, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
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
|
validators := snap.ValidatorSet.Validators
|
||||||
if limit := uint64(len(snap.Signers)/2 + 1); number < limit || seen > number-limit {
|
// proposer will be the last signer if block is not epoch block
|
||||||
log.Info("Signed recently, must wait for others")
|
proposer := snap.ValidatorSet.GetProposer().Address
|
||||||
// return nil
|
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
|
// 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
|
delay := time.Unix(int64(header.Time), 0).Sub(time.Now()) // nolint: gosimple
|
||||||
if header.Difficulty.Cmp(diffNoTurn) == 0 {
|
wiggle := time.Duration(wiggleTime) * time.Duration(tempIndex-proposerIndex)
|
||||||
// It's not our turn explicitly to sign, delay it a bit
|
delay += wiggle
|
||||||
wiggle := time.Duration(len(snap.Signers)/2+1) * wiggleTime
|
|
||||||
delay += time.Duration(rand.Int63n(int64(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!
|
// Sign all the things!
|
||||||
sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header))
|
sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
|
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
|
||||||
|
|
||||||
// Wait until sealing is terminated or delay timeout.
|
// Wait until sealing is terminated or delay timeout.
|
||||||
log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay))
|
log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay))
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -724,7 +742,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *t
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 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.
|
// 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
|
// GetCurrentValidators get current validators
|
||||||
func (c *Bor) GetCurrentValidators(number uint64) ([]*Validator, error) {
|
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)
|
blockNr := rpc.BlockNumber(number)
|
||||||
|
|
||||||
// validator set ABI
|
// validator set ABI
|
||||||
|
|
@ -765,9 +788,9 @@ func (c *Bor) GetCurrentValidators(number uint64) ([]*Validator, error) {
|
||||||
|
|
||||||
// call
|
// call
|
||||||
msgData := (hexutil.Bytes)(data)
|
msgData := (hexutil.Bytes)(data)
|
||||||
toAddress := common.HexToAddress(c.config.ValidatorContract)
|
toAddress := common.HexToAddress(validatorContract)
|
||||||
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
|
||||||
result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{
|
result, err := ethAPI.Call(ctx, ethapi.CallArgs{
|
||||||
Gas: &gas,
|
Gas: &gas,
|
||||||
To: &toAddress,
|
To: &toAddress,
|
||||||
Data: &msgData,
|
Data: &msgData,
|
||||||
|
|
@ -800,3 +823,37 @@ func (c *Bor) GetCurrentValidators(number uint64) ([]*Validator, error) {
|
||||||
}
|
}
|
||||||
return valz, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,12 @@ package bor
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"sort"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
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.
|
// Snapshot is the state of the authorization voting at a given point in time.
|
||||||
type Snapshot struct {
|
type Snapshot struct {
|
||||||
config *params.BorConfig // Consensus engine parameters to fine tune behavior
|
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
|
Number uint64 `json:"number"` // Block number where the snapshot was created
|
||||||
Hash common.Hash `json:"hash"` // Block hash 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
|
ValidatorSet *ValidatorSet `json:"validatorSet"` // Validator set at this moment
|
||||||
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
|
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
|
// Votes []*Vote `json:"votes"` // List of votes cast in chronological order
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// signersAscending implements the sort interface to allow sorting a list of addresses
|
// 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
|
// 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
|
||||||
// the genesis block.
|
// 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{
|
snap := &Snapshot{
|
||||||
config: config,
|
config: config,
|
||||||
sigcache: sigcache,
|
ethAPI: ethAPI,
|
||||||
Number: number,
|
sigcache: sigcache,
|
||||||
Hash: hash,
|
Number: number,
|
||||||
Signers: make(map[common.Address]struct{}),
|
Hash: hash,
|
||||||
Recents: make(map[uint64]common.Address),
|
ValidatorSet: NewValidatorSet(validators),
|
||||||
Tally: make(map[common.Address]Tally),
|
Recents: make(map[uint64]common.Address),
|
||||||
}
|
// Tally: make(map[common.Address]Tally),
|
||||||
for _, signer := range signers {
|
|
||||||
snap.Signers[signer] = struct{}{}
|
|
||||||
}
|
}
|
||||||
|
fmt.Println("New validator set", "number", number, "proposer", snap.ValidatorSet.Proposer.Address.Hex())
|
||||||
return snap
|
return snap
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadSnapshot loads an existing snapshot from the database.
|
// 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[:]...))
|
blob, err := db.Get(append([]byte("bor-"), hash[:]...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -95,6 +96,7 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
|
||||||
}
|
}
|
||||||
snap.config = config
|
snap.config = config
|
||||||
snap.sigcache = sigcache
|
snap.sigcache = sigcache
|
||||||
|
snap.ethAPI = ethAPI
|
||||||
|
|
||||||
return snap, nil
|
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.
|
// copy creates a deep copy of the snapshot, though not the individual votes.
|
||||||
func (s *Snapshot) copy() *Snapshot {
|
func (s *Snapshot) copy() *Snapshot {
|
||||||
cpy := &Snapshot{
|
cpy := &Snapshot{
|
||||||
config: s.config,
|
config: s.config,
|
||||||
sigcache: s.sigcache,
|
ethAPI: s.ethAPI,
|
||||||
Number: s.Number,
|
sigcache: s.sigcache,
|
||||||
Hash: s.Hash,
|
Number: s.Number,
|
||||||
Signers: make(map[common.Address]struct{}),
|
Hash: s.Hash,
|
||||||
Recents: make(map[uint64]common.Address),
|
ValidatorSet: s.ValidatorSet.Copy(),
|
||||||
Votes: make([]*Vote, len(s.Votes)),
|
Recents: make(map[uint64]common.Address),
|
||||||
Tally: make(map[common.Address]Tally),
|
// Votes: make([]*Vote, len(s.Votes)),
|
||||||
}
|
// Tally: make(map[common.Address]Tally),
|
||||||
for signer := range s.Signers {
|
|
||||||
cpy.Signers[signer] = struct{}{}
|
|
||||||
}
|
}
|
||||||
for block, signer := range s.Recents {
|
for block, signer := range s.Recents {
|
||||||
cpy.Recents[block] = signer
|
cpy.Recents[block] = signer
|
||||||
}
|
}
|
||||||
for address, tally := range s.Tally {
|
// for address, tally := range s.Tally {
|
||||||
cpy.Tally[address] = tally
|
// cpy.Tally[address] = tally
|
||||||
}
|
// }
|
||||||
copy(cpy.Votes, s.Votes)
|
// copy(cpy.Votes, s.Votes)
|
||||||
|
|
||||||
return cpy
|
return cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
// validVote returns whether it makes sense to cast the specified vote in the
|
// // 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).
|
// // given snapshot context (e.g. don't try to add an already authorized signer).
|
||||||
func (s *Snapshot) validVote(address common.Address, authorize bool) bool {
|
// func (s *Snapshot) validVote(address common.Address, authorize bool) bool {
|
||||||
_, signer := s.Signers[address]
|
// _, signer := s.Signers[address]
|
||||||
return (signer && !authorize) || (!signer && authorize)
|
// return (signer && !authorize) || (!signer && authorize)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// cast adds a new vote into the tally.
|
// // cast adds a new vote into the tally.
|
||||||
func (s *Snapshot) cast(address common.Address, authorize bool) bool {
|
// func (s *Snapshot) cast(address common.Address, authorize bool) bool {
|
||||||
// Ensure the vote is meaningful
|
// // Ensure the vote is meaningful
|
||||||
if !s.validVote(address, authorize) {
|
// if !s.validVote(address, authorize) {
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
// Cast the vote into an existing or new tally
|
// // Cast the vote into an existing or new tally
|
||||||
if old, ok := s.Tally[address]; ok {
|
// if old, ok := s.Tally[address]; ok {
|
||||||
old.Votes++
|
// old.Votes++
|
||||||
s.Tally[address] = old
|
// s.Tally[address] = old
|
||||||
} else {
|
// } else {
|
||||||
s.Tally[address] = Tally{Authorize: authorize, Votes: 1}
|
// s.Tally[address] = Tally{Authorize: authorize, Votes: 1}
|
||||||
}
|
// }
|
||||||
return true
|
// return true
|
||||||
}
|
// }
|
||||||
|
|
||||||
// uncast removes a previously cast vote from the tally.
|
// // uncast removes a previously cast vote from the tally.
|
||||||
func (s *Snapshot) uncast(address common.Address, authorize bool) bool {
|
// func (s *Snapshot) uncast(address common.Address, authorize bool) bool {
|
||||||
// If there's no tally, it's a dangling vote, just drop
|
// // If there's no tally, it's a dangling vote, just drop
|
||||||
tally, ok := s.Tally[address]
|
// tally, ok := s.Tally[address]
|
||||||
if !ok {
|
// if !ok {
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
// Ensure we only revert counted votes
|
// // Ensure we only revert counted votes
|
||||||
if tally.Authorize != authorize {
|
// if tally.Authorize != authorize {
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
// Otherwise revert the vote
|
// // Otherwise revert the vote
|
||||||
if tally.Votes > 1 {
|
// if tally.Votes > 1 {
|
||||||
tally.Votes--
|
// tally.Votes--
|
||||||
s.Tally[address] = tally
|
// s.Tally[address] = tally
|
||||||
} else {
|
// } else {
|
||||||
delete(s.Tally, address)
|
// delete(s.Tally, address)
|
||||||
}
|
// }
|
||||||
return true
|
// 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) {
|
func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
// Allow passing in no headers for cleaner code
|
// Allow passing in no headers for cleaner code
|
||||||
if len(headers) == 0 {
|
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
|
// Sanity check that the headers can be applied
|
||||||
for i := 0; i < len(headers)-1; i++ {
|
for i := 0; i < len(headers)-1; i++ {
|
||||||
if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
|
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 {
|
if headers[0].Number.Uint64() != s.Number+1 {
|
||||||
return nil, errInvalidVotingChain
|
return nil, errOutOfRangeChain
|
||||||
}
|
}
|
||||||
// Iterate through the headers and create a new snapshot
|
// Iterate through the headers and create a new snapshot
|
||||||
snap := s.copy()
|
snap := s.copy()
|
||||||
|
|
@ -200,91 +198,125 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
for _, header := range headers {
|
for _, header := range headers {
|
||||||
// Remove any votes on checkpoint blocks
|
// Remove any votes on checkpoint blocks
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
if number%s.config.Epoch == 0 {
|
if (number+1)%s.config.Epoch == 0 {
|
||||||
snap.Votes = nil
|
// snap.Votes = nil
|
||||||
snap.Tally = make(map[common.Address]Tally)
|
// snap.Tally = make(map[common.Address]Tally)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the oldest signer from the recent list to allow it signing again
|
// Delete the oldest signer from the recent list to allow it signing again
|
||||||
if limit := uint64(len(snap.Signers)/2 + 1); number >= limit {
|
if number >= s.config.Epoch && number-s.config.Epoch >= 0 {
|
||||||
delete(snap.Recents, number-limit)
|
delete(snap.Recents, number-s.config.Epoch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the authorization key and check against signers
|
// Resolve the authorization key and check against signers
|
||||||
signer, err := ecrecover(header, s.sigcache)
|
signer, err := ecrecover(header, s.sigcache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if _, ok := snap.Signers[signer]; !ok {
|
|
||||||
|
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
||||||
return nil, errUnauthorizedSigner
|
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
|
snap.Recents[number] = signer
|
||||||
|
fmt.Println("Recent signer", "number", number, "signer", signer.Hex())
|
||||||
// Header authorized, discard any previous votes from the signer
|
// change proposer on epoch
|
||||||
for i, vote := range snap.Votes {
|
if number > 0 && (number+1)%s.config.Epoch == 0 {
|
||||||
if vote.Signer == signer && vote.Address == header.Coinbase {
|
newVals, _ := GetValidators(number, snap.config.ValidatorContract, snap.ethAPI)
|
||||||
// Uncast the vote from the cached tally
|
v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals)
|
||||||
snap.uncast(vote.Address, vote.Authorize)
|
v.IncrementProposerPriority(1)
|
||||||
|
snap.ValidatorSet = v
|
||||||
// Uncast the vote from the chronological list
|
fmt.Println("New validator set", "number", number, "proposer", v.Proposer.Address.Hex())
|
||||||
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
|
|
||||||
break // only one vote allowed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// // 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
|
// Tally up the new vote from the signer
|
||||||
var authorize bool
|
// var authorize bool
|
||||||
switch {
|
// switch {
|
||||||
case bytes.Equal(header.Nonce[:], nonceAuthVote):
|
// case bytes.Equal(header.Nonce[:], nonceAuthVote):
|
||||||
authorize = true
|
// authorize = true
|
||||||
case bytes.Equal(header.Nonce[:], nonceDropVote):
|
// case bytes.Equal(header.Nonce[:], nonceDropVote):
|
||||||
authorize = false
|
// authorize = false
|
||||||
default:
|
// default:
|
||||||
return nil, errInvalidVote
|
// return nil, errInvalidVote
|
||||||
}
|
// }
|
||||||
if snap.cast(header.Coinbase, authorize) {
|
// if snap.cast(header.Coinbase, authorize) {
|
||||||
snap.Votes = append(snap.Votes, &Vote{
|
// snap.Votes = append(snap.Votes, &Vote{
|
||||||
Signer: signer,
|
// Signer: signer,
|
||||||
Block: number,
|
// Block: number,
|
||||||
Address: header.Coinbase,
|
// Address: header.Coinbase,
|
||||||
Authorize: authorize,
|
// Authorize: authorize,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
// If the vote passed, update the list of signers
|
// If the vote passed, update the list of signers
|
||||||
if tally := snap.Tally[header.Coinbase]; tally.Votes > len(snap.Signers)/2 {
|
// if tally := snap.Tally[header.Coinbase]; tally.Votes > len(snap.Signers)/2 {
|
||||||
if tally.Authorize {
|
// if tally.Authorize {
|
||||||
snap.Signers[header.Coinbase] = struct{}{}
|
// snap.Signers[header.Coinbase] = struct{}{}
|
||||||
} else {
|
// } else {
|
||||||
delete(snap.Signers, header.Coinbase)
|
// delete(snap.Signers, header.Coinbase)
|
||||||
|
|
||||||
// Signer list shrunk, delete any leftover recent caches
|
// // Signer list shrunk, delete any leftover recent caches
|
||||||
if limit := uint64(len(snap.Signers)/2 + 1); number >= limit {
|
// if limit := uint64(len(snap.Signers)/2 + 1); number >= limit {
|
||||||
delete(snap.Recents, number-limit)
|
// delete(snap.Recents, number-limit)
|
||||||
}
|
// }
|
||||||
// Discard any previous votes the deauthorized signer cast
|
// // Discard any previous votes the deauthorized signer cast
|
||||||
for i := 0; i < len(snap.Votes); i++ {
|
// for i := 0; i < len(snap.Votes); i++ {
|
||||||
if snap.Votes[i].Signer == header.Coinbase {
|
// if snap.Votes[i].Signer == header.Coinbase {
|
||||||
// Uncast the vote from the cached tally
|
// // Uncast the vote from the cached tally
|
||||||
snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize)
|
// snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize)
|
||||||
|
|
||||||
// Uncast the vote from the chronological list
|
// // Uncast the vote from the chronological list
|
||||||
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
|
// snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
|
||||||
|
|
||||||
i--
|
// i--
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// Discard any previous votes around the just changed account
|
// // Discard any previous votes around the just changed account
|
||||||
for i := 0; i < len(snap.Votes); i++ {
|
// for i := 0; i < len(snap.Votes); i++ {
|
||||||
if snap.Votes[i].Address == header.Coinbase {
|
// if snap.Votes[i].Address == header.Coinbase {
|
||||||
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
|
// snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
|
||||||
i--
|
// i--
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
delete(snap.Tally, header.Coinbase)
|
// delete(snap.Tally, header.Coinbase)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
snap.Number += uint64(len(headers))
|
snap.Number += uint64(len(headers))
|
||||||
snap.Hash = headers[len(headers)-1].Hash()
|
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.
|
// signers retrieves the list of authorized signers in ascending order.
|
||||||
func (s *Snapshot) signers() []common.Address {
|
func (s *Snapshot) signers() []common.Address {
|
||||||
sigs := make([]common.Address, 0, len(s.Signers))
|
sigs := make([]common.Address, 0, len(s.ValidatorSet.Validators))
|
||||||
for sig := range s.Signers {
|
for _, sig := range s.ValidatorSet.Validators {
|
||||||
sigs = append(sigs, sig)
|
sigs = append(sigs, sig.Address)
|
||||||
}
|
}
|
||||||
sort.Sort(signersAscending(sigs))
|
|
||||||
return sigs
|
return sigs
|
||||||
}
|
}
|
||||||
|
|
||||||
// inturn returns if a signer at a given block height is in-turn or not.
|
// 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 {
|
func (s *Snapshot) inturn(number uint64, signer common.Address, epoch uint64) uint64 {
|
||||||
signers, offset := s.signers(), 0
|
// if signer is empty
|
||||||
for offset < len(signers) && signers[offset] != signer {
|
if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 {
|
||||||
offset++
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 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
|
// the head block (ethash cache or clique voting snapshot). Might as well do
|
||||||
// it in advance.
|
// 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 {
|
if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 {
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,10 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
TrieTimeLimit: config.TrieTimeout,
|
TrieTimeLimit: config.TrieTimeout,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue