Merge pull request #1405 from nspcc-dev/rework-block-verifications

Rework block verifications a bit
This commit is contained in:
Roman Khimov 2020-09-16 14:27:24 +03:00 committed by GitHub
commit 6f3aff76a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 17 additions and 53 deletions

View file

@ -46,8 +46,8 @@ func (b *Block) Header() *Header {
} }
} }
// computeMerkleTree computes Merkle tree based on actual block's data. // ComputeMerkleRoot computes Merkle tree root hash based on actual block's data.
func (b *Block) computeMerkleTree() util.Uint256 { func (b *Block) ComputeMerkleRoot() util.Uint256 {
hashes := make([]util.Uint256, len(b.Transactions)+1) hashes := make([]util.Uint256, len(b.Transactions)+1)
hashes[0] = b.ConsensusData.Hash() hashes[0] = b.ConsensusData.Hash()
for i, tx := range b.Transactions { for i, tx := range b.Transactions {
@ -59,27 +59,7 @@ func (b *Block) computeMerkleTree() util.Uint256 {
// RebuildMerkleRoot rebuilds the merkleroot of the block. // RebuildMerkleRoot rebuilds the merkleroot of the block.
func (b *Block) RebuildMerkleRoot() { func (b *Block) RebuildMerkleRoot() {
b.MerkleRoot = b.computeMerkleTree() b.MerkleRoot = b.ComputeMerkleRoot()
}
// Verify verifies the integrity of the block.
func (b *Block) Verify() error {
if b.Transactions != nil {
hashes := map[util.Uint256]bool{}
for _, tx := range b.Transactions {
if !hashes[tx.Hash()] {
hashes[tx.Hash()] = true
} else {
return errors.New("transaction duplication is not allowed")
}
}
}
merkle := b.computeMerkleTree()
if !b.MerkleRoot.Equals(merkle) {
return errors.New("MerkleRoot mismatch")
}
return nil
} }
// NewBlockFromTrimmedBytes returns a new block from trimmed data. // NewBlockFromTrimmedBytes returns a new block from trimmed data.
@ -173,7 +153,6 @@ func (b *Block) DecodeBinary(br *io.BinReader) {
if br.Err != nil { if br.Err != nil {
return return
} }
br.Err = b.Verify()
} }
// EncodeBinary encodes the block to the given BinWriter, implementing // EncodeBinary encodes the block to the given BinWriter, implementing

View file

@ -64,12 +64,6 @@ type baseAux struct {
Witnesses []transaction.Witness `json:"witnesses"` Witnesses []transaction.Witness `json:"witnesses"`
} }
// Verify verifies the integrity of the Base.
func (b *Base) Verify() bool {
// TODO: Need a persisted blockchain for this.
return true
}
// Hash returns the hash of the block. // Hash returns the hash of the block.
func (b *Base) Hash() util.Uint256 { func (b *Base) Hash() util.Uint256 {
if b.hash.Equals(util.Uint256{}) { if b.hash.Equals(util.Uint256{}) {

View file

@ -108,17 +108,6 @@ func TestHashBlockEqualsHashHeader(t *testing.T) {
assert.Equal(t, block.Hash(), block.Header().Hash()) assert.Equal(t, block.Hash(), block.Header().Hash())
} }
func TestBlockVerify(t *testing.T) {
block := newDumbBlock()
assert.NotNil(t, block.Verify())
block.RebuildMerkleRoot()
assert.Nil(t, block.Verify())
block.Transactions = []*transaction.Transaction{}
block.RebuildMerkleRoot()
assert.Nil(t, block.Verify())
}
func TestBinBlockDecodeEncode(t *testing.T) { func TestBinBlockDecodeEncode(t *testing.T) {
// transaction taken from mainnet: 2000000 // transaction taken from mainnet: 2000000
rawtx := "0000000005440c786a66aaebf472aacb1d1db19d5b494c6a9226ea91bf5cf0e63a6605138cde5064efb81bc6539620b9e6d6d7c74f97d415b922c4fb4bb1833ce6a97a9d61f962fb7301000065f000005d12ac6c589d59f92e82d8bf60659cb716ffc1f101fd4a010c4011ff5d2138cf546d112ef712ee8a15277f7b6f1d5d2564b97497ac155782e6089cd3005dc9de81a8b22bb2f1c3a2edbac55e01581cb27980fdedf3a8bc57fa470c40657253c374a48da773fc653591f282a63a60695f29ab6c86300020ed505a019e5563e1be493efa71bdde37b16b4ec3f5f6dc2d2a2550151b020176b4dbe7afe40c403efdc559cb6bff135fd79138267db897c6fded01e3a0f15c0fb1c337359935d65e7ac49239f020951a74a96e11e73d225c9789953ffec40d5f7c9a84707b1d9a0c402804f24ab8034fa41223977ba48883eb94951184e31e5739872daf4f65461de3196ebf333f6d7dc4aff0b7b2143793179415f50a715484aba4e33b97dc636e150c40ed6b2ffeaef97eef746815ad16f5b8aed743892e93f7216bb744eb5c2f4cad91ae291919b61cd9a8d50fe85630d5e010c49a01ed687727c3ae5a7e17d4da213afdfd00150c2103009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a20c21030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba0c210214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff010c2103408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a2594778060c2102a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b0c2102ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd0c2102f889ecd43c5126ff1932d75fa87dea34fc95325fb724db93c8f79fe32cc3f180170b41138defaf0202c1353ed4e94d0cbc00be80024f7673890000000000261c130000000000e404210001f813c2cc8e18bbe4b3b87f8ef9105b50bb93918e01005d0300743ba40b0000000c14aa07cc3f2193a973904a09a6e60b87f1f96273970c14f813c2cc8e18bbe4b3b87f8ef9105b50bb93918e13c00c087472616e736665720c14bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e6641627d5b523801420c402360bbf64b9644c25f066dbd406454b07ab9f56e8e25d92d90c96c598f6c29d97eabdcf226f3575481662cfcdd064ee410978e5fae3f09a2f83129ba9cd82641290c2103caf763f91d3691cba5b5df3eb13e668fdace0295b37e2e259fd0fb152d354f900b4195440d78" rawtx := "0000000005440c786a66aaebf472aacb1d1db19d5b494c6a9226ea91bf5cf0e63a6605138cde5064efb81bc6539620b9e6d6d7c74f97d415b922c4fb4bb1833ce6a97a9d61f962fb7301000065f000005d12ac6c589d59f92e82d8bf60659cb716ffc1f101fd4a010c4011ff5d2138cf546d112ef712ee8a15277f7b6f1d5d2564b97497ac155782e6089cd3005dc9de81a8b22bb2f1c3a2edbac55e01581cb27980fdedf3a8bc57fa470c40657253c374a48da773fc653591f282a63a60695f29ab6c86300020ed505a019e5563e1be493efa71bdde37b16b4ec3f5f6dc2d2a2550151b020176b4dbe7afe40c403efdc559cb6bff135fd79138267db897c6fded01e3a0f15c0fb1c337359935d65e7ac49239f020951a74a96e11e73d225c9789953ffec40d5f7c9a84707b1d9a0c402804f24ab8034fa41223977ba48883eb94951184e31e5739872daf4f65461de3196ebf333f6d7dc4aff0b7b2143793179415f50a715484aba4e33b97dc636e150c40ed6b2ffeaef97eef746815ad16f5b8aed743892e93f7216bb744eb5c2f4cad91ae291919b61cd9a8d50fe85630d5e010c49a01ed687727c3ae5a7e17d4da213afdfd00150c2103009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a20c21030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba0c210214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff010c2103408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a2594778060c2102a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b0c2102ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd0c2102f889ecd43c5126ff1932d75fa87dea34fc95325fb724db93c8f79fe32cc3f180170b41138defaf0202c1353ed4e94d0cbc00be80024f7673890000000000261c130000000000e404210001f813c2cc8e18bbe4b3b87f8ef9105b50bb93918e01005d0300743ba40b0000000c14aa07cc3f2193a973904a09a6e60b87f1f96273970c14f813c2cc8e18bbe4b3b87f8ef9105b50bb93918e13c00c087472616e736665720c14bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e6641627d5b523801420c402360bbf64b9644c25f066dbd406454b07ab9f56e8e25d92d90c96c598f6c29d97eabdcf226f3575481662cfcdd064ee410978e5fae3f09a2f83129ba9cd82641290c2103caf763f91d3691cba5b5df3eb13e668fdace0295b37e2e259fd0fb152d354f900b4195440d78"
@ -157,6 +146,9 @@ func TestBinBlockDecodeEncode(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, rawtx, hex.EncodeToString(data)) assert.Equal(t, rawtx, hex.EncodeToString(data))
// update hidden hash value.
_ = b.ConsensusData.Hash()
testserdes.MarshalUnmarshalJSON(t, b, New(netmode.TestNet)) testserdes.MarshalUnmarshalJSON(t, b, New(netmode.TestNet))
} }

View file

@ -264,9 +264,6 @@ func (bc *Blockchain) init() error {
} }
headerSliceReverse(headers) headerSliceReverse(headers)
for _, h := range headers { for _, h := range headers {
if !h.Verify() {
return fmt.Errorf("bad header %d/%s in the storage", h.Index, h.Hash())
}
bc.headerList.Add(h.Hash()) bc.headerList.Add(h.Hash())
} }
} }
@ -426,9 +423,9 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
} }
} }
if bc.config.VerifyBlocks { if bc.config.VerifyBlocks {
err := block.Verify() merkle := block.ComputeMerkleRoot()
if err != nil { if !block.MerkleRoot.Equals(merkle) {
return fmt.Errorf("block %s is invalid: %w", block.Hash().StringLE(), err) return errors.New("invalid block: MerkleRoot mismatch")
} }
mp = mempool.New(len(block.Transactions)) mp = mempool.New(len(block.Transactions))
for _, tx := range block.Transactions { for _, tx := range block.Transactions {
@ -506,10 +503,6 @@ func (bc *Blockchain) addHeaders(verify bool, headers ...*block.Header) (err err
if int(h.Index) < headerList.Len() { if int(h.Index) < headerList.Len() {
continue continue
} }
if !h.Verify() {
err = fmt.Errorf("header %v is invalid", h)
return
}
if err = bc.processHeader(h, batch, headerList); err != nil { if err = bc.processHeader(h, batch, headerList); err != nil {
return return
} }

View file

@ -161,7 +161,10 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
}, },
serverResponse: b1Verbose, serverResponse: b1Verbose,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
return getResultBlock1() res := getResultBlock1()
// update hidden hash value.
_ = res.Block.ConsensusData.Hash()
return res
}, },
}, },
{ {
@ -190,7 +193,10 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
}, },
serverResponse: b1Verbose, serverResponse: b1Verbose,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
return getResultBlock1() res := getResultBlock1()
// update hidden hash value.
_ = res.Block.ConsensusData.Hash()
return res
}, },
}, },
}, },