From 58c5df729b81f7a761b273876c3a1cb06f7ae6ff Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 22 Dec 2017 16:43:45 +0100 Subject: [PATCH] Add ResultHash to header --- lite/dynamic_test.go | 6 +++--- lite/files/commit_test.go | 2 +- lite/files/provider_test.go | 2 +- lite/helpers.go | 11 ++++++----- lite/inquirer_test.go | 9 ++++++--- lite/performance_test.go | 5 +++-- lite/provider_test.go | 4 ++-- lite/static_test.go | 2 +- state/execution.go | 4 ++++ state/execution_test.go | 6 ++++++ state/state.go | 8 ++++++-- types/block.go | 6 +++++- 12 files changed, 44 insertions(+), 21 deletions(-) diff --git a/lite/dynamic_test.go b/lite/dynamic_test.go index acbd1e65..c45371ac 100644 --- a/lite/dynamic_test.go +++ b/lite/dynamic_test.go @@ -46,7 +46,7 @@ func TestDynamicCert(t *testing.T) { for _, tc := range cases { check := tc.keys.GenCommit(chainID, tc.height, nil, tc.vals, - []byte("bar"), []byte("params"), tc.first, tc.last) + []byte("bar"), []byte("params"), []byte("results"), tc.first, tc.last) err := cert.Certify(check) if tc.proper { assert.Nil(err, "%+v", err) @@ -71,7 +71,7 @@ func TestDynamicUpdate(t *testing.T) { // one valid block to give us a sense of time h := int64(100) - good := keys.GenCommit(chainID, h, nil, vals, []byte("foo"), []byte("params"), 0, len(keys)) + good := keys.GenCommit(chainID, h, nil, vals, []byte("foo"), []byte("params"), []byte("results"), 0, len(keys)) err := cert.Certify(good) require.Nil(err, "%+v", err) @@ -109,7 +109,7 @@ func TestDynamicUpdate(t *testing.T) { for _, tc := range cases { fc := tc.keys.GenFullCommit(chainID, tc.height, nil, tc.vals, - []byte("bar"), []byte("params"), tc.first, tc.last) + []byte("bar"), []byte("params"), []byte("results"), tc.first, tc.last) err := cert.Update(fc) if tc.proper { assert.Nil(err, "%d: %+v", tc.height, err) diff --git a/lite/files/commit_test.go b/lite/files/commit_test.go index f6cb2a73..e0235ba2 100644 --- a/lite/files/commit_test.go +++ b/lite/files/commit_test.go @@ -29,7 +29,7 @@ func TestSerializeFullCommits(t *testing.T) { // build a fc keys := lite.GenValKeys(5) vals := keys.ToValidators(10, 0) - fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, 5) + fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5) require.Equal(h, fc.Height()) require.Equal(vals.Hash(), fc.ValidatorsHash()) diff --git a/lite/files/provider_test.go b/lite/files/provider_test.go index e50d3461..5deebb1a 100644 --- a/lite/files/provider_test.go +++ b/lite/files/provider_test.go @@ -46,7 +46,7 @@ func TestFileProvider(t *testing.T) { // (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ... vals := keys.ToValidators(10, int64(count/2)) h := int64(20 + 10*i) - check := keys.GenCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, 5) + check := keys.GenCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5) seeds[i] = lite.NewFullCommit(check, vals) } diff --git a/lite/helpers.go b/lite/helpers.go index 394cd666..01ed4a84 100644 --- a/lite/helpers.go +++ b/lite/helpers.go @@ -110,7 +110,7 @@ func makeVote(header *types.Header, vals *types.ValidatorSet, key crypto.PrivKey // Silences warning that vals can also be merkle.Hashable // nolint: interfacer func genHeader(chainID string, height int64, txs types.Txs, - vals *types.ValidatorSet, appHash, consHash []byte) *types.Header { + vals *types.ValidatorSet, appHash, consHash, resHash []byte) *types.Header { return &types.Header{ ChainID: chainID, @@ -124,14 +124,15 @@ func genHeader(chainID string, height int64, txs types.Txs, DataHash: txs.Hash(), AppHash: appHash, ConsensusHash: consHash, + ResultsHash: resHash, } } // GenCommit calls genHeader and signHeader and combines them into a Commit. func (v ValKeys) GenCommit(chainID string, height int64, txs types.Txs, - vals *types.ValidatorSet, appHash, consHash []byte, first, last int) Commit { + vals *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) Commit { - header := genHeader(chainID, height, txs, vals, appHash, consHash) + header := genHeader(chainID, height, txs, vals, appHash, consHash, resHash) check := Commit{ Header: header, Commit: v.signHeader(header, first, last), @@ -141,9 +142,9 @@ func (v ValKeys) GenCommit(chainID string, height int64, txs types.Txs, // GenFullCommit calls genHeader and signHeader and combines them into a Commit. func (v ValKeys) GenFullCommit(chainID string, height int64, txs types.Txs, - vals *types.ValidatorSet, appHash, consHash []byte, first, last int) FullCommit { + vals *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) FullCommit { - header := genHeader(chainID, height, txs, vals, appHash, consHash) + header := genHeader(chainID, height, txs, vals, appHash, consHash, resHash) commit := Commit{ Header: header, Commit: v.signHeader(header, first, last), diff --git a/lite/inquirer_test.go b/lite/inquirer_test.go index eb45eb3c..ce431754 100644 --- a/lite/inquirer_test.go +++ b/lite/inquirer_test.go @@ -23,6 +23,7 @@ func TestInquirerValidPath(t *testing.T) { // construct a bunch of commits, each with one more height than the last chainID := "inquiry-test" consHash := []byte("params") + resHash := []byte("results") count := 50 commits := make([]lite.FullCommit, count) for i := 0; i < count; i++ { @@ -31,7 +32,7 @@ func TestInquirerValidPath(t *testing.T) { vals := keys.ToValidators(vote, 0) h := int64(20 + 10*i) appHash := []byte(fmt.Sprintf("h=%d", h)) - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, 0, len(keys)) + commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0, len(keys)) } // initialize a certifier with the initial state @@ -79,7 +80,8 @@ func TestInquirerMinimalPath(t *testing.T) { vals := keys.ToValidators(vote, 0) h := int64(5 + 10*i) appHash := []byte(fmt.Sprintf("h=%d", h)) - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, 0, len(keys)) + resHash := []byte(fmt.Sprintf("res=%d", h)) + commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0, len(keys)) } // initialize a certifier with the initial state @@ -127,7 +129,8 @@ func TestInquirerVerifyHistorical(t *testing.T) { vals := keys.ToValidators(vote, 0) h := int64(20 + 10*i) appHash := []byte(fmt.Sprintf("h=%d", h)) - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, 0, len(keys)) + resHash := []byte(fmt.Sprintf("res=%d", h)) + commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0, len(keys)) } // initialize a certifier with the initial state diff --git a/lite/performance_test.go b/lite/performance_test.go index af6eacc3..835e52f9 100644 --- a/lite/performance_test.go +++ b/lite/performance_test.go @@ -33,7 +33,8 @@ func benchmarkGenCommit(b *testing.B, keys lite.ValKeys) { for i := 0; i < b.N; i++ { h := int64(1 + i) appHash := []byte(fmt.Sprintf("h=%d", h)) - keys.GenCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, len(keys)) + resHash := []byte(fmt.Sprintf("res=%d", h)) + keys.GenCommit(chainID, h, nil, vals, appHash, []byte("params"), resHash, 0, len(keys)) } } @@ -105,7 +106,7 @@ func benchmarkCertifyCommit(b *testing.B, keys lite.ValKeys) { chainID := "bench-certify" vals := keys.ToValidators(20, 10) cert := lite.NewStatic(chainID, vals) - check := keys.GenCommit(chainID, 123, nil, vals, []byte("foo"), []byte("params"), 0, len(keys)) + check := keys.GenCommit(chainID, 123, nil, vals, []byte("foo"), []byte("params"), []byte("res"), 0, len(keys)) for i := 0; i < b.N; i++ { err := cert.Certify(check) if err != nil { diff --git a/lite/provider_test.go b/lite/provider_test.go index 09ad0aa8..b2529b55 100644 --- a/lite/provider_test.go +++ b/lite/provider_test.go @@ -58,7 +58,7 @@ func checkProvider(t *testing.T, p lite.Provider, chainID, app string) { // (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ... vals := keys.ToValidators(10, int64(count/2)) h := int64(20 + 10*i) - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, 5) + commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5) } // check provider is empty @@ -129,7 +129,7 @@ func TestCacheGetsBestHeight(t *testing.T) { for i := 0; i < count; i++ { vals := keys.ToValidators(10, int64(count/2)) h := int64(10 * (i + 1)) - fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, 5) + fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5) err := p2.StoreCommit(fc) require.NoError(err) } diff --git a/lite/static_test.go b/lite/static_test.go index d0a1e685..3e4d5927 100644 --- a/lite/static_test.go +++ b/lite/static_test.go @@ -44,7 +44,7 @@ func TestStaticCert(t *testing.T) { for _, tc := range cases { check := tc.keys.GenCommit(chainID, tc.height, nil, tc.vals, - []byte("foo"), []byte("params"), tc.first, tc.last) + []byte("foo"), []byte("params"), []byte("results"), tc.first, tc.last) err := cert.Certify(check) if tc.proper { assert.Nil(err, "%+v", err) diff --git a/state/execution.go b/state/execution.go index d626ee0f..786cc36d 100644 --- a/state/execution.go +++ b/state/execution.go @@ -241,6 +241,7 @@ func (s *State) MakeBlock(height int64, txs []types.Tx, commit *types.Commit) (* block.ValidatorsHash = s.Validators.Hash() block.AppHash = s.AppHash block.ConsensusHash = s.LastConsensusParams.Hash() + block.ResultsHash = s.LastResultHash return block, block.MakePartSet(s.ConsensusParams.BlockGossip.BlockPartSizeBytes) } @@ -279,6 +280,9 @@ func (s *State) validateBlock(b *types.Block) error { if !bytes.Equal(b.ConsensusHash, s.LastConsensusParams.Hash()) { return fmt.Errorf("Wrong Block.Header.ConsensusHash. Expected %X, got %v", s.LastConsensusParams.Hash(), b.ConsensusHash) } + if !bytes.Equal(b.ResultsHash, s.LastResultHash) { + return fmt.Errorf("Wrong Block.Header.ResultsHash. Expected %X, got %v", s.LastResultHash, b.ResultsHash) + } // Validate block LastCommit. if b.Height == 1 { diff --git a/state/execution_test.go b/state/execution_test.go index a639d39a..5cddfc7f 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -67,6 +67,12 @@ func TestValidateBlock(t *testing.T) { block.ConsensusHash = []byte("wrong consensus hash") err = state.ValidateBlock(block) require.Error(t, err) + + // wrong results hash fails + block = makeBlock(state, 1) + block.ResultsHash = []byte("wrong results hash") + err = state.ValidateBlock(block) + require.Error(t, err) } func TestApplyBlock(t *testing.T) { diff --git a/state/state.go b/state/state.go index 316a3161..9ef734fc 100644 --- a/state/state.go +++ b/state/state.go @@ -79,8 +79,9 @@ type State struct { LastHeightConsensusParamsChanged int64 // Store LastABCIResults along with hash - LastResults ABCIResults // TODO: remove?? - LastResultHash []byte + LastResults ABCIResults // TODO: remove?? + LastResultHash []byte // this is the one for the next block to propose + LastLastResultHash []byte // this verifies the last block? // The latest AppHash we've received from calling abci.Commit() AppHash []byte @@ -156,6 +157,9 @@ func (s *State) Copy() *State { AppHash: s.AppHash, + LastResults: s.LastResults, + LastResultHash: s.LastResultHash, + logger: s.logger, } } diff --git a/types/block.go b/types/block.go index 7a1ed04e..ee0f54ea 100644 --- a/types/block.go +++ b/types/block.go @@ -153,6 +153,7 @@ type Header struct { ValidatorsHash data.Bytes `json:"validators_hash"` // validators for the current block ConsensusHash data.Bytes `json:"consensus_hash"` // consensus params for current block AppHash data.Bytes `json:"app_hash"` // state after txs from the previous block + ResultsHash data.Bytes `json:"results_hash"` // root hash of all results from the txs from the previous block } // Hash returns the hash of the header. @@ -173,6 +174,7 @@ func (h *Header) Hash() data.Bytes { "Validators": h.ValidatorsHash, "App": h.AppHash, "Consensus": h.ConsensusHash, + "Results": h.ResultsHash, }) } @@ -192,7 +194,8 @@ func (h *Header) StringIndented(indent string) string { %s Data: %v %s Validators: %v %s App: %v -%s Conensus: %v +%s Conensus: %v +%s Results: %v %s}#%v`, indent, h.ChainID, indent, h.Height, @@ -205,6 +208,7 @@ func (h *Header) StringIndented(indent string) string { indent, h.ValidatorsHash, indent, h.AppHash, indent, h.ConsensusHash, + indent, h.ResultsHash, indent, h.Hash()) }