From 96554a3bc14030e5d0dfc9dc1ee6bcdd9a133fa8 Mon Sep 17 00:00:00 2001 From: Jimmy Hu Date: Thu, 30 Aug 2018 17:21:58 +0800 Subject: core: Add PreparePayloads to Application and Remove blockConverter interface. (#84) --- core/application.go | 41 ------------------------- core/consensus.go | 21 +++++-------- core/crypto.go | 10 +++---- core/crypto_test.go | 24 +++------------ core/interfaces.go | 58 ++++++++++++++++++++++++++++++++++++ core/nonblocking-application.go | 6 ++++ core/nonblocking-application_test.go | 4 +++ core/test/app.go | 5 ++++ core/test/blocks-generator.go | 2 +- core/test/utils.go | 3 +- core/types/block.go | 29 ++++-------------- 11 files changed, 97 insertions(+), 106 deletions(-) delete mode 100644 core/application.go create mode 100644 core/interfaces.go (limited to 'core') diff --git a/core/application.go b/core/application.go deleted file mode 100644 index 3834d68..0000000 --- a/core/application.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018 The dexon-consensus-core Authors -// This file is part of the dexon-consensus-core library. -// -// The dexon-consensus-core library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus-core library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus-core library. If not, see -// . - -package core - -import ( - "time" - - "github.com/dexon-foundation/dexon-consensus-core/common" - "github.com/dexon-foundation/dexon-consensus-core/core/types" -) - -// Application describes the application interface that interacts with DEXON -// consensus core. -type Application interface { - // StronglyAcked is called when a block is strongly acked. - StronglyAcked(blockHash common.Hash) - - // TotalOrderingDeliver is called when the total ordering algorithm deliver // a set of block. - TotalOrderingDeliver(blockHashes common.Hashes, early bool) - - // DeliverBlock is called when a block is add to the compaction chain. - DeliverBlock(blockHash common.Hash, timestamp time.Time) - - // NotaryAckDeliver is called when a notary ack is created. - NotaryAckDeliver(notaryAck *types.NotaryAck) -} diff --git a/core/consensus.go b/core/consensus.go index d163686..9c109e4 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -113,10 +113,9 @@ func (con *Consensus) ProcessVote(vote *types.Vote) (err error) { } // sanityCheck checks if the block is a valid block -func (con *Consensus) sanityCheck(blockConv types.BlockConverter) (err error) { - b := blockConv.Block() +func (con *Consensus) sanityCheck(b *types.Block) (err error) { // Check the hash of block. - hash, err := hashBlock(blockConv) + hash, err := hashBlock(b) if err != nil || hash != b.Hash { return ErrIncorrectHash } @@ -133,12 +132,11 @@ func (con *Consensus) sanityCheck(blockConv types.BlockConverter) (err error) { } // ProcessBlock is the entry point to submit one block to a Consensus instance. -func (con *Consensus) ProcessBlock(blockConv types.BlockConverter) (err error) { +func (con *Consensus) ProcessBlock(b *types.Block) (err error) { // TODO(jimmy-dexon): BlockConverter.Block() is called twice in this method. - if err := con.sanityCheck(blockConv); err != nil { + if err := con.sanityCheck(b); err != nil { return err } - b := blockConv.Block() var ( deliveredBlocks []*types.Block earlyDelivered bool @@ -218,9 +216,8 @@ func (con *Consensus) checkPrepareBlock( } // PrepareBlock would setup header fields of block based on its ProposerID. -func (con *Consensus) PrepareBlock(blockConv types.BlockConverter, +func (con *Consensus) PrepareBlock(b *types.Block, proposeTime time.Time) (err error) { - b := blockConv.Block() if err = con.checkPrepareBlock(b, proposeTime); err != nil { return } @@ -229,6 +226,7 @@ func (con *Consensus) PrepareBlock(blockConv types.BlockConverter, con.rbModule.prepareBlock(b) b.Timestamps[b.ProposerID] = proposeTime + b.Payloads = con.app.PreparePayloads(b.ShardID, b.ChainID, b.Height) b.Hash, err = hashBlock(b) if err != nil { return @@ -237,18 +235,16 @@ func (con *Consensus) PrepareBlock(blockConv types.BlockConverter, if err != nil { return } - blockConv.SetBlock(b) return } // PrepareGenesisBlock would setup header fields for genesis block. -func (con *Consensus) PrepareGenesisBlock(blockConv types.BlockConverter, +func (con *Consensus) PrepareGenesisBlock(b *types.Block, proposeTime time.Time) (err error) { - b := blockConv.Block() if err = con.checkPrepareBlock(b, proposeTime); err != nil { return } - if len(b.Payloads()) != 0 { + if len(b.Payloads) != 0 { err = ErrGenesisBlockNotEmpty return } @@ -268,7 +264,6 @@ func (con *Consensus) PrepareGenesisBlock(blockConv types.BlockConverter, if err != nil { return } - blockConv.SetBlock(b) return } diff --git a/core/crypto.go b/core/crypto.go index 57aae92..d6af360 100644 --- a/core/crypto.go +++ b/core/crypto.go @@ -49,9 +49,7 @@ func verifyNotarySignature(pubkey crypto.PublicKey, return pubkey.VerifySignature(hash, sig), nil } -func hashBlock(blockConv types.BlockConverter) (common.Hash, error) { - block := blockConv.Block() - +func hashBlock(block *types.Block) (common.Hash, error) { hashPosition := hashPosition(block.ShardID, block.ChainID, block.Height) // Handling Block.Acks. acks := make(common.Hashes, 0, len(block.Acks)) @@ -80,7 +78,7 @@ func hashBlock(blockConv types.BlockConverter) (common.Hash, error) { } } hashTimestamps := crypto.Keccak256Hash(binaryTimestamps...) - payloadHash := crypto.Keccak256Hash(blockConv.Payloads()...) + payloadHash := crypto.Keccak256Hash(block.Payloads...) hash := crypto.Keccak256Hash( block.ProposerID.Hash[:], @@ -93,8 +91,8 @@ func hashBlock(blockConv types.BlockConverter) (common.Hash, error) { } func verifyBlockSignature(pubkey crypto.PublicKey, - blockConv types.BlockConverter, sig crypto.Signature) (bool, error) { - hash, err := hashBlock(blockConv) + block *types.Block, sig crypto.Signature) (bool, error) { + hash, err := hashBlock(block) if err != nil { return false, err } diff --git a/core/crypto_test.go b/core/crypto_test.go index 62f7daa..f4013be 100644 --- a/core/crypto_test.go +++ b/core/crypto_test.go @@ -34,22 +34,6 @@ type CryptoTestSuite struct { var myVID = types.ValidatorID{Hash: common.NewRandomHash()} -type simpleBlock struct { - block *types.Block -} - -func (sb *simpleBlock) Block() *types.Block { - return sb.block -} - -func (sb *simpleBlock) Payloads() [][]byte { - return [][]byte{} -} - -func (sb *simpleBlock) SetBlock(block *types.Block) { - *sb.block = *block -} - func (s *CryptoTestSuite) prepareBlock(prevBlock *types.Block) *types.Block { acks := make(map[common.Hash]struct{}) timestamps := make(map[types.ValidatorID]time.Time) @@ -84,7 +68,7 @@ func (s *CryptoTestSuite) prepareBlock(prevBlock *types.Block) *types.Block { func (s *CryptoTestSuite) newBlock(prevBlock *types.Block) *types.Block { block := s.prepareBlock(prevBlock) var err error - block.Hash, err = hashBlock(&simpleBlock{block: block}) + block.Hash, err = hashBlock(block) s.Require().Nil(err) return block } @@ -177,17 +161,17 @@ func (s *CryptoTestSuite) TestBlockSignature() { parentBlock, exist := blockMap[block.ParentHash] s.Require().True(exist) s.True(parentBlock.Height == block.Height-1) - hash, err := hashBlock(&simpleBlock{block: parentBlock}) + hash, err := hashBlock(parentBlock) s.Require().Nil(err) s.Equal(hash, block.ParentHash) } - s.True(verifyBlockSignature(pub, &simpleBlock{block: block}, block.Signature)) + s.True(verifyBlockSignature(pub, block, block.Signature)) } // Modify Block.Acks and verify signature again. for _, block := range blocks { block.Acks[common.NewRandomHash()] = struct{}{} s.False(verifyBlockSignature( - pub, &simpleBlock{block: block}, block.Signature)) + pub, block, block.Signature)) } } diff --git a/core/interfaces.go b/core/interfaces.go new file mode 100644 index 0000000..364f2da --- /dev/null +++ b/core/interfaces.go @@ -0,0 +1,58 @@ +// Copyright 2018 The dexon-consensus-core Authors +// This file is part of the dexon-consensus-core library. +// +// The dexon-consensus-core library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus-core library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus-core library. If not, see +// . + +package core + +import ( + "time" + + "github.com/dexon-foundation/dexon-consensus-core/common" + "github.com/dexon-foundation/dexon-consensus-core/core/types" +) + +// Application describes the application interface that interacts with DEXON +// consensus core. +type Application interface { + // PreparePayload is called when consensus core is preparing a block. + PreparePayloads(shardID, chainID, height uint64) [][]byte + + // StronglyAcked is called when a block is strongly acked. + StronglyAcked(blockHash common.Hash) + + // TotalOrderingDeliver is called when the total ordering algorithm deliver + // a set of block. + TotalOrderingDeliver(blockHashes common.Hashes, early bool) + + // DeliverBlock is called when a block is add to the compaction chain. + DeliverBlock(blockHash common.Hash, timestamp time.Time) + + // NotaryAckDeliver is called when a notary ack is created. + NotaryAckDeliver(notaryAck *types.NotaryAck) +} + +// Network describs the network interface that interacts with DEXON consensus +// core. +type Network interface { + // BroadcastVote broadcasts vote to all nodes in DEXON network. + BroadcastVote(vote *types.Vote) + // BroadcastBlock broadcasts block to all nodes in DEXON network. + BroadcastBlock(block *types.Block) + // BroadcastNotaryAck broadcasts notaryAck to all nodes in DEXON network. + BroadcastNotaryAck(notaryAck *types.NotaryAck) + // ReceiveChan returns a channel to receive messages from DEXON network. + ReceiveChan() <-chan interface{} +} diff --git a/core/nonblocking-application.go b/core/nonblocking-application.go index ccdf42e..72f63b9 100644 --- a/core/nonblocking-application.go +++ b/core/nonblocking-application.go @@ -114,6 +114,12 @@ func (app *nonBlockingApplication) wait() { app.running.Wait() } +// PreparePayloads cannot be non-blocking. +func (app *nonBlockingApplication) PreparePayloads( + shardID, chainID, height uint64) [][]byte { + return app.app.PreparePayloads(shardID, chainID, height) +} + // StronglyAcked is called when a block is strongly acked. func (app *nonBlockingApplication) StronglyAcked(blockHash common.Hash) { app.addEvent(stronglyAckedEvent{blockHash}) diff --git a/core/nonblocking-application_test.go b/core/nonblocking-application_test.go index 336eea0..14fb670 100644 --- a/core/nonblocking-application_test.go +++ b/core/nonblocking-application_test.go @@ -45,6 +45,10 @@ func newSlowApp(sleep time.Duration) *slowApp { } } +func (app *slowApp) PreparePayloads(_, _, _ uint64) [][]byte { + return [][]byte{} +} + func (app *slowApp) StronglyAcked(blockHash common.Hash) { time.Sleep(app.sleep) app.stronglyAcked[blockHash] = struct{}{} diff --git a/core/test/app.go b/core/test/app.go index e26c20c..e36a184 100644 --- a/core/test/app.go +++ b/core/test/app.go @@ -102,6 +102,11 @@ func NewApp() *App { } } +// PreparePayloads implements Application interface. +func (app *App) PreparePayloads(shardID, chainID, height uint64) [][]byte { + return [][]byte{} +} + // StronglyAcked implements Application interface. func (app *App) StronglyAcked(blockHash common.Hash) { app.ackedLock.Lock() diff --git a/core/test/blocks-generator.go b/core/test/blocks-generator.go index 3485b77..92271f7 100644 --- a/core/test/blocks-generator.go +++ b/core/test/blocks-generator.go @@ -39,7 +39,7 @@ type validatorStatus struct { lastAckingHeight map[types.ValidatorID]uint64 } -type hashBlockFn func(types.BlockConverter) (common.Hash, error) +type hashBlockFn func(*types.Block) (common.Hash, error) // getAckedBlockHash would randomly pick one block between // last acked one to current head. diff --git a/core/test/utils.go b/core/test/utils.go index 789c28e..5f92ad9 100644 --- a/core/test/utils.go +++ b/core/test/utils.go @@ -25,8 +25,7 @@ import ( "github.com/dexon-foundation/dexon-consensus-core/core/types" ) -func stableRandomHash(blockConv types.BlockConverter) (common.Hash, error) { - block := blockConv.Block() +func stableRandomHash(block *types.Block) (common.Hash, error) { if (block.Hash != common.Hash{}) { return block.Hash, nil } diff --git a/core/types/block.go b/core/types/block.go index 1a55121..f13d868 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -70,6 +70,7 @@ type Block struct { Height uint64 `json:"height"` Timestamps map[ValidatorID]time.Time `json:"timestamps"` Acks map[common.Hash]struct{} `json:"acks"` + Payloads [][]byte `json:"payloads"` Signature crypto.Signature `json:"signature"` CRSSignature crypto.Signature `json:"crs_signature"` @@ -77,29 +78,6 @@ type Block struct { Notary Notary `json:"notary"` } -// Block implements BlockConverter interface. -func (b *Block) Block() *Block { - return b -} - -// Payloads impelmemnts BlockConverter interface. -func (b *Block) Payloads() [][]byte { - return [][]byte{} -} - -// SetBlock implments BlockConverter interface. -func (b *Block) SetBlock(block *Block) { - *b = *block -} - -// BlockConverter interface define the interface for extracting block -// information from an existing object. -type BlockConverter interface { - Block() *Block - Payloads() [][]byte - SetBlock(block *Block) -} - func (b *Block) String() string { return fmt.Sprintf("Block(%v)", b.Hash.String()[:6]) } @@ -130,6 +108,11 @@ func (b *Block) Clone() (bcopy *Block) { for k, v := range b.Acks { bcopy.Acks[k] = v } + bcopy.Payloads = make([][]byte, len(b.Payloads)) + for k, v := range b.Payloads { + bcopy.Payloads[k] = make([]byte, len(v)) + copy(bcopy.Payloads[k], v) + } return } -- cgit v1.2.3