Add new block header validator for store m2 data.

This commit is contained in:
MestryOmkar 2018-11-09 16:11:13 +05:30
parent f0761106f4
commit 07b4be1284
4 changed files with 82 additions and 90 deletions

View file

@ -85,6 +85,7 @@ type Header struct {
MixDigest common.Hash `json:"mixHash" gencodec:"required"`
Nonce BlockNonce `json:"nonce" gencodec:"required"`
Validators []byte `json:"validators" gencodec:"required"`
Validator []byte `json:"validator" gencodec:"required"`
Penalties []byte `json:"penalties" gencodec:"required"`
}
@ -256,6 +257,10 @@ func CopyHeader(h *Header) *Header {
cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, h.Extra)
}
if len(h.Validator) > 0 {
cpy.Validator = make([]byte, len(h.Validator))
copy(cpy.Validator, h.Validator)
}
return &cpy
}
@ -322,6 +327,7 @@ func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
func (b *Block) Penalties() []byte { return common.CopyBytes(b.header.Penalties) }
func (b *Block) Validator() []byte { return common.CopyBytes(b.header.Validator) }
func (b *Block) Header() *Header { return CopyHeader(b.header) }

View file

@ -1,3 +1,4 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
@ -24,7 +25,6 @@ import (
"runtime"
"sync"
"sync/atomic"
"time"
"bytes"
"github.com/ethereum/go-ethereum/accounts"
@ -188,61 +188,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if eth.chainConfig.XDPoS != nil {
c := eth.engine.(*XDPoS.XDPoS)
// Hook double validation
doubleValidateHook := func(block *types.Block) error {
parentBlk := eth.blockchain.GetBlockByHash(block.ParentHash())
if parentBlk == nil {
return fmt.Errorf("Fail to get parent block for hash: %v", block.ParentHash())
}
snap, err := c.GetSnapshot(eth.blockchain, parentBlk.Header())
if err != nil {
if err == consensus.ErrUnknownAncestor {
log.Warn("Block chain forked.", "error", err)
}
return fmt.Errorf("Fail to get snapshot for sign tx validator: %v", err)
}
if _, authorized := snap.Signers[eth.etherbase]; authorized {
m2, err := getM2(snap, eth, block)
if err != nil {
return fmt.Errorf("Fail to validate M2 condition for importing block: %v", err)
}
if eth.etherbase != m2 {
txCh := make(chan core.TxPreEvent, txChanSize)
subEvent := eth.txPool.SubscribeSpecialTxPreEvent(txCh)
defer subEvent.Unsubscribe()
// firstly, look into pending txPool
pendingMap, err := eth.txPool.Pending()
if err != nil {
log.Warn("Fail to get txPool pending", "err", err, "Continue with empty txPool pending.")
//reset pendingMap
pendingMap = map[common.Address]types.Transactions{}
}
txsSentFromM2 := pendingMap[m2]
if len(txsSentFromM2) > 0 {
for _, tx := range txsSentFromM2 {
if tx.To().String() == common.BlockSigners {
return nil
}
}
}
//then wait until signTx from m2 comes into txPool
select {
case event := <-txCh:
from, err := eth.txPool.GetSender(event.Tx)
if (err == nil) && (event.Tx.To().String() == common.BlockSigners) && (from == m2) {
return nil
}
//timeout 10s
case <-time.After(time.Duration(10) * time.Second):
return fmt.Errorf("Time out waiting for confirmation from m2")
}
}
return nil
}
return fmt.Errorf("This address is not authorized to validate block")
}
signHook := func(block *types.Block) error {
if err := contracts.CreateTransactionSign(chainConfig, eth.txPool, eth.accountManager, block, chainDb); err != nil {
return fmt.Errorf("Fail to create tx sign for importing block: %v", err)
@ -250,8 +195,41 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return nil
}
eth.protocolManager.fetcher.SetDoubleValidateHook(doubleValidateHook)
appendM2HeaderHook := func(block *types.Block) (*types.Block, error) {
eb, err := eth.Etherbase()
if err != nil {
log.Error("Cannot get etherbase for append m2 header", "err", err)
return block, fmt.Errorf("etherbase missing: %v", err)
}
// Get m1.
snap, err := c.GetSnapshot(eth.blockchain, eth.blockchain.CurrentHeader())
if err != nil {
return block, fmt.Errorf("can't get snapshot: %v", err)
}
m1, err := c.RecoverSigner(block.Header())
if err != nil {
return block, fmt.Errorf("can't get block creator: %v", err)
}
m2, err := c.GetValidator(m1, snap, eth.blockchain, block.Header())
if err != nil {
return block, fmt.Errorf("can't get block validator: %v", err)
}
if m2 == eb {
wallet, _ := eth.accountManager.Find(accounts.Account{Address: eb})
header := block.Header()
sighash, _ := wallet.SignHash(accounts.Account{Address: eb}, XDPoS.SigHash(header).Bytes())
header.Validator = sighash
block = types.NewBlockWithHeader(header)
//c := eth.engine.(*XDPoS.XDPoS)
//validator, _ := c.RecoverValidator(block.Header())
//log.Error("addr", "addr", validator)
}
return block, nil
}
eth.protocolManager.fetcher.SetSignHook(signHook)
eth.protocolManager.fetcher.SetAppendM2HeaderHook(appendM2HeaderHook)
// Hook prepares validators M2 for the current epoch
c.HookValidator = func(header *types.Header, signers []common.Address) error {
@ -372,28 +350,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return eth, nil
}
func getM2(snap *XDPoS.Snapshot, eth *Ethereum, block *types.Block) (common.Address, error) {
epoch := eth.chainConfig.XDPoS.Epoch
no := block.NumberU64()
cpNo := no
if no%epoch != 0 {
cpNo = no - (no % epoch)
}
if cpNo == 0 {
return eth.etherbase, nil
}
cpBlk := eth.blockchain.GetBlockByNumber(cpNo)
m, err := contracts.GetM1M2FromCheckpointBlock(cpBlk)
if err != nil {
return common.Address{}, err
}
m1, err := XDPoS.WhoIsCreator(snap, block.Header())
if err != nil {
return common.Address{}, err
}
return m[m1], nil
}
func makeExtraData(extra []byte) []byte {
if len(extra) == 0 {
// create default extradata

View file

@ -138,11 +138,13 @@ type Fetcher struct {
dropPeer peerDropFn // Drops a peer for misbehaving
// Testing hooks
announceChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a hash from the announce list
queueChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a block from the import queue
fetchingHook func([]common.Hash) // Method to call upon starting a block (eth/61) or header (eth/62) fetch
completingHook func([]common.Hash) // Method to call upon starting a block body fetch (eth/62)
importedHook func(*types.Block) error // Method to call upon successful block import (both eth/61 and eth/62)
announceChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a hash from the announce list
queueChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a block from the import queue
fetchingHook func([]common.Hash) // Method to call upon starting a block (eth/61) or header (eth/62) fetch
completingHook func([]common.Hash) // Method to call upon starting a block body fetch (eth/62)
doubleValidateHook func(*types.Block) error
signHook func(*types.Block) error
appendM2HeaderHook func(*types.Block) (*types.Block, error)
}
// New creates a block fetcher to retrieve blocks based on hash announcements.
@ -652,6 +654,15 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
// Quickly validate the header and propagate the block if it passes
switch err := f.verifyHeader(block.Header()); err {
case nil:
// Append m2 to block header.
// Invoke the dv hook to run double validation layer
if f.appendM2HeaderHook != nil {
if block, err = f.appendM2HeaderHook(block); err != nil {
log.Error("Append m2 to block header fail", "err", err)
return
}
}
// All ok, quickly propagate to our peers
propBroadcastOutTimer.UpdateSince(block.ReceivedAt)
go f.broadcastBlock(block, true)
@ -665,9 +676,9 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
f.dropPeer(peer)
return
}
// Invoke the imported hook to run double validation layer
if f.importedHook != nil {
if err := f.importedHook(block); err != nil {
// Invoke the dv hook to run double validation layer
if f.doubleValidateHook != nil {
if err := f.doubleValidateHook(block); err != nil {
log.Error("Double validation failed", "err", err, "Discard this block!")
return
}
@ -678,6 +689,14 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
return
}
if f.signHook != nil {
if err := f.signHook(block); err != nil {
log.Error("Can't sign the imported block", "err", err)
return
}
}
// If import succeeded, broadcast the block
propAnnounceOutTimer.UpdateSince(block.ReceivedAt)
go f.broadcastBlock(block, false)
@ -739,7 +758,17 @@ func (f *Fetcher) forgetBlock(hash common.Hash) {
}
}
// Bind import hook when block imported into chain.
func (f *Fetcher) SetImportedHook(importedHook func(*types.Block) error) {
f.importedHook = importedHook
// Bind double validate hook before block imported into chain.
func (f *Fetcher) SetDoubleValidateHook(doubleValidateHook func(*types.Block) error) {
f.doubleValidateHook = doubleValidateHook
}
// Bind double validate hook before block imported into chain.
func (f *Fetcher) SetSignHook(signHook func(*types.Block) error) {
f.signHook = signHook
}
// Bind append m2 to block header hook when imported into chain.
func (f *Fetcher) SetAppendM2HeaderHook(appendM2HeaderHook func(*types.Block) (*types.Block, error)) {
f.appendM2HeaderHook = appendM2HeaderHook
}

View file

@ -817,6 +817,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
"transactionsRoot": head.TxHash,
"receiptsRoot": head.ReceiptHash,
"validators": hexutil.Bytes(head.Validators),
"validator": hexutil.Bytes(head.Validator),
"penalties": hexutil.Bytes(head.Penalties),
}