diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index 3112571759a2743eef2e619046b7af0410af6076..6827c69a1ec8cc09dc89c736ee3cf247c68a9720 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -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 +} diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go index a9148558c075315e6cab74364e863e186f725a06..f4201e4def77faafc2effc67262444e4b032c7cf 100644 --- a/consensus/bor/snapshot.go +++ b/consensus/bor/snapshot.go @@ -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 - - 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 + 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 + 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 - } - } - 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) + // + // Check validator + // - // Uncast the vote from the chronological list - snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) - break // only one vote allowed + 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 } } - // 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, - }) + + // add recents + snap.Recents[number] = signer + 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, + // }) + // } // 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) - - // 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:]...) - - 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) - } + // 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) + + // // 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) + // } } 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 + } + + 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 ((number / producerPeriod) % uint64(len(signers))) == uint64(offset) + + 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 } diff --git a/core/blockchain.go b/core/blockchain.go index 2355f0ea315fd97d07dd1fa3da2521afa452c026..47fb5c705184b390aa2ba1fb0671bfe7611a8158 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -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 ( diff --git a/eth/backend.go b/eth/backend.go index 698f519bc77602aac0639d326375a46e1e3e24a3..e4d01c169bc7d79f150f06db8b200e924c2d7c6f 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -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 }