mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
Add ABCIResults with Hash and Proof to State
State maintains LastResultsHash Verify that we can produce unique hashes for each result, and provide valid proofs from the root hash.
This commit is contained in:
parent
d844799b3b
commit
f870a49f42
@ -8,10 +8,13 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
"github.com/tendermint/go-wire/data"
|
||||||
|
"golang.org/x/crypto/ripemd160"
|
||||||
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
"github.com/tendermint/tmlibs/merkle"
|
||||||
|
|
||||||
wire "github.com/tendermint/go-wire"
|
wire "github.com/tendermint/go-wire"
|
||||||
|
|
||||||
@ -71,6 +74,10 @@ type State struct {
|
|||||||
LastConsensusParams types.ConsensusParams
|
LastConsensusParams types.ConsensusParams
|
||||||
LastHeightConsensusParamsChanged int64
|
LastHeightConsensusParamsChanged int64
|
||||||
|
|
||||||
|
// Store LastABCIResults along with hash
|
||||||
|
LastResults ABCIResults
|
||||||
|
LastResultHash []byte
|
||||||
|
|
||||||
// The latest AppHash we've received from calling abci.Commit()
|
// The latest AppHash we've received from calling abci.Commit()
|
||||||
AppHash []byte
|
AppHash []byte
|
||||||
|
|
||||||
@ -346,14 +353,16 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ
|
|||||||
types.BlockID{header.Hash(), blockPartsHeader},
|
types.BlockID{header.Hash(), blockPartsHeader},
|
||||||
header.Time,
|
header.Time,
|
||||||
nextValSet,
|
nextValSet,
|
||||||
nextParams)
|
nextParams,
|
||||||
|
NewResults(abciResponses.DeliverTx))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) setBlockAndValidators(height int64,
|
func (s *State) setBlockAndValidators(height int64,
|
||||||
newTxs int64, blockID types.BlockID, blockTime time.Time,
|
newTxs int64, blockID types.BlockID, blockTime time.Time,
|
||||||
valSet *types.ValidatorSet,
|
valSet *types.ValidatorSet,
|
||||||
params types.ConsensusParams) {
|
params types.ConsensusParams,
|
||||||
|
results ABCIResults) {
|
||||||
|
|
||||||
s.LastBlockHeight = height
|
s.LastBlockHeight = height
|
||||||
s.LastBlockTotalTx += newTxs
|
s.LastBlockTotalTx += newTxs
|
||||||
@ -365,6 +374,9 @@ func (s *State) setBlockAndValidators(height int64,
|
|||||||
|
|
||||||
s.LastConsensusParams = s.ConsensusParams
|
s.LastConsensusParams = s.ConsensusParams
|
||||||
s.ConsensusParams = params
|
s.ConsensusParams = params
|
||||||
|
|
||||||
|
s.LastResults = results
|
||||||
|
s.LastResultHash = results.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValidators returns the last and current validator sets.
|
// GetValidators returns the last and current validator sets.
|
||||||
@ -401,6 +413,59 @@ func (a *ABCIResponses) Bytes() []byte {
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ABCIResult is just the essential info to prove
|
||||||
|
// success/failure of a DeliverTx
|
||||||
|
type ABCIResult struct {
|
||||||
|
Code uint32 `json:"code"`
|
||||||
|
Data data.Bytes `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash creates a canonical json hash of the ABCIResult
|
||||||
|
func (a ABCIResult) Hash() []byte {
|
||||||
|
// stupid canonical json output, easy to check in any language
|
||||||
|
bs := fmt.Sprintf(`{"code":%d,"data":"%s"}`, a.Code, a.Data)
|
||||||
|
var hasher = ripemd160.New()
|
||||||
|
hasher.Write([]byte(bs))
|
||||||
|
return hasher.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABCIResults wraps the deliver tx results to return a proof
|
||||||
|
type ABCIResults []ABCIResult
|
||||||
|
|
||||||
|
// NewResults creates ABCIResults from ResponseDeliverTx
|
||||||
|
func NewResults(del []*abci.ResponseDeliverTx) ABCIResults {
|
||||||
|
res := make(ABCIResults, len(del))
|
||||||
|
for i, d := range del {
|
||||||
|
res[i] = ABCIResult{
|
||||||
|
Code: d.Code,
|
||||||
|
Data: d.Data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash returns a merkle hash of all results
|
||||||
|
func (a ABCIResults) Hash() []byte {
|
||||||
|
return merkle.SimpleHashFromHashables(a.toHashables())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProveResult returns a merkle proof of one result from the set
|
||||||
|
func (a ABCIResults) ProveResult(i int) merkle.SimpleProof {
|
||||||
|
_, proofs := merkle.SimpleProofsFromHashables(a.toHashables())
|
||||||
|
return *proofs[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a ABCIResults) toHashables() []merkle.Hashable {
|
||||||
|
l := len(a)
|
||||||
|
hashables := make([]merkle.Hashable, l)
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
hashables[i] = a[i]
|
||||||
|
}
|
||||||
|
return hashables
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// ValidatorsInfo represents the latest validator set, or the last height it changed
|
// ValidatorsInfo represents the latest validator set, or the last height it changed
|
||||||
type ValidatorsInfo struct {
|
type ValidatorsInfo struct {
|
||||||
ValidatorSet *types.ValidatorSet
|
ValidatorSet *types.ValidatorSet
|
||||||
|
@ -279,6 +279,40 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestABCIResults(t *testing.T) {
|
||||||
|
a := ABCIResult{Code: 0, Data: nil}
|
||||||
|
b := ABCIResult{Code: 0, Data: []byte{}}
|
||||||
|
c := ABCIResult{Code: 0, Data: []byte("one")}
|
||||||
|
d := ABCIResult{Code: 14, Data: nil}
|
||||||
|
e := ABCIResult{Code: 14, Data: []byte("foo")}
|
||||||
|
f := ABCIResult{Code: 14, Data: []byte("bar")}
|
||||||
|
|
||||||
|
// nil and []byte{} should produce same hash
|
||||||
|
assert.Equal(t, a.Hash(), b.Hash())
|
||||||
|
|
||||||
|
// a and b should be the same, don't go in results
|
||||||
|
results := ABCIResults{a, c, d, e, f}
|
||||||
|
|
||||||
|
// make sure each result hashes properly
|
||||||
|
var last []byte
|
||||||
|
for i, res := range results {
|
||||||
|
h := res.Hash()
|
||||||
|
assert.NotEqual(t, last, h, "%d", i)
|
||||||
|
last = h
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure that we can get a root hash from results
|
||||||
|
// and verify proofs
|
||||||
|
root := results.Hash()
|
||||||
|
assert.NotEmpty(t, root)
|
||||||
|
|
||||||
|
for i, res := range results {
|
||||||
|
proof := results.ProveResult(i)
|
||||||
|
valid := proof.Verify(i, len(results), res.Hash(), root)
|
||||||
|
assert.True(t, valid, "%d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func makeParams(blockBytes, blockTx, blockGas, txBytes,
|
func makeParams(blockBytes, blockTx, blockGas, txBytes,
|
||||||
txGas, partSize int) types.ConsensusParams {
|
txGas, partSize int) types.ConsensusParams {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user