verify validators info at checkpoint block

This commit is contained in:
Nguyen Ba Tam 2018-10-08 14:18:34 +07:00 committed by Tuna
parent f7c2902315
commit a7c149d76b
5 changed files with 78 additions and 39 deletions

View file

@ -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.

View file

@ -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
@ -213,9 +215,10 @@ type Posv struct {
signFn clique.SignerFn // Signer function to authorize hashes with signFn clique.SignerFn // Signer function to authorize hashes with
lock sync.RWMutex // Protects the signer fields lock sync.RWMutex // Protects the signer fields
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())
} }

View file

@ -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++
} }

View file

@ -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 ")
) )

View file

@ -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 err != nil {
return err
if lenSigners > 0 {
for _, addr := range signers {
random, err := contracts.GetRandomizeFromContract(client, addr)
if err != nil {
log.Error("Fail to get random m2 from contract.", "error", 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
}