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"` MixDigest common.Hash `json:"mixHash" gencodec:"required"`
Nonce BlockNonce `json:"nonce" gencodec:"required"` Nonce BlockNonce `json:"nonce" gencodec:"required"`
Validators []byte `json:"validators" gencodec:"required"` Validators []byte `json:"validators" gencodec:"required"`
Validator []byte `json:"validator" gencodec:"required"`
Penalties []byte `json:"penalties" gencodec:"required"` Penalties []byte `json:"penalties" gencodec:"required"`
} }
@ -256,6 +257,10 @@ func CopyHeader(h *Header) *Header {
cpy.Extra = make([]byte, len(h.Extra)) cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, 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 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) UncleHash() common.Hash { return b.header.UncleHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } 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) 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) } func (b *Block) Header() *Header { return CopyHeader(b.header) }

View file

@ -1,3 +1,4 @@
// Copyright 2014 The go-ethereum Authors // Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
@ -24,7 +25,6 @@ import (
"runtime" "runtime"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time"
"bytes" "bytes"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
@ -188,61 +188,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if eth.chainConfig.XDPoS != nil { if eth.chainConfig.XDPoS != nil {
c := eth.engine.(*XDPoS.XDPoS) 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 { signHook := func(block *types.Block) error {
if err := contracts.CreateTransactionSign(chainConfig, eth.txPool, eth.accountManager, block, chainDb); err != nil { 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) 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 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.SetSignHook(signHook)
eth.protocolManager.fetcher.SetAppendM2HeaderHook(appendM2HeaderHook)
// Hook prepares validators M2 for the current epoch // Hook prepares validators M2 for the current epoch
c.HookValidator = func(header *types.Header, signers []common.Address) error { 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 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 { func makeExtraData(extra []byte) []byte {
if len(extra) == 0 { if len(extra) == 0 {
// create default extradata // create default extradata

View file

@ -138,11 +138,13 @@ type Fetcher struct {
dropPeer peerDropFn // Drops a peer for misbehaving dropPeer peerDropFn // Drops a peer for misbehaving
// Testing hooks // Testing hooks
announceChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a hash from the announce list 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 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 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) 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) 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. // 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 // Quickly validate the header and propagate the block if it passes
switch err := f.verifyHeader(block.Header()); err { switch err := f.verifyHeader(block.Header()); err {
case nil: 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 // All ok, quickly propagate to our peers
propBroadcastOutTimer.UpdateSince(block.ReceivedAt) propBroadcastOutTimer.UpdateSince(block.ReceivedAt)
go f.broadcastBlock(block, true) go f.broadcastBlock(block, true)
@ -665,9 +676,9 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
f.dropPeer(peer) f.dropPeer(peer)
return return
} }
// Invoke the imported hook to run double validation layer // Invoke the dv hook to run double validation layer
if f.importedHook != nil { if f.doubleValidateHook != nil {
if err := f.importedHook(block); err != nil { if err := f.doubleValidateHook(block); err != nil {
log.Error("Double validation failed", "err", err, "Discard this block!") log.Error("Double validation failed", "err", err, "Discard this block!")
return 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) log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
return 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 // If import succeeded, broadcast the block
propAnnounceOutTimer.UpdateSince(block.ReceivedAt) propAnnounceOutTimer.UpdateSince(block.ReceivedAt)
go f.broadcastBlock(block, false) go f.broadcastBlock(block, false)
@ -739,7 +758,17 @@ func (f *Fetcher) forgetBlock(hash common.Hash) {
} }
} }
// Bind import hook when block imported into chain. // Bind double validate hook before block imported into chain.
func (f *Fetcher) SetImportedHook(importedHook func(*types.Block) error) { func (f *Fetcher) SetDoubleValidateHook(doubleValidateHook func(*types.Block) error) {
f.importedHook = importedHook 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, "transactionsRoot": head.TxHash,
"receiptsRoot": head.ReceiptHash, "receiptsRoot": head.ReceiptHash,
"validators": hexutil.Bytes(head.Validators), "validators": hexutil.Bytes(head.Validators),
"validator": hexutil.Bytes(head.Validator),
"penalties": hexutil.Bytes(head.Penalties), "penalties": hexutil.Bytes(head.Penalties),
} }