mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
verify validators info at checkpoint block
This commit is contained in:
parent
f7c2902315
commit
a7c149d76b
5 changed files with 78 additions and 39 deletions
|
|
@ -71,7 +71,7 @@ func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return snap.signers(), nil
|
return snap.GetSigners(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSignersAtHash retrieves the state snapshot at a given block.
|
// GetSignersAtHash retrieves the state snapshot at a given block.
|
||||||
|
|
@ -84,7 +84,7 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return snap.signers(), nil
|
return snap.GetSigners(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proposals returns the current proposals the node tries to uphold and vote on.
|
// Proposals returns the current proposals the node tries to uphold and vote on.
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,8 @@ var (
|
||||||
// on an instant chain (0 second period). It's important to refuse these as the
|
// on an instant chain (0 second period). It's important to refuse these as the
|
||||||
// block reward is zero, so an empty block just bloats the chain... fast.
|
// block reward is zero, so an empty block just bloats the chain... fast.
|
||||||
errWaitTransactions = errors.New("waiting for transactions")
|
errWaitTransactions = errors.New("waiting for transactions")
|
||||||
|
|
||||||
|
ErrInvalidCheckpointValidators = errors.New("invalid validators list on checkpoint block")
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignerFn is a signer callback function to request a hash to be signed by a
|
// SignerFn is a signer callback function to request a hash to be signed by a
|
||||||
|
|
@ -216,6 +218,7 @@ type Posv struct {
|
||||||
HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error
|
HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error
|
||||||
HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error)
|
HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error)
|
||||||
HookPrepare func(header *types.Header, signers []common.Address) error
|
HookPrepare func(header *types.Header, signers []common.Address) error
|
||||||
|
VerifyValidators func(header *types.Header, signers []common.Address) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a Posv proof-of-stake-voting consensus engine with the initial
|
// New creates a Posv proof-of-stake-voting consensus engine with the initial
|
||||||
|
|
@ -379,7 +382,7 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.
|
||||||
return errInvalidCheckpointPenalties
|
return errInvalidCheckpointPenalties
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signers := snap.signers()
|
signers := snap.GetSigners()
|
||||||
signers = common.RemoveItemFromArray(signers, penPenalties)
|
signers = common.RemoveItemFromArray(signers, penPenalties)
|
||||||
for i := 1; i <= common.LimitPenaltyEpoch; i++ {
|
for i := 1; i <= common.LimitPenaltyEpoch; i++ {
|
||||||
if number > uint64(i)*c.config.Epoch {
|
if number > uint64(i)*c.config.Epoch {
|
||||||
|
|
@ -391,6 +394,12 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.
|
||||||
if !bytes.Equal(header.Extra[extraVanity:extraSuffix], byteMasterNodes) {
|
if !bytes.Equal(header.Extra[extraVanity:extraSuffix], byteMasterNodes) {
|
||||||
return errInvalidCheckpointSigners
|
return errInvalidCheckpointSigners
|
||||||
}
|
}
|
||||||
|
if c.VerifyValidators != nil {
|
||||||
|
err := c.VerifyValidators(header, signers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 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)
|
||||||
|
|
@ -581,7 +590,7 @@ func (c *Posv) verifySeal(chain consensus.ChainReader, header *types.Header, par
|
||||||
mstring = append(mstring, m.String())
|
mstring = append(mstring, m.String())
|
||||||
}
|
}
|
||||||
nstring := []string{}
|
nstring := []string{}
|
||||||
for _, n := range snap.signers() {
|
for _, n := range snap.GetSigners() {
|
||||||
nstring = append(nstring, n.String())
|
nstring = append(nstring, n.String())
|
||||||
}
|
}
|
||||||
if _, ok := snap.Signers[signer]; !ok {
|
if _, ok := snap.Signers[signer]; !ok {
|
||||||
|
|
@ -656,7 +665,7 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error
|
||||||
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
|
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
|
||||||
}
|
}
|
||||||
header.Extra = header.Extra[:extraVanity]
|
header.Extra = header.Extra[:extraVanity]
|
||||||
signers := snap.signers()
|
signers := snap.GetSigners()
|
||||||
if number%c.config.Epoch == 0 {
|
if number%c.config.Epoch == 0 {
|
||||||
if c.HookPenalty != nil {
|
if c.HookPenalty != nil {
|
||||||
penSigners, err := c.HookPenalty(chain, number)
|
penSigners, err := c.HookPenalty(chain, number)
|
||||||
|
|
@ -698,6 +707,9 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error
|
||||||
}
|
}
|
||||||
if c.HookPrepare != nil {
|
if c.HookPrepare != nil {
|
||||||
c.HookPrepare(header, signers)
|
c.HookPrepare(header, signers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -710,7 +722,7 @@ func (c *Posv) UpdateMasternodes(chain consensus.ChainReader, header *types.Head
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
currentSigners := snap.signers()
|
currentSigners := snap.GetSigners()
|
||||||
proposedSigners := make(map[common.Address]struct{})
|
proposedSigners := make(map[common.Address]struct{})
|
||||||
// count all addresses in ms to be masternode
|
// count all addresses in ms to be masternode
|
||||||
for _, m := range ms {
|
for _, m := range ms {
|
||||||
|
|
@ -724,7 +736,7 @@ func (c *Posv) UpdateMasternodes(chain consensus.ChainReader, header *types.Head
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nm := []string{}
|
nm := []string{}
|
||||||
newSigners := snap.signers()
|
newSigners := snap.GetSigners()
|
||||||
for _, n := range newSigners {
|
for _, n := range newSigners {
|
||||||
nm = append(nm, n.String())
|
nm = append(nm, n.String())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ 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) GetSigners() []common.Address {
|
||||||
signers := make([]common.Address, 0, len(s.Signers))
|
signers := make([]common.Address, 0, len(s.Signers))
|
||||||
for signer := range s.Signers {
|
for signer := range s.Signers {
|
||||||
signers = append(signers, signer)
|
signers = append(signers, signer)
|
||||||
|
|
@ -303,7 +303,7 @@ func (s *Snapshot) signers() []common.Address {
|
||||||
|
|
||||||
// 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) bool {
|
func (s *Snapshot) inturn(number uint64, signer common.Address) bool {
|
||||||
signers, offset := s.signers(), 0
|
signers, offset := s.GetSigners(), 0
|
||||||
for offset < len(signers) && signers[offset] != signer {
|
for offset < len(signers) && signers[offset] != signer {
|
||||||
offset++
|
offset++
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,4 +34,6 @@ var (
|
||||||
ErrNonceTooHigh = errors.New("nonce too high")
|
ErrNonceTooHigh = errors.New("nonce too high")
|
||||||
|
|
||||||
ErrNotPoSV = errors.New("Posv not found in config")
|
ErrNotPoSV = errors.New("Posv not found in config")
|
||||||
|
|
||||||
|
ErrNotFoundM1 = errors.New("list M1 not found ")
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"bytes"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
|
@ -211,36 +212,13 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
|
|
||||||
// Hook will process when preparing block.
|
// Hook will process when preparing block.
|
||||||
c.HookPrepare = func(header *types.Header, signers []common.Address) error {
|
c.HookPrepare = func(header *types.Header, signers []common.Address) error {
|
||||||
client, err := eth.blockchain.GetClient()
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Fail to connect IPC client for penalty.", "error", err)
|
|
||||||
}
|
|
||||||
number := header.Number.Int64()
|
number := header.Number.Int64()
|
||||||
// Check m2 exists on chaindb.
|
|
||||||
// Get secrets and opening at epoc block checkpoint.
|
|
||||||
if number > 0 && number%common.EpocBlockRandomize == 0 {
|
if number > 0 && number%common.EpocBlockRandomize == 0 {
|
||||||
var candidates []int64
|
validators, err := GetValidators(eth.blockchain, signers)
|
||||||
lenSigners := int64(len(signers))
|
|
||||||
|
|
||||||
if lenSigners > 0 {
|
|
||||||
for _, addr := range signers {
|
|
||||||
random, err := contracts.GetRandomizeFromContract(client, addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Fail to get random m2 from contract.", "error", err)
|
return err
|
||||||
}
|
|
||||||
candidates = append(candidates, random)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get randomize m2 list.
|
|
||||||
m2, err := contracts.GenM2FromRandomize(candidates, lenSigners)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Can not get m2 from randomize SC", "error", err)
|
|
||||||
}
|
|
||||||
if len(m2) > 0 {
|
|
||||||
header.Validators = contracts.BuildValidatorFromM2(m2)
|
|
||||||
log.Debug("New set Validators", "m2", m2, "number", header.Number.Uint64())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
header.Validators = validators
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -330,6 +308,19 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
c.VerifyValidators = func(header *types.Header, signers []common.Address) error {
|
||||||
|
number := header.Number.Int64()
|
||||||
|
if number > 0 && number%common.EpocBlockRandomize == 0 {
|
||||||
|
validators, err := GetValidators(eth.blockchain, signers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(header.Validators, validators) {
|
||||||
|
return posv.ErrInvalidCheckpointValidators
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return eth, nil
|
return eth, nil
|
||||||
|
|
@ -606,3 +597,37 @@ func (s *Ethereum) Stop() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetValidators(bc *core.BlockChain, masternodes []common.Address) ([]byte, error) {
|
||||||
|
if bc.Config().Posv == nil {
|
||||||
|
return nil, core.ErrNotPoSV
|
||||||
|
}
|
||||||
|
client, err := bc.GetClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Check m2 exists on chaindb.
|
||||||
|
// Get secrets and opening at epoc block checkpoint.
|
||||||
|
|
||||||
|
var candidates []int64
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lenSigners := int64(len(masternodes))
|
||||||
|
if lenSigners > 0 {
|
||||||
|
for _, addr := range masternodes {
|
||||||
|
random, err := contracts.GetRandomizeFromContract(client, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
candidates = append(candidates, random)
|
||||||
|
}
|
||||||
|
// Get randomize m2 list.
|
||||||
|
m2, err := contracts.GenM2FromRandomize(candidates, lenSigners)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return contracts.BuildValidatorFromM2(m2), nil
|
||||||
|
}
|
||||||
|
return nil, core.ErrNotFoundM1
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue