From cd53a2d817c7f9000c0610da30469a5875041229 Mon Sep 17 00:00:00 2001 From: leventeliu Date: Tue, 15 Jan 2019 12:22:42 +0800 Subject: [PATCH 1/4] Add SetHash/VerifyHash methods for verifier --- blockproducer/blocknode.go | 2 +- blockproducer/blocknode_test.go | 41 +++++++++++------ blockproducer/chain.go | 37 ++++++--------- blockproducer/chain_test.go | 4 +- blockproducer/errors.go | 4 +- cmd/cqld/bootstrap.go | 16 ++++--- crypto/verifier/common.go | 48 ++++++++++++++++---- types/bp_block.go | 80 +++++++++++++++++---------------- types/bp_block_gen.go | 55 +++++++---------------- types/bp_block_test.go | 42 ++++++++++++++++- 10 files changed, 194 insertions(+), 135 deletions(-) diff --git a/blockproducer/blocknode.go b/blockproducer/blocknode.go index 8a0aaacc8..317ee655f 100644 --- a/blockproducer/blocknode.go +++ b/blockproducer/blocknode.go @@ -43,7 +43,7 @@ func newBlockNode(h uint32, b *types.BPBlock, p *blockNode) *blockNode { }(), height: h, - hash: b.SignedHeader.BlockHash, + hash: b.SignedHeader.DataHash, block: b, } } diff --git a/blockproducer/blocknode_test.go b/blockproducer/blocknode_test.go index dcebfadb3..09299abdc 100644 --- a/blockproducer/blocknode_test.go +++ b/blockproducer/blocknode_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/CovenantSQL/CovenantSQL/crypto/hash" + "github.com/CovenantSQL/CovenantSQL/crypto/verifier" "github.com/CovenantSQL/CovenantSQL/types" . "github.com/smartystreets/goconvey/convey" ) @@ -29,39 +30,49 @@ func TestBlockNode(t *testing.T) { var ( b0 = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ - BlockHash: hash.Hash{0x1}, + DefaultHashSignVerifierImpl: verifier.DefaultHashSignVerifierImpl{ + DataHash: hash.Hash{0x1}, + }, }, } b1 = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ BPHeader: types.BPHeader{ - ParentHash: b0.SignedHeader.BlockHash, + ParentHash: b0.SignedHeader.DataHash, + }, + DefaultHashSignVerifierImpl: verifier.DefaultHashSignVerifierImpl{ + DataHash: hash.Hash{0x2}, }, - BlockHash: hash.Hash{0x2}, }, } b2 = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ BPHeader: types.BPHeader{ - ParentHash: b1.SignedHeader.BlockHash, + ParentHash: b1.SignedHeader.DataHash, + }, + DefaultHashSignVerifierImpl: verifier.DefaultHashSignVerifierImpl{ + DataHash: hash.Hash{0x3}, }, - BlockHash: hash.Hash{0x3}, }, } b3 = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ BPHeader: types.BPHeader{ - ParentHash: b2.SignedHeader.BlockHash, + ParentHash: b2.SignedHeader.DataHash, + }, + DefaultHashSignVerifierImpl: verifier.DefaultHashSignVerifierImpl{ + DataHash: hash.Hash{0x4}, }, - BlockHash: hash.Hash{0x4}, }, } b4 = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ BPHeader: types.BPHeader{ - ParentHash: b3.SignedHeader.BlockHash, + ParentHash: b3.SignedHeader.DataHash, + }, + DefaultHashSignVerifierImpl: verifier.DefaultHashSignVerifierImpl{ + DataHash: hash.Hash{0x5}, }, - BlockHash: hash.Hash{0x5}, }, } n0 = newBlockNode(0, b0, nil) @@ -73,17 +84,21 @@ func TestBlockNode(t *testing.T) { b3p = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ BPHeader: types.BPHeader{ - ParentHash: b2.SignedHeader.BlockHash, + ParentHash: b2.SignedHeader.DataHash, + }, + DefaultHashSignVerifierImpl: verifier.DefaultHashSignVerifierImpl{ + DataHash: hash.Hash{0x6}, }, - BlockHash: hash.Hash{0x6}, }, } b4p = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ BPHeader: types.BPHeader{ - ParentHash: b3p.SignedHeader.BlockHash, + ParentHash: b3p.SignedHeader.DataHash, + }, + DefaultHashSignVerifierImpl: verifier.DefaultHashSignVerifierImpl{ + DataHash: hash.Hash{0x7}, }, - BlockHash: hash.Hash{0x7}, }, } n3p = newBlockNode(3, b3p, n2) diff --git a/blockproducer/chain.go b/blockproducer/chain.go index be25dd3b2..08acc20eb 100644 --- a/blockproducer/chain.go +++ b/blockproducer/chain.go @@ -31,7 +31,6 @@ import ( "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" "github.com/CovenantSQL/CovenantSQL/crypto/hash" "github.com/CovenantSQL/CovenantSQL/crypto/kms" - "github.com/CovenantSQL/CovenantSQL/merkle" "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/route" "github.com/CovenantSQL/CovenantSQL/rpc" @@ -113,11 +112,20 @@ func NewChainWithContext(ctx context.Context, cfg *Config) (c *Chain, err error) bus = chainbus.New() ) - if fi, err := os.Stat(cfg.DataFile); err == nil && fi.Mode().IsRegular() { - existed = true + // Verify genesis block in config + if cfg.Genesis == nil { + err = ErrNilGenesis + return + } + if ierr = cfg.Genesis.VerifyHash(); ierr != nil { + err = errors.Wrap(ierr, "failed to verify genesis block hash") + return } // Open storage + if fi, err := os.Stat(cfg.DataFile); err == nil && fi.Mode().IsRegular() { + existed = true + } if st, ierr = openStorage(fmt.Sprintf("file:%s", cfg.DataFile)); ierr != nil { err = errors.Wrap(ierr, "failed to open storage") return @@ -134,7 +142,7 @@ func NewChainWithContext(ctx context.Context, cfg *Config) (c *Chain, err error) } var sps = init.compileChanges(nil) sps = append(sps, addBlock(0, cfg.Genesis)) - sps = append(sps, updateIrreversible(cfg.Genesis.SignedHeader.BlockHash)) + sps = append(sps, updateIrreversible(cfg.Genesis.SignedHeader.DataHash)) if ierr = store(st, sps, nil); ierr != nil { err = errors.Wrap(ierr, "failed to initialize storage") return @@ -279,28 +287,9 @@ func (c *Chain) Stop() (err error) { return } -// checkBlock has following steps: 1. check parent block 2. checkTx 2. merkle tree 3. Hash 4. Signature. -func (c *Chain) checkBlock(b *types.BPBlock) (err error) { - rootHash := merkle.NewMerkle(b.GetTxHashes()).GetRoot() - if !b.SignedHeader.MerkleRoot.IsEqual(rootHash) { - return ErrInvalidMerkleTreeRoot - } - - enc, err := b.SignedHeader.BPHeader.MarshalHash() - if err != nil { - return err - } - h := hash.THashH(enc) - if !b.BlockHash().IsEqual(&h) { - return ErrInvalidHash - } - - return nil -} - func (c *Chain) pushBlock(b *types.BPBlock) (err error) { var ierr error - if ierr = c.checkBlock(b); ierr != nil { + if ierr = b.Verify(); ierr != nil { err = errors.Wrap(ierr, "failed to check block") return } diff --git a/blockproducer/chain_test.go b/blockproducer/chain_test.go index 58fd88bf0..79c720024 100644 --- a/blockproducer/chain_test.go +++ b/blockproducer/chain_test.go @@ -121,7 +121,7 @@ func TestChain(t *testing.T) { }), }, } - err = genesis.PackAndSignBlock(testingPrivateKey) + err = genesis.SetHash() So(err, ShouldBeNil) begin = genesis.Timestamp() @@ -147,7 +147,7 @@ func TestChain(t *testing.T) { Convey("A new chain running before genesis time should be waiting for genesis", func() { config.Genesis.SignedHeader.Timestamp = time.Now().Add(24 * time.Hour) - err = genesis.PackAndSignBlock(testingPrivateKey) + err = genesis.SetHash() So(err, ShouldBeNil) chain, err = NewChain(config) So(err, ShouldBeNil) diff --git a/blockproducer/errors.go b/blockproducer/errors.go index 4fee3209f..5599f8d23 100644 --- a/blockproducer/errors.go +++ b/blockproducer/errors.go @@ -27,8 +27,6 @@ var ( ErrInvalidHash = errors.New("Hash is invalid") // ErrExistedTx defines existed tx error. ErrExistedTx = errors.New("Tx existed") - // ErrInvalidMerkleTreeRoot defines invalid merkle tree root error. - ErrInvalidMerkleTreeRoot = errors.New("Block merkle tree root does not match the tx hashes") // ErrParentNotMatch defines invalid parent hash. ErrParentNotMatch = errors.New("Block's parent hash cannot match best block") // ErrTooManyTransactionsInBlock defines error of too many transactions in a block. @@ -70,6 +68,8 @@ var ( ErrMinerUserNotMatch = errors.New("miner and user do not match") // ErrInsufficientAdvancePayment indicates that the advance payment is insufficient. ErrInsufficientAdvancePayment = errors.New("insufficient advance payment") + // ErrNilGenesis indicates that the genesis block is nil in config. + ErrNilGenesis = errors.New("nil genesis block") // ErrMultipleGenesis indicates that there're multiple genesis blocks while loading. ErrMultipleGenesis = errors.New("multiple genesis blocks") // ErrInvalidGasPrice indicates that the gas price is invalid. diff --git a/cmd/cqld/bootstrap.go b/cmd/cqld/bootstrap.go index 420f8a710..55c1ecb62 100644 --- a/cmd/cqld/bootstrap.go +++ b/cmd/cqld/bootstrap.go @@ -50,7 +50,10 @@ const ( func runNode(nodeID proto.NodeID, listenAddr string) (err error) { rootPath := conf.GConf.WorkingRoot - genesis := loadGenesis() + genesis, err := loadGenesis() + if err != nil { + return + } var masterKey []byte if !conf.GConf.IsTestMode { @@ -226,11 +229,11 @@ func initKayakTwoPC(rootDir string, node *proto.Node, peers *proto.Peers, h kt.H return } -func loadGenesis() *types.BPBlock { +func loadGenesis() (genesis *types.BPBlock, err error) { genesisInfo := conf.GConf.BP.BPGenesis log.WithField("config", genesisInfo).Info("load genesis config") - genesis := &types.BPBlock{ + genesis = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ BPHeader: types.BPHeader{ Version: genesisInfo.Version, @@ -239,7 +242,6 @@ func loadGenesis() *types.BPBlock { ParentHash: genesisInfo.ParentHash, Timestamp: genesisInfo.Timestamp, }, - BlockHash: genesisInfo.BlockHash, }, } @@ -256,5 +258,9 @@ func loadGenesis() *types.BPBlock { })) } - return genesis + // Rewrite genesis merkle and block hash + if err = genesis.SetHash(); err != nil { + return + } + return } diff --git a/crypto/verifier/common.go b/crypto/verifier/common.go index 7885eb67a..2167da208 100644 --- a/crypto/verifier/common.go +++ b/crypto/verifier/common.go @@ -33,7 +33,11 @@ type MarshalHasher interface { // MarshalHasher, can be signed by a private key and verified later. type HashSignVerifier interface { Hash() hash.Hash + SetHash(MarshalHasher) error + SignHash(*ca.PrivateKey) error Sign(MarshalHasher, *ca.PrivateKey) error + VerifyHash(MarshalHasher) error + VerifySignature() error Verify(MarshalHasher) error } @@ -49,23 +53,37 @@ func (i *DefaultHashSignVerifierImpl) Hash() hash.Hash { return i.DataHash } -// Sign implements HashSignVerifier.Sign. -func (i *DefaultHashSignVerifierImpl) Sign(mh MarshalHasher, signer *ca.PrivateKey) (err error) { +// SetHash implements HashSignVerifier.SetHash. +func (i *DefaultHashSignVerifierImpl) SetHash(mh MarshalHasher) (err error) { var enc []byte if enc, err = mh.MarshalHash(); err != nil { return } - var h = hash.THashH(enc) - if i.Signature, err = signer.Sign(h[:]); err != nil { + i.DataHash = hash.THashH(enc) + return +} + +// SignHash implements HashSignVerifier.SignHash. +func (i *DefaultHashSignVerifierImpl) SignHash(signer *ca.PrivateKey) (err error) { + if i.Signature, err = signer.Sign(i.DataHash[:]); err != nil { return } - i.DataHash = h i.Signee = signer.PubKey() return } -// Verify implements HashSignVerifier.Verify. -func (i *DefaultHashSignVerifierImpl) Verify(mh MarshalHasher) (err error) { +// Sign implements HashSignVerifier.Sign. +func (i *DefaultHashSignVerifierImpl) Sign(mh MarshalHasher, signer *ca.PrivateKey) (err error) { + // Set hash + if err = i.SetHash(mh); err != nil { + return + } + err = i.SignHash(signer) + return +} + +// VerifyHash implements HashSignVerifier.VerifyHash. +func (i *DefaultHashSignVerifierImpl) VerifyHash(mh MarshalHasher) (err error) { var enc []byte if enc, err = mh.MarshalHash(); err != nil { return @@ -75,9 +93,23 @@ func (i *DefaultHashSignVerifierImpl) Verify(mh MarshalHasher) (err error) { err = errors.WithStack(ErrHashValueNotMatch) return } - if i.Signature == nil || i.Signee == nil || !i.Signature.Verify(h[:], i.Signee) { + return +} + +// VerifySignature implements HashSignVerifier.VerifySignature. +func (i *DefaultHashSignVerifierImpl) VerifySignature() (err error) { + if i.Signature == nil || i.Signee == nil || !i.Signature.Verify(i.DataHash[:], i.Signee) { err = errors.WithStack(ErrSignatureNotMatch) return } return } + +// Verify implements HashSignVerifier.Verify. +func (i *DefaultHashSignVerifierImpl) Verify(mh MarshalHasher) (err error) { + if err = i.VerifyHash(mh); err != nil { + return + } + err = i.VerifySignature() + return +} diff --git a/types/bp_block.go b/types/bp_block.go index 72c721e10..4fd05a3ad 100644 --- a/types/bp_block.go +++ b/types/bp_block.go @@ -22,6 +22,7 @@ import ( pi "github.com/CovenantSQL/CovenantSQL/blockproducer/interfaces" "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" "github.com/CovenantSQL/CovenantSQL/crypto/hash" + "github.com/CovenantSQL/CovenantSQL/crypto/verifier" "github.com/CovenantSQL/CovenantSQL/merkle" "github.com/CovenantSQL/CovenantSQL/proto" ) @@ -40,18 +41,23 @@ type BPHeader struct { // BPSignedHeader defines the main chain header with the signature. type BPSignedHeader struct { BPHeader - BlockHash hash.Hash - Signee *asymmetric.PublicKey - Signature *asymmetric.Signature + verifier.DefaultHashSignVerifierImpl } -// Verify verifies the signature. -func (s *BPSignedHeader) Verify() error { - if !s.Signature.Verify(s.BlockHash[:], s.Signee) { - return ErrSignVerification - } +func (s *BPSignedHeader) verifyHash() error { + return s.DefaultHashSignVerifierImpl.VerifyHash(&s.BPHeader) +} - return nil +func (s *BPSignedHeader) verify() error { + return s.DefaultHashSignVerifierImpl.Verify(&s.BPHeader) +} + +func (s *BPSignedHeader) setHash() error { + return s.DefaultHashSignVerifierImpl.SetHash(&s.BPHeader) +} + +func (s *BPSignedHeader) sign(signer *asymmetric.PrivateKey) error { + return s.DefaultHashSignVerifierImpl.Sign(&s.BPHeader, signer) } // BPBlock defines the main chain block. @@ -73,47 +79,45 @@ func (b *BPBlock) GetTxHashes() []*hash.Hash { return hs } -// PackAndSignBlock computes block's hash and sign it. -func (b *BPBlock) PackAndSignBlock(signer *asymmetric.PrivateKey) error { - hs := b.GetTxHashes() - - b.SignedHeader.MerkleRoot = *merkle.NewMerkle(hs).GetRoot() - enc, err := b.SignedHeader.BPHeader.MarshalHash() +func (b *BPBlock) setMerkleRoot() { + var merkleRoot = merkle.NewMerkle(b.GetTxHashes()).GetRoot() + b.SignedHeader.MerkleRoot = *merkleRoot +} - if err != nil { - return err +func (b *BPBlock) verifyMerkleRoot() error { + var merkleRoot = *merkle.NewMerkle(b.GetTxHashes()).GetRoot() + if !merkleRoot.IsEqual(&b.SignedHeader.MerkleRoot) { + return ErrMerkleRootVerification } + return nil +} - b.SignedHeader.BlockHash = hash.THashH(enc) - b.SignedHeader.Signature, err = signer.Sign(b.SignedHeader.BlockHash[:]) - b.SignedHeader.Signee = signer.PubKey() +// SetHash sets the block header hash, including the merkle root of the packed transactions. +func (b *BPBlock) SetHash() error { + b.setMerkleRoot() + return b.SignedHeader.setHash() +} - if err != nil { +// VerifyHash verifies the block header hash, including the merkle root of the packed transactions. +func (b *BPBlock) VerifyHash() error { + if err := b.verifyMerkleRoot(); err != nil { return err } + return b.SignedHeader.verifyHash() +} - return nil +// PackAndSignBlock computes block's hash and sign it. +func (b *BPBlock) PackAndSignBlock(signer *asymmetric.PrivateKey) error { + b.setMerkleRoot() + return b.SignedHeader.sign(signer) } // Verify verifies whether the block is valid. func (b *BPBlock) Verify() error { - hs := b.GetTxHashes() - merkleRoot := *merkle.NewMerkle(hs).GetRoot() - if !merkleRoot.IsEqual(&b.SignedHeader.MerkleRoot) { - return ErrMerkleRootVerification - } - - enc, err := b.SignedHeader.BPHeader.MarshalHash() - if err != nil { + if err := b.verifyMerkleRoot(); err != nil { return err } - - h := hash.THashH(enc) - if !h.IsEqual(&b.SignedHeader.BlockHash) { - return ErrHashVerification - } - - return b.SignedHeader.Verify() + return b.SignedHeader.verify() } // Timestamp returns timestamp of block. @@ -133,5 +137,5 @@ func (b *BPBlock) ParentHash() *hash.Hash { // BlockHash returns the parent hash field of the block header. func (b *BPBlock) BlockHash() *hash.Hash { - return &b.SignedHeader.BlockHash + return &b.SignedHeader.DataHash } diff --git a/types/bp_block_gen.go b/types/bp_block_gen.go index 5afbe938a..baa2fd975 100644 --- a/types/bp_block_gen.go +++ b/types/bp_block_gen.go @@ -11,8 +11,15 @@ func (z *BPBlock) MarshalHash() (o []byte, err error) { var b []byte o = hsp.Require(b, z.Msgsize()) // map header, size 2 - o = append(o, 0x82, 0x82) - if oTemp, err := z.SignedHeader.MarshalHash(); err != nil { + // map header, size 2 + o = append(o, 0x82, 0x82, 0x82, 0x82) + if oTemp, err := z.SignedHeader.BPHeader.MarshalHash(); err != nil { + return nil, err + } else { + o = hsp.AppendBytes(o, oTemp) + } + o = append(o, 0x82) + if oTemp, err := z.SignedHeader.DefaultHashSignVerifierImpl.MarshalHash(); err != nil { return nil, err } else { o = hsp.AppendBytes(o, oTemp) @@ -31,7 +38,7 @@ func (z *BPBlock) MarshalHash() (o []byte, err error) { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *BPBlock) Msgsize() (s int) { - s = 1 + 13 + z.SignedHeader.Msgsize() + 13 + hsp.ArrayHeaderSize + s = 1 + 13 + 1 + 9 + z.SignedHeader.BPHeader.Msgsize() + 28 + z.SignedHeader.DefaultHashSignVerifierImpl.Msgsize() + 13 + hsp.ArrayHeaderSize for za0001 := range z.Transactions { s += z.Transactions[za0001].Msgsize() } @@ -78,35 +85,15 @@ func (z *BPHeader) Msgsize() (s int) { func (z *BPSignedHeader) MarshalHash() (o []byte, err error) { var b []byte o = hsp.Require(b, z.Msgsize()) - // map header, size 4 - o = append(o, 0x84, 0x84) - if z.Signee == nil { - o = hsp.AppendNil(o) - } else { - if oTemp, err := z.Signee.MarshalHash(); err != nil { - return nil, err - } else { - o = hsp.AppendBytes(o, oTemp) - } - } - o = append(o, 0x84) - if z.Signature == nil { - o = hsp.AppendNil(o) - } else { - if oTemp, err := z.Signature.MarshalHash(); err != nil { - return nil, err - } else { - o = hsp.AppendBytes(o, oTemp) - } - } - o = append(o, 0x84) + // map header, size 2 + o = append(o, 0x82, 0x82) if oTemp, err := z.BPHeader.MarshalHash(); err != nil { return nil, err } else { o = hsp.AppendBytes(o, oTemp) } - o = append(o, 0x84) - if oTemp, err := z.BlockHash.MarshalHash(); err != nil { + o = append(o, 0x82) + if oTemp, err := z.DefaultHashSignVerifierImpl.MarshalHash(); err != nil { return nil, err } else { o = hsp.AppendBytes(o, oTemp) @@ -116,18 +103,6 @@ func (z *BPSignedHeader) MarshalHash() (o []byte, err error) { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *BPSignedHeader) Msgsize() (s int) { - s = 1 + 7 - if z.Signee == nil { - s += hsp.NilSize - } else { - s += z.Signee.Msgsize() - } - s += 10 - if z.Signature == nil { - s += hsp.NilSize - } else { - s += z.Signature.Msgsize() - } - s += 9 + z.BPHeader.Msgsize() + 10 + z.BlockHash.Msgsize() + s = 1 + 9 + z.BPHeader.Msgsize() + 28 + z.DefaultHashSignVerifierImpl.Msgsize() return } diff --git a/types/bp_block_test.go b/types/bp_block_test.go index 60bf2d793..3c492dd97 100644 --- a/types/bp_block_test.go +++ b/types/bp_block_test.go @@ -22,7 +22,9 @@ import ( "reflect" "testing" + "github.com/CovenantSQL/CovenantSQL/crypto/verifier" "github.com/CovenantSQL/CovenantSQL/utils" + "github.com/pkg/errors" ) func TestHeader_MarshalUnmarshalBinary(t *testing.T) { @@ -114,14 +116,50 @@ func TestBlock_PackAndSignBlock(t *testing.T) { t.Fatalf("failed to generate block: %v", err) } + err = block.verifyMerkleRoot() + if err != nil { + t.Fatalf("failed to verify: %v", err) + } + + err = block.VerifyHash() + if err != nil { + t.Fatalf("failed to verify: %v", err) + } + + err = block.Verify() + if err != nil { + t.Fatalf("failed to verify: %v", err) + } + + block.SignedHeader.DataHash[0]++ err = block.Verify() + if errors.Cause(err) != verifier.ErrHashValueNotMatch { + t.Fatalf("unexpected error: %v", err) + } + err = block.VerifyHash() + if errors.Cause(err) != verifier.ErrHashValueNotMatch { + t.Fatalf("unexpected error: %v", err) + } + err = block.SetHash() + if err != nil { + t.Fatalf("failed to set hash: %v", err) + } + err = block.VerifyHash() if err != nil { t.Fatalf("failed to verify: %v", err) } - block.SignedHeader.BlockHash[0]++ + block.SignedHeader.MerkleRoot[0]++ err = block.Verify() - if err != ErrHashVerification { + if err != ErrMerkleRootVerification { + t.Fatalf("unexpected error: %v", err) + } + err = block.VerifyHash() + if err != ErrMerkleRootVerification { + t.Fatalf("unexpected error: %v", err) + } + err = block.verifyMerkleRoot() + if err != ErrMerkleRootVerification { t.Fatalf("unexpected error: %v", err) } From ca2a2c2dd3e3a460ae0afddd5f5d72284f4e5596 Mon Sep 17 00:00:00 2001 From: leventeliu Date: Tue, 15 Jan 2019 16:46:44 +0800 Subject: [PATCH 2/4] Add persisted genesis block hash check on startup --- blockproducer/chain.go | 10 +++++++++ blockproducer/chain_test.go | 42 +++++++++++++++++++++++++++++++++++++ blockproducer/errors.go | 3 +++ 3 files changed, 55 insertions(+) diff --git a/blockproducer/chain.go b/blockproducer/chain.go index 08acc20eb..83409833e 100644 --- a/blockproducer/chain.go +++ b/blockproducer/chain.go @@ -130,6 +130,11 @@ func NewChainWithContext(ctx context.Context, cfg *Config) (c *Chain, err error) err = errors.Wrap(ierr, "failed to open storage") return } + defer func() { + if err != nil { + st.Close() + } + }() // Create initial state from genesis block and store if !existed { @@ -154,6 +159,11 @@ func NewChainWithContext(ctx context.Context, cfg *Config) (c *Chain, err error) err = errors.Wrap(ierr, "failed to load data from storage") return } + if persistedGenesis := irre.ancestorByCount(0); persistedGenesis == nil || + !persistedGenesis.hash.IsEqual(cfg.Genesis.BlockHash()) { + err = ErrGenesisHashNotMatch + return + } for _, v := range heads { log.WithFields(log.Fields{ "irre_hash": irre.hash.Short(4), diff --git a/blockproducer/chain_test.go b/blockproducer/chain_test.go index 79c720024..cc6c662a9 100644 --- a/blockproducer/chain_test.go +++ b/blockproducer/chain_test.go @@ -31,6 +31,7 @@ import ( "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/rpc" "github.com/CovenantSQL/CovenantSQL/types" + "github.com/pkg/errors" . "github.com/smartystreets/goconvey/convey" ) @@ -312,6 +313,47 @@ func TestChain(t *testing.T) { chain.stat() }) + Convey("The chain should report error if genesis in config is cleared", func() { + err = chain.Stop() + So(err, ShouldBeNil) + config.Genesis = nil + chain, err = NewChain(config) + So(err, ShouldEqual, ErrNilGenesis) + So(chain, ShouldBeNil) + }) + + Convey("The chain should report error if config is changed", func() { + err = chain.Stop() + So(err, ShouldBeNil) + config.Genesis.Transactions = append( + config.Genesis.Transactions, + types.NewBaseAccount(&types.Account{ + Address: addr2, + TokenBalance: [5]uint64{1000, 1000, 1000, 1000, 1000}, + }), + ) + chain, err = NewChain(config) + So(errors.Cause(err), ShouldEqual, types.ErrMerkleRootVerification) + So(chain, ShouldBeNil) + }) + + Convey("The chain should report error if config is changed and rehashed", func() { + err = chain.Stop() + So(err, ShouldBeNil) + config.Genesis.Transactions = append( + config.Genesis.Transactions, + types.NewBaseAccount(&types.Account{ + Address: addr2, + TokenBalance: [5]uint64{1000, 1000, 1000, 1000, 1000}, + }), + ) + err = config.Genesis.SetHash() + So(err, ShouldBeNil) + chain, err = NewChain(config) + So(err, ShouldEqual, ErrGenesisHashNotMatch) + So(chain, ShouldBeNil) + }) + Convey("The chain APIs should return expected results", func() { var ( bl *types.BPBlock diff --git a/blockproducer/errors.go b/blockproducer/errors.go index 5599f8d23..42421b072 100644 --- a/blockproducer/errors.go +++ b/blockproducer/errors.go @@ -72,6 +72,9 @@ var ( ErrNilGenesis = errors.New("nil genesis block") // ErrMultipleGenesis indicates that there're multiple genesis blocks while loading. ErrMultipleGenesis = errors.New("multiple genesis blocks") + // ErrGenesisHashNotMatch indicates that the genesis block hash in config doesn't match + // the persisted one. + ErrGenesisHashNotMatch = errors.New("persisted genesis block hash not match") // ErrInvalidGasPrice indicates that the gas price is invalid. ErrInvalidGasPrice = errors.New("gas price is invalid") // ErrInvalidMinerCount indicates that the miner node count is invalid. From 95aa69171ae1c4ede7264512fcf0d265025342eb Mon Sep 17 00:00:00 2001 From: leventeliu Date: Tue, 15 Jan 2019 18:08:56 +0800 Subject: [PATCH 3/4] Remove genesis config fields --- cmd/cqld/bootstrap.go | 7 ++----- conf/config.go | 8 -------- conf/config_test.go | 8 ++------ 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/cmd/cqld/bootstrap.go b/cmd/cqld/bootstrap.go index 55c1ecb62..89f456552 100644 --- a/cmd/cqld/bootstrap.go +++ b/cmd/cqld/bootstrap.go @@ -236,11 +236,8 @@ func loadGenesis() (genesis *types.BPBlock, err error) { genesis = &types.BPBlock{ SignedHeader: types.BPSignedHeader{ BPHeader: types.BPHeader{ - Version: genesisInfo.Version, - Producer: proto.AccountAddress(genesisInfo.Producer), - MerkleRoot: genesisInfo.MerkleRoot, - ParentHash: genesisInfo.ParentHash, - Timestamp: genesisInfo.Timestamp, + Version: genesisInfo.Version, + Timestamp: genesisInfo.Timestamp, }, }, } diff --git a/conf/config.go b/conf/config.go index 7f3914842..5acef45a3 100644 --- a/conf/config.go +++ b/conf/config.go @@ -54,16 +54,8 @@ type BaseAccountInfo struct { type BPGenesisInfo struct { // Version defines the block version Version int32 `yaml:"Version"` - // Producer defines the block producer - Producer hash.Hash `yaml:"Producer"` - // MerkleRoot defines the transaction merkle tree's root - MerkleRoot hash.Hash `yaml:"MerkleRoot"` - // ParentHash defines the parent block's hash - ParentHash hash.Hash `yaml:"ParentHash"` // Timestamp defines the initial time of chain Timestamp time.Time `yaml:"Timestamp"` - // BlockHash defines the block hash of genesis block - BlockHash hash.Hash `yaml:"BlockHash"` // BaseAccounts defines the base accounts for testnet BaseAccounts []BaseAccountInfo `yaml:"BaseAccounts"` } diff --git a/conf/config_test.go b/conf/config_test.go index 1cdc590dd..43bfc74e5 100644 --- a/conf/config_test.go +++ b/conf/config_test.go @@ -62,12 +62,8 @@ func TestConf(t *testing.T) { }, ChainFileName: "", BPGenesis: BPGenesisInfo{ - Version: 1, - Producer: h, - MerkleRoot: h, - ParentHash: h, - Timestamp: time.Now().UTC(), - BlockHash: h, + Version: 1, + Timestamp: time.Now().UTC(), }, } Convey("LoadConfig", t, func() { From efebf088683a6ddcdc747e9eb5ee5e7a5742e01f Mon Sep 17 00:00:00 2001 From: leventeliu Date: Thu, 17 Jan 2019 11:23:57 +0800 Subject: [PATCH 4/4] Minor fix --- crypto/verifier/common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/verifier/common.go b/crypto/verifier/common.go index 2167da208..dc99a8fbb 100644 --- a/crypto/verifier/common.go +++ b/crypto/verifier/common.go @@ -98,7 +98,7 @@ func (i *DefaultHashSignVerifierImpl) VerifyHash(mh MarshalHasher) (err error) { // VerifySignature implements HashSignVerifier.VerifySignature. func (i *DefaultHashSignVerifierImpl) VerifySignature() (err error) { - if i.Signature == nil || i.Signee == nil || !i.Signature.Verify(i.DataHash[:], i.Signee) { + if !i.Signature.Verify(i.DataHash[:], i.Signee) { err = errors.WithStack(ErrSignatureNotMatch) return }