mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-21 06:04:33 +00:00
Add new block header validator for store m2 data.
This commit is contained in:
parent
f0761106f4
commit
07b4be1284
4 changed files with 82 additions and 90 deletions
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
114
eth/backend.go
114
eth/backend.go
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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),
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue