From 07b4be1284b9a4b07b99b0bfe37964cd895a97c4 Mon Sep 17 00:00:00 2001 From: MestryOmkar Date: Fri, 9 Nov 2018 16:11:13 +0530 Subject: [PATCH] Add new block header validator for store m2 data. --- core/types/block.go | 6 +++ eth/backend.go | 114 +++++++++++++---------------------------- eth/fetcher/fetcher.go | 51 ++++++++++++++---- internal/ethapi/api.go | 1 + 4 files changed, 82 insertions(+), 90 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index 2a16a15729..a99fc975c0 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -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) } diff --git a/eth/backend.go b/eth/backend.go index f395ecbe5d..35f5cd8c9d 100644 --- a/eth/backend.go +++ b/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 diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index d7f0aa553d..08381bafe7 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -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 } \ No newline at end of file diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a6429d5b6c..31b78e3dd5 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -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), }