diff --git a/.pending/bugfixes/sdk/1351-https-github-co b/.pending/bugfixes/sdk/1351-https-github-co new file mode 100644 index 000000000000..8c346e5633ae --- /dev/null +++ b/.pending/bugfixes/sdk/1351-https-github-co @@ -0,0 +1 @@ +[\#1351](https://github.com/cosmos/cosmos-sdk/issues/1351) Stable AppHash allows no_empty_blocks \ No newline at end of file diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index c4a4679e97ba..4a384ad218d1 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -477,7 +477,7 @@ type storeCore struct { func (si storeInfo) Hash() []byte { // Doesn't write Name, since merkle.SimpleHashFromMap() will // include them via the keys. - bz, _ := cdc.MarshalBinaryLengthPrefixed(si.Core) + bz := si.Core.CommitID.Hash hasher := tmhash.New() _, err := hasher.Write(bz) diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 9c67a47424d1..df2714c6cfe0 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -77,6 +77,33 @@ func TestCacheMultiStoreWithVersion(t *testing.T) { }) } +func TestHashStableWithEmptyCommit(t *testing.T) { + var db dbm.DB = dbm.NewMemDB() + if useDebugDB { + db = dbm.NewDebugDB("CMS", db) + } + ms := newMultiStoreWithMounts(db) + err := ms.LoadLatestVersion() + require.Nil(t, err) + + commitID := types.CommitID{} + checkStore(t, ms, commitID, commitID) + + k, v := []byte("wind"), []byte("blows") + + store1 := ms.getStoreByName("store1").(types.KVStore) + store1.Set(k, v) + + cID := ms.Commit() + require.Equal(t, int64(1), cID.Version) + hash := cID.Hash + + // make an empty commit, it should update version, but not affect hash + cID = ms.Commit() + require.Equal(t, int64(2), cID.Version) + require.Equal(t, hash, cID.Hash) +} + func TestMultistoreCommitLoad(t *testing.T) { var db dbm.DB = dbm.NewMemDB() if useDebugDB { diff --git a/types/abci.go b/types/abci.go index 0646d21e3223..8f71362eda6d 100644 --- a/types/abci.go +++ b/types/abci.go @@ -2,14 +2,20 @@ package types import abci "github.com/tendermint/tendermint/abci/types" -// initialize application state at genesis +// InitChainer initializes application state at genesis type InitChainer func(ctx Context, req abci.RequestInitChain) abci.ResponseInitChain -// run code before the transactions in a block +// BeginBlocker runs code before the transactions in a block +// +// Note: applications which set create_empty_blocks=false will not have regular block timing and should use +// e.g. BFT timestamps rather than block height for any periodic BeginBlock logic type BeginBlocker func(ctx Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock -// run code after the transactions in a block and return updates to the validator set +// EndBlocker runs code after the transactions in a block and return updates to the validator set +// +// Note: applications which set create_empty_blocks=false will not have regular block timing and should use +// e.g. BFT timestamps rather than block height for any periodic EndBlock logic type EndBlocker func(ctx Context, req abci.RequestEndBlock) abci.ResponseEndBlock -// respond to p2p filtering queries from Tendermint +// PeerFilter responds to p2p filtering queries from Tendermint type PeerFilter func(info string) abci.ResponseQuery