Merge pull request #207 from nguyenbatam/verify_info_at_checkpoint_block

verify info at checkpoint block
This commit is contained in:
Tuna 2018-10-23 11:36:59 +07:00 committed by GitHub
commit e4cbeaeb8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 46 deletions

View file

@ -71,7 +71,7 @@ func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
if err != nil {
return nil, err
}
return snap.signers(), nil
return snap.GetSigners(), nil
}
// 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 {
return nil, err
}
return snap.signers(), nil
return snap.GetSigners(), nil
}
// 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
// block reward is zero, so an empty block just bloats the chain... fast.
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
@ -215,7 +217,8 @@ type Posv struct {
HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error
HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error)
HookPrepare func(header *types.Header, signers []common.Address) error
HookValidator func(header *types.Header, signers []common.Address) error
HookVerifyMNs func(header *types.Header, signers []common.Address) error
}
// 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
}
}
signers := snap.signers()
signers := snap.GetSigners()
signers = common.RemoveItemFromArray(signers, penPenalties)
for i := 1; i <= common.LimitPenaltyEpoch; i++ {
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) {
return errInvalidCheckpointSigners
}
if c.HookVerifyMNs != nil {
err := c.HookVerifyMNs(header, signers)
if err != nil {
return err
}
}
}
// All basic checks passed, verify the seal and return
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())
}
nstring := []string{}
for _, n := range snap.signers() {
for _, n := range snap.GetSigners() {
nstring = append(nstring, n.String())
}
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 = header.Extra[:extraVanity]
signers := snap.signers()
signers := snap.GetSigners()
if number%c.config.Epoch == 0 {
if c.HookPenalty != nil {
penSigners, err := c.HookPenalty(chain, number)
@ -696,8 +705,11 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error
if header.Time.Int64() < time.Now().Unix() {
header.Time = big.NewInt(time.Now().Unix())
}
if c.HookPrepare != nil {
c.HookPrepare(header, signers)
if c.HookValidator != nil {
c.HookValidator(header, signers)
if err != nil {
return err
}
}
return nil
}
@ -710,7 +722,7 @@ func (c *Posv) UpdateMasternodes(chain consensus.ChainReader, header *types.Head
if err != nil {
return err
}
currentSigners := snap.signers()
currentSigners := snap.GetSigners()
proposedSigners := make(map[common.Address]struct{})
// count all addresses in ms to be masternode
for _, m := range ms {
@ -724,7 +736,7 @@ func (c *Posv) UpdateMasternodes(chain consensus.ChainReader, header *types.Head
}
}
nm := []string{}
newSigners := snap.signers()
newSigners := snap.GetSigners()
for _, n := range newSigners {
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.
func (s *Snapshot) signers() []common.Address {
func (s *Snapshot) GetSigners() []common.Address {
signers := make([]common.Address, 0, len(s.Signers))
for signer := range s.Signers {
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.
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 {
offset++
}

View file

@ -34,4 +34,6 @@ var (
ErrNonceTooHigh = errors.New("nonce too high")
ErrNotPoSV = errors.New("Posv not found in config")
ErrNotFoundM1 = errors.New("list M1 not found ")
)

View file

@ -25,6 +25,7 @@ import (
"sync"
"sync/atomic"
"bytes"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@ -189,7 +190,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if eth.chainConfig.Posv != nil {
c := eth.engine.(*posv.Posv)
// Inject hook for send tx sign to smartcontract after insert block into chain.
// Hook sends tx sign to smartcontract after inserting block to chain.
importedHook := func(block *types.Block) {
snap, err := c.GetSnapshot(eth.blockchain, block.Header())
if err != nil {
@ -209,42 +210,20 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
}
eth.protocolManager.fetcher.SetImportedHook(importedHook)
// Hook will process when preparing block.
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)
}
// Hook prepares validators M2 for the current epoch
c.HookValidator = func(header *types.Header, signers []common.Address) error {
number := header.Number.Int64()
// Check m2 exists on chaindb.
// Get secrets and opening at epoc block checkpoint.
if number > 0 && number%common.EpocBlockRandomize == 0 {
var candidates []int64
lenSigners := int64(len(signers))
if lenSigners > 0 {
for _, addr := range signers {
random, err := contracts.GetRandomizeFromContract(client, addr)
validators, err := GetValidators(eth.blockchain, signers)
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())
}
return err
}
header.Validators = validators
}
return nil
}
// Hook penalty.
// Hook scans for bad masternodes and decide to penalty them
c.HookPenalty = func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) {
client, err := eth.blockchain.GetClient()
if err != nil {
@ -285,7 +264,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return []common.Address{}, nil
}
// Hook reward for posv validator.
// Hook calculates reward for masternodes
c.HookReward = func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error {
client, err := eth.blockchain.GetClient()
if err != nil {
@ -330,6 +309,21 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return nil
}
// Hook verifies masternodes set
c.HookVerifyMNs = 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
@ -606,3 +600,37 @@ func (s *Ethereum) Stop() error {
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
}