From 53605132932964c91fb7aa48fbae83a19d5b8779 Mon Sep 17 00:00:00 2001 From: DinhLN Date: Wed, 24 Oct 2018 15:06:49 +0700 Subject: [PATCH] Add new block header validator for store m2 data. --- consensus/posv/posv.go | 32 ++++++++++++++++++++++++++++++-- core/types/block.go | 6 ++++++ eth/backend.go | 35 ++++++++++++++++++++++++++++++++++- eth/fetcher/fetcher.go | 15 +++++++++++++++ internal/ethapi/api.go | 1 + 5 files changed, 86 insertions(+), 3 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 29c3da567d..2fef728f15 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -179,6 +179,10 @@ func sigHash(header *types.Header) (hash common.Hash) { return hash } +func SigHash(header *types.Header) (hash common.Hash) { + return sigHash(header) +} + // ecrecover extracts the Ethereum account address from a signed header. func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) { // If the signature's already cached, return that @@ -645,7 +649,7 @@ func (c *Posv) verifySeal(chain consensus.ChainReader, header *types.Header, par } // verify validator - assignedValidator, err := c.getValidator(creator, snap, chain, header) + assignedValidator, err := c.GetValidator(creator, snap, chain, header) if err != nil { return err } @@ -656,7 +660,7 @@ func (c *Posv) verifySeal(chain consensus.ChainReader, header *types.Header, par return nil } -func (c *Posv) getValidator(creator common.Address, snap *Snapshot, chain consensus.ChainReader, header *types.Header) (common.Address, error) { +func (c *Posv) GetValidator(creator common.Address, snap *Snapshot, chain consensus.ChainReader, header *types.Header) (common.Address, error) { epoch := c.config.Epoch no := header.Number.Uint64() cpNo := no @@ -946,6 +950,30 @@ func (c *Posv) RecoverSigner(header *types.Header) (common.Address, error) { return ecrecover(header, c.signatures) } +func (c *Posv) RecoverValidator(header *types.Header) (common.Address, error) { + // If the signature's already cached, return that + hash := header.Hash() + if address, known := c.signatures.Get(hash); known { + return address.(common.Address), nil + } + // Retrieve the signature from the header extra-data + if len(header.Validator) < extraSeal { + return common.Address{}, errMissingSignature + } + signature := header.Validator[len(header.Validator)-extraSeal:] + + // Recover the public key and the Ethereum address + pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature) + if err != nil { + return common.Address{}, err + } + var signer common.Address + copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) + + c.signatures.Add(hash, signer) + return signer, nil +} + // Get master nodes over extra data of previous checkpoint block. func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address { if preCheckpointHeader == nil { 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 ceb638718a..e95bf36148 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -187,7 +187,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { if eth.chainConfig.Posv != nil { c := eth.engine.(*posv.Posv) - 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) @@ -195,7 +194,41 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return nil } + 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}, posv.SigHash(header).Bytes()) + header.Validator = sighash + block = types.NewBlockWithHeader(header) + //c := eth.engine.(*posv.Posv) + //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 { diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index e75ecdbfa5..9584cfa856 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -144,6 +144,7 @@ type Fetcher struct { 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. @@ -653,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) @@ -757,3 +767,8 @@ func (f *Fetcher) SetDoubleValidateHook(doubleValidateHook func(*types.Block) er 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 +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7ecdd76787..f5e0bab9e9 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), }