diff --git a/chain/block.go b/chain/block.go index 444175f105..bdbce99364 100644 --- a/chain/block.go +++ b/chain/block.go @@ -40,7 +40,8 @@ type StatefulBlock struct { Tmstmp int64 `json:"timestamp"` Hght uint64 `json:"height"` - Txs []*Transaction `json:"txs"` + Txs []*Transaction `json:"txs"` + TxsRoot []byte `json:"txsRoot"` // StateRoot is the root of the post-execution state // of [Prnt]. diff --git a/chain/builder.go b/chain/builder.go index 689d387048..2ae2e6701c 100644 --- a/chain/builder.go +++ b/chain/builder.go @@ -4,6 +4,7 @@ package chain import ( + "bytes" "context" "encoding/binary" "errors" @@ -17,9 +18,12 @@ import ( "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/utils/set" + "github.com/cbergoon/merkletree" "go.opentelemetry.io/otel/attribute" "go.uber.org/zap" + "crypto/sha256" + "github.com/ava-labs/hypersdk/executor" "github.com/ava-labs/hypersdk/keys" "github.com/ava-labs/hypersdk/tstate" @@ -34,6 +38,29 @@ const ( stopBuildingThreshold = 2_048 // units ) +type TestContent struct { + x []byte +} + +// CalculateHash hashes the values of a TestContent +func (t TestContent) CalculateHash() ([]byte, error) { + h := sha256.New() + if _, err := h.Write([]byte(t.x)); err != nil { + return nil, err + } + + return h.Sum(nil), nil +} + +// Equals tests for equality of two Contents +func (t TestContent) Equals(other merkletree.Content) (bool, error) { + otherTC, ok := other.(TestContent) + if !ok { + return false, errors.New("value is not of type TestContent") + } + return bytes.Equal(t.x, otherTC.x), nil +} + var errBlockFull = errors.New("block full") func HandlePreExecute(log logging.Logger, err error) bool { @@ -128,6 +155,8 @@ func BuildBlock( txsAttempted = 0 results = []*Result{} + txSuccessList []merkletree.Content + vdrState = vm.ValidatorState() sm = vm.StateManager() @@ -136,6 +165,9 @@ func BuildBlock( prepareStreamLock sync.Mutex ) + // prevent empty list + txSuccessList = append(txSuccessList, TestContent{x: make([]byte, 32)}) + // Batch fetch items from mempool to unblock incoming RPC/Gossip traffic mempool.StartStreaming(ctx) b.Txs = []*Transaction{} @@ -381,6 +413,7 @@ func BuildBlock( tsv.Commit() b.Txs = append(b.Txs, tx) results = append(results, result) + txSuccessList = append(txSuccessList, TestContent{x: tx.Bytes()}) if tx.WarpMessage != nil { if warpErr == nil { // Add a bit if the warp message was verified @@ -415,6 +448,13 @@ func BuildBlock( } } + trie, err := merkletree.NewTree(txSuccessList) + if err != nil { + b.vm.Logger().Warn("unable to build trie", zap.Error(err)) + return nil, err + } + b.TxsRoot = trie.MerkleRoot() + // Wait for stream preparation to finish to make // sure all transactions are returned to the mempool. go func() { diff --git a/examples/morpheusvm/go.mod b/examples/morpheusvm/go.mod index e7a3c8fd2c..ea2cd2462d 100644 --- a/examples/morpheusvm/go.mod +++ b/examples/morpheusvm/go.mod @@ -24,6 +24,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect + github.com/cbergoon/merkletree v0.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chzyer/readline v1.5.1 // indirect diff --git a/examples/morpheusvm/go.sum b/examples/morpheusvm/go.sum index 09e3deb50d..6e28f1da1c 100644 --- a/examples/morpheusvm/go.sum +++ b/examples/morpheusvm/go.sum @@ -95,6 +95,8 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cbergoon/merkletree v0.2.0 h1:Bttqr3OuoiZEo4ed1L7fTasHka9II+BF9fhBfbNEEoQ= +github.com/cbergoon/merkletree v0.2.0/go.mod h1:5c15eckUgiucMGDOCanvalj/yJnD+KAZj1qyJtRW5aM= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= diff --git a/go.mod b/go.mod index 7c92f4716f..3c2c246bea 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect + github.com/cbergoon/merkletree v0.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chzyer/readline v1.5.1 // indirect diff --git a/go.sum b/go.sum index 4bdd31a1e3..306c4192e4 100644 --- a/go.sum +++ b/go.sum @@ -97,6 +97,8 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/bytecodealliance/wasmtime-go/v14 v14.0.0 h1:ur7S3P+PAeJmgllhSrKnGQOAmmtUbLQxb/nw2NZiaEM= github.com/bytecodealliance/wasmtime-go/v14 v14.0.0/go.mod h1:tqOVEUjnXY6aGpSfM9qdVRR6G//Yc513fFYUdzZb/DY= +github.com/cbergoon/merkletree v0.2.0 h1:Bttqr3OuoiZEo4ed1L7fTasHka9II+BF9fhBfbNEEoQ= +github.com/cbergoon/merkletree v0.2.0/go.mod h1:5c15eckUgiucMGDOCanvalj/yJnD+KAZj1qyJtRW5aM= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=