Skip to content

Commit

Permalink
Merge pull request #1502 from dusk-network/tx-root
Browse files Browse the repository at this point in the history
  • Loading branch information
herr-seppia authored Feb 22, 2023
2 parents cdab00a + 6629d9f commit 12e737e
Show file tree
Hide file tree
Showing 16 changed files with 145 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- Add `Iteration` to block header [#1500]
- Add `TxRoot` to block header [#1499]

### Removed
- Remove `step` from block header certificate [#1500]
Expand Down Expand Up @@ -98,6 +99,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- Issues -->

[#1500]: https://github.com/dusk-network/dusk-blockchain/issues/1500
[#1499]: https://github.com/dusk-network/dusk-blockchain/issues/1499
[#1481]: https://github.com/dusk-network/dusk-blockchain/issues/1481
[#1479]: https://github.com/dusk-network/dusk-blockchain/issues/1479
[#1464]: https://github.com/dusk-network/dusk-blockchain/issues/1464
Expand Down
1 change: 1 addition & 0 deletions cmd/utils/metrics/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Header struct {
PrevBlockHash []byte `json:"prev-hash"` // Hash of previous block (32 bytes)
Seed []byte `json:"seed"` // Marshaled BLS signature or hash of the previous block seed (32 bytes)
GeneratorBlsPubkey []byte `json:"generator"` // Generator BLS Public Key (96 bytes)
TxRoot []byte `json:"txroot"` // Root hash of the merkle tree containing all txes (32 bytes)

//*Certificate `json:"certificate"` // Block certificate
Hash []byte `json:"hash"` // Hash of all previous fields
Expand Down
9 changes: 9 additions & 0 deletions pkg/config/genesis/generation.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func Generate(c Config) *block.Block {
Height: 0,
PrevBlockHash: state_root,
GeneratorBlsPubkey: make([]byte, 96),
TxRoot: nil,
Seed: c.seed,
Certificate: block.EmptyCertificate(),
StateHash: state_root,
Expand All @@ -40,6 +41,14 @@ func Generate(c Config) *block.Block {
Txs: c.Transactions,
}

// Set root and hash, since they have changed because of the adding of txs.
root, err := b.CalculateTxRoot()
if err != nil {
panic(err)
}

b.Header.TxRoot = root

hash, err := b.CalculateHash()
if err != nil {
panic(err)
Expand Down
6 changes: 3 additions & 3 deletions pkg/config/genesis/presets.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ func addDefaultTxs(name string, c Config) Config {
// the other hand, in order to be aligned with default testnet genesis hash
// we need one empty tx in testnet genesis block.
switch name {
case "testnet":
c.Transactions = append(c.Transactions, transactions.EmptyTx())
default:
case "test":
c.Transactions = append(c.Transactions, transactions.MockTx())
default:
c.Transactions = append(c.Transactions, transactions.EmptyTx())
}

return c
Expand Down
18 changes: 18 additions & 0 deletions pkg/core/candidate/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ func SanityCheckCandidate(cm block.Block) error {
return errors.New("invalid candidate received")
}

if err := checkRoot(&cm); err != nil {
log.WithError(err).Errorln("validation failed")
return errors.New("invalid candidate received")
}

return nil
}

Expand All @@ -43,3 +48,16 @@ func checkHash(blk *block.Block) error {

return nil
}

func checkRoot(blk *block.Block) error {
root, err := blk.CalculateTxRoot()
if err != nil {
return err
}

if !bytes.Equal(root, blk.Header.TxRoot) {
return errors.New("invalid merkle root hash")
}

return nil
}
12 changes: 12 additions & 0 deletions pkg/core/consensus/blockgenerator/candidate/blockgenerator.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ func (bg *generator) GenerateBlock(ctx context.Context, round uint64, seed, prev
Height: round,
PrevBlockHash: prevBlockHash,
GeneratorBlsPubkey: bg.Keys.BLSPubKey,
TxRoot: nil,
Seed: seed,
Certificate: block.EmptyCertificate(),
StateHash: stateHash,
Expand All @@ -196,6 +197,17 @@ func (bg *generator) GenerateBlock(ctx context.Context, round uint64, seed, prev
Txs: txs,
}

// Update TxRoot
root, err := candidateBlock.CalculateTxRoot()
if err != nil {
lg.
WithError(err).
Error("failed to CalculateRoot")
return nil, err
}

candidateBlock.Header.TxRoot = root

// Generate the block hash
hash, err := candidateBlock.CalculateHash()
if err != nil {
Expand Down
22 changes: 22 additions & 0 deletions pkg/core/data/block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/dusk-network/dusk-blockchain/pkg/core/data/ipc/transactions"
"github.com/dusk-network/dusk-blockchain/pkg/p2p/wire/message/payload"
"github.com/dusk-network/dusk-crypto/merkletree"
"github.com/dusk-network/dusk-protobuf/autogen/go/rusk"
)

Expand Down Expand Up @@ -77,6 +78,27 @@ func (b *Block) SetPrevBlock(prevHeader *Header) {
b.Header.PrevBlockHash = prevHeader.Hash
}

// CalculateTxRoot will calculate and return the block merkle root hash.
func (b *Block) CalculateTxRoot() ([]byte, error) {
txsLen := len(b.Txs)
if txsLen == 0 {
return EmptyHash[:], nil
}

// convert Transaction interface to Payload interface
txs := make([]merkletree.Payload, txsLen)
for i, tx := range b.Txs {
txs[i] = tx.(merkletree.Payload)
}

tree, err := merkletree.NewTree(txs)
if err != nil {
return nil, err
}

return tree.MerkleRoot, nil
}

// AddTx will add a transaction to the block.
func (b *Block) AddTx(tx *transactions.Transaction) {
b.Txs = append(b.Txs, tx)
Expand Down
11 changes: 11 additions & 0 deletions pkg/core/data/block/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Header struct {
PrevBlockHash []byte `json:"prev-hash"` // Hash of previous block (32 bytes)
Seed []byte `json:"seed"` // Marshaled BLS signature or hash of the previous block seed (32 bytes)
GeneratorBlsPubkey []byte `json:"generator"` // Generator BLS Public Key (96 bytes)
TxRoot []byte `json:"tx-root"` // Root hash of the merkle tree containing all txes (32 bytes)
StateHash []byte `json:"state-hash"` // Root hash of the Rusk Contract Storage state

Hash []byte `json:"hash"` // Hash of all previous fields
Expand Down Expand Up @@ -72,6 +73,8 @@ func (b *Header) Copy() *Header {
copy(h.Seed, b.Seed)
h.GeneratorBlsPubkey = make([]byte, len(b.GeneratorBlsPubkey))
copy(h.GeneratorBlsPubkey, b.GeneratorBlsPubkey)
h.TxRoot = make([]byte, len(b.TxRoot))
copy(h.TxRoot, b.TxRoot)
h.Hash = make([]byte, len(b.Hash))
copy(h.Hash, b.Hash)
h.StateHash = make([]byte, len(b.StateHash))
Expand Down Expand Up @@ -117,6 +120,10 @@ func (b *Header) Equals(other *Header) bool {
return false
}

if !bytes.Equal(b.TxRoot, other.TxRoot) {
return false
}

if !bytes.Equal(b.GeneratorBlsPubkey, other.GeneratorBlsPubkey) {
return false
}
Expand Down Expand Up @@ -169,6 +176,10 @@ func marshalHashable(b *bytes.Buffer, h *Header) error {
return err
}

if err := binary.Write(b, binary.BigEndian, h.TxRoot); err != nil {
return err
}

if err := binary.Write(b, binary.LittleEndian, h.GasLimit); err != nil {
return err
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/core/mempool/mempool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func TestRemoveAccepted(t *testing.T) {
m, bus, rb, _ := startMempoolTest(ctx)

// Create a random block
b := helper.RandomBlock(200, 0)
b := helper.RandomBlock(200, 1)
b.Txs = make([]transactions.ContractCall, 0)

// generate 3*4 random txs
Expand All @@ -193,6 +193,8 @@ func TestRemoveAccepted(t *testing.T) {
}
}

root, _ := b.CalculateTxRoot()
b.Header.TxRoot = root
blockMsg := message.New(topics.AcceptedBlock, *b)
errList := bus.Publish(topics.AcceptedBlock, blockMsg)
assert.Empty(errList)
Expand Down
20 changes: 20 additions & 0 deletions pkg/core/tests/helper/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,27 @@ func RandomBlock(height uint64, txBatchCount uint16) *block.Block {
Txs: transactions.RandContractCalls(int(txBatchCount), 0, true),
}

txRoot, err := b.CalculateTxRoot()
if err != nil {
panic(err)
}

b.Header.TxRoot = txRoot

hash, err := b.CalculateHash()
if err != nil {
panic(err)
}

b.Header.Hash = hash

root, xerr := b.CalculateTxRoot()
if xerr != nil {
panic(xerr)
}

b.Header.TxRoot = root

return b
}

Expand All @@ -57,6 +71,11 @@ func TwoLinkedBlocks(t *testing.T) (*block.Block, *block.Block) {
blk1.Header.Height = blk0.Header.Height + 1
blk1.Header.Timestamp = blk0.Header.Timestamp + 100

root, err := blk1.CalculateTxRoot()
assert.Nil(t, err)

blk1.Header.TxRoot = root

hash, err = blk1.CalculateHash()
assert.Nil(t, err)

Expand All @@ -80,6 +99,7 @@ func RandomHeader(height uint64) *block.Header {
PrevBlockHash: transactions.Rand32Bytes(),
Seed: RandomBLSSignature(),
GeneratorBlsPubkey: key.NewRandKeys().BLSPubKey,
TxRoot: transactions.Rand32Bytes(),
StateHash: make([]byte, 32),

Certificate: RandomCertificate(),
Expand Down
10 changes: 10 additions & 0 deletions pkg/core/verifiers/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ func CheckBlockHeader(prevBlock block.Block, blk block.Block) error {
return errors.New("invalid state hash")
}

// Merkle tree check -- Check is here as the root is not calculated on decode
root, err := blk.CalculateTxRoot()
if err != nil {
return errors.New("could not calculate the merkle tree root for this header")
}

if !bytes.Equal(root, blk.Header.TxRoot) {
return errors.New("merkle root mismatch")
}

return nil
}

Expand Down
5 changes: 5 additions & 0 deletions pkg/core/verifiers/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ func twoLinkedBlocks(t *testing.T, change int64) (*block.Block, *block.Block) {
blk1.Header.Height = blk0.Header.Height + 1
blk1.Header.Timestamp = blk0.Header.Timestamp + change

root, err := blk1.CalculateTxRoot()
assert.Nil(t, err)

blk1.Header.TxRoot = root

hash, err = blk1.CalculateHash()
assert.Nil(t, err)

Expand Down
2 changes: 2 additions & 0 deletions pkg/gql/query/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type (
PrevBlockHash []byte `json:"prev-hash"` // Hash of previous block (32 bytes)
Seed []byte `json:"seed"` // Marshaled BLS signature or hash of the previous block seed (32 bytes)
GeneratorBlsPubkey []byte `json:"generator"` // Generator's BLS public key (96 bytes)
TxRoot []byte `json:"tx-root"` // Root hash of the merkle tree containing all txes (32 bytes)
StateHash []byte `json:"state-hash"` // Root hash of the Rusk State

*block.Certificate `json:"certificate"` // Block certificate
Expand All @@ -62,6 +63,7 @@ func newQueryBlock(b *block.Block) queryBlock {
qb.Header.PrevBlockHash = b.Header.PrevBlockHash
qb.Header.Seed = b.Header.Seed
qb.Header.GeneratorBlsPubkey = b.Header.GeneratorBlsPubkey
qb.Header.TxRoot = b.Header.TxRoot
qb.Header.Certificate = b.Header.Certificate
qb.Header.Hash = b.Header.Hash
qb.Header.StateHash = b.Header.StateHash
Expand Down
15 changes: 15 additions & 0 deletions pkg/gql/query/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ func initializeDB(db database.DB) error {

b1.Header.Timestamp = 10

b1.Header.TxRoot, err = b1.CalculateTxRoot()
if err != nil {
return err
}

b1.Header.Hash, err = b1.CalculateHash()
if err != nil {
return err
Expand All @@ -108,6 +113,11 @@ func initializeDB(db database.DB) error {
b2.Txs = append(b2.Txs, bid2)
b2.Header.Timestamp = 20

b2.Header.TxRoot, err = b2.CalculateTxRoot()
if err != nil {
return err
}

b2.Header.Hash, err = b2.CalculateHash()
if err != nil {
return err
Expand All @@ -122,6 +132,11 @@ func initializeDB(db database.DB) error {
b3.Txs = append(b3.Txs, bid3)
b3.Header.Timestamp = 30

b3.Header.TxRoot, err = b3.CalculateTxRoot()
if err != nil {
return err
}

b3.Header.Hash, err = b3.CalculateHash()
if err != nil {
return err
Expand Down
3 changes: 3 additions & 0 deletions pkg/gql/query/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ var Header = graphql.NewObject(
"generatorblspubkey": &graphql.Field{
Type: Hex,
},
"txroot": &graphql.Field{
Type: Hex,
},
"timestamp": &graphql.Field{
Type: UnixTimestamp,
},
Expand Down
9 changes: 9 additions & 0 deletions pkg/p2p/wire/message/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ func MarshalHashable(r *bytes.Buffer, h *block.Header) error {
return err
}

if err := encoding.Write256(r, h.TxRoot); err != nil {
return err
}

if err := encoding.WriteUint64LE(r, h.GasLimit); err != nil {
return err
}
Expand Down Expand Up @@ -174,6 +178,11 @@ func UnmarshalHeader(r *bytes.Buffer, h *block.Header) error {
return err
}

h.TxRoot = make([]byte, 32)
if err := encoding.Read256(r, h.TxRoot); err != nil {
return err
}

if err := encoding.ReadUint64LE(r, &h.GasLimit); err != nil {
return err
}
Expand Down

0 comments on commit 12e737e

Please sign in to comment.