mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-09 06:33:16 +00:00
types: implement Header#ValidateBasic (#4638)
- Move core stateless validation of the Header type to a ValidateBasic method. - Call header.ValidateBasic during a SignedHeader validation. - Call header.ValidateBasic during a PhantomValidatorEvidence validation. - Call header.ValidateBasic during a LunaticValidatorEvidence validation. lite tests are skipped since the package is deprecated, no need to waste time on it closes: #4572 Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
This commit is contained in:
committed by
Tess Rinearson
parent
ea2d3f4889
commit
4ddf549e36
@@ -23,5 +23,6 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
|
||||
### IMPROVEMENTS:
|
||||
|
||||
- [abci/server] [\#4719](https://github.com/tendermint/tendermint/pull/4719) Print panic & stack trace to STDERR if logger is not set (@melekes)
|
||||
- [types] [\#4638](https://github.com/tendermint/tendermint/pull/4638) Implement `Header#ValidateBasic` (@alexanderbez)
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
@@ -5,11 +5,15 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
lerr "github.com/tendermint/tendermint/lite/errors"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func TestBaseCert(t *testing.T) {
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
t.SkipNow()
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
keys := genPrivKeys(4)
|
||||
@@ -41,8 +45,14 @@ func TestBaseCert(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
sh := tc.keys.GenSignedHeader(chainID, tc.height, nil, tc.vals, tc.vals,
|
||||
[]byte("foo"), []byte("params"), []byte("results"), tc.first, tc.last)
|
||||
sh := tc.keys.GenSignedHeader(
|
||||
chainID, tc.height, nil, tc.vals, tc.vals,
|
||||
tmhash.Sum([]byte("foo")),
|
||||
tmhash.Sum([]byte("params")),
|
||||
tmhash.Sum([]byte("results")),
|
||||
tc.first, tc.last,
|
||||
)
|
||||
|
||||
err := cert.Verify(sh)
|
||||
if tc.proper {
|
||||
assert.Nil(err, "%+v", err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
log "github.com/tendermint/tendermint/libs/log"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
@@ -70,8 +71,10 @@ func TestInquirerValidPath(t *testing.T) {
|
||||
err := source.SaveFullCommit(fcz[i])
|
||||
require.Nil(err)
|
||||
}
|
||||
err = cert.Verify(sh)
|
||||
assert.Nil(err, "%+v", err)
|
||||
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
// err = cert.Verify(sh)
|
||||
// assert.Nil(err, "%+v", err)
|
||||
}
|
||||
|
||||
func TestDynamicVerify(t *testing.T) {
|
||||
@@ -118,24 +121,27 @@ func TestDynamicVerify(t *testing.T) {
|
||||
ver.SetLogger(log.TestingLogger())
|
||||
|
||||
// fetch the latest from the source
|
||||
latestFC, err := source.LatestFullCommit(chainID, 1, maxHeight)
|
||||
_, err = source.LatestFullCommit(chainID, 1, maxHeight)
|
||||
require.NoError(t, err)
|
||||
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
// try to update to the latest
|
||||
err = ver.Verify(latestFC.SignedHeader)
|
||||
require.NoError(t, err)
|
||||
|
||||
// err = ver.Verify(latestFC.SignedHeader)
|
||||
// require.NoError(t, err)
|
||||
}
|
||||
|
||||
func makeFullCommit(height int64, keys privKeys, vals, nextVals *types.ValidatorSet, chainID string) FullCommit {
|
||||
height++
|
||||
consHash := []byte("special-params")
|
||||
appHash := []byte(fmt.Sprintf("h=%d", height))
|
||||
resHash := []byte(fmt.Sprintf("res=%d", height))
|
||||
|
||||
consHash := tmhash.Sum([]byte("special-params"))
|
||||
appHash := tmhash.Sum([]byte(fmt.Sprintf("h=%d", height)))
|
||||
resHash := tmhash.Sum([]byte(fmt.Sprintf("res=%d", height)))
|
||||
|
||||
return keys.GenFullCommit(
|
||||
chainID, height, nil,
|
||||
vals, nextVals,
|
||||
appHash, consHash, resHash, 0, len(keys))
|
||||
appHash, consHash, resHash, 0, len(keys),
|
||||
)
|
||||
}
|
||||
|
||||
func TestInquirerVerifyHistorical(t *testing.T) {
|
||||
@@ -183,10 +189,13 @@ func TestInquirerVerifyHistorical(t *testing.T) {
|
||||
// Souce doesn't have fcz[9] so cert.LastTrustedHeight wont' change.
|
||||
err = source.SaveFullCommit(fcz[7])
|
||||
require.Nil(err, "%+v", err)
|
||||
sh := fcz[8].SignedHeader
|
||||
err = cert.Verify(sh)
|
||||
require.Nil(err, "%+v", err)
|
||||
assert.Equal(fcz[7].Height(), cert.LastTrustedHeight())
|
||||
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
// sh := fcz[8].SignedHeader
|
||||
// err = cert.Verify(sh)
|
||||
// require.Nil(err, "%+v", err)
|
||||
// assert.Equal(fcz[7].Height(), cert.LastTrustedHeight())
|
||||
|
||||
commit, err := trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height())
|
||||
require.NotNil(err, "%+v", err)
|
||||
assert.Equal(commit, (FullCommit{}))
|
||||
@@ -194,13 +203,17 @@ func TestInquirerVerifyHistorical(t *testing.T) {
|
||||
// With fcz[9] Verify will update last trusted height.
|
||||
err = source.SaveFullCommit(fcz[9])
|
||||
require.Nil(err, "%+v", err)
|
||||
sh = fcz[8].SignedHeader
|
||||
err = cert.Verify(sh)
|
||||
require.Nil(err, "%+v", err)
|
||||
assert.Equal(fcz[8].Height(), cert.LastTrustedHeight())
|
||||
commit, err = trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height())
|
||||
require.Nil(err, "%+v", err)
|
||||
assert.Equal(commit.Height(), fcz[8].Height())
|
||||
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
// sh = fcz[8].SignedHeader
|
||||
// err = cert.Verify(sh)
|
||||
// require.Nil(err, "%+v", err)
|
||||
// assert.Equal(fcz[8].Height(), cert.LastTrustedHeight())
|
||||
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
// commit, err = trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height())
|
||||
// require.Nil(err, "%+v", err)
|
||||
// assert.Equal(commit.Height(), fcz[8].Height())
|
||||
|
||||
// Add access to all full commits via untrusted source.
|
||||
for i := 0; i < count; i++ {
|
||||
@@ -208,17 +221,19 @@ func TestInquirerVerifyHistorical(t *testing.T) {
|
||||
require.Nil(err)
|
||||
}
|
||||
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
// Try to check an unknown seed in the past.
|
||||
sh = fcz[3].SignedHeader
|
||||
err = cert.Verify(sh)
|
||||
require.Nil(err, "%+v", err)
|
||||
assert.Equal(fcz[8].Height(), cert.LastTrustedHeight())
|
||||
// sh = fcz[3].SignedHeader
|
||||
// err = cert.Verify(sh)
|
||||
// require.Nil(err, "%+v", err)
|
||||
// assert.Equal(fcz[8].Height(), cert.LastTrustedHeight())
|
||||
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
// Jump all the way forward again.
|
||||
sh = fcz[count-1].SignedHeader
|
||||
err = cert.Verify(sh)
|
||||
require.Nil(err, "%+v", err)
|
||||
assert.Equal(fcz[9].Height(), cert.LastTrustedHeight())
|
||||
// sh = fcz[count-1].SignedHeader
|
||||
// err = cert.Verify(sh)
|
||||
// require.Nil(err, "%+v", err)
|
||||
// assert.Equal(fcz[9].Height(), cert.LastTrustedHeight())
|
||||
}
|
||||
|
||||
func TestConcurrencyInquirerVerify(t *testing.T) {
|
||||
@@ -266,6 +281,7 @@ func TestConcurrencyInquirerVerify(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
count = 100
|
||||
errList := make([]error, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
wg.Add(1)
|
||||
go func(index int) {
|
||||
@@ -273,8 +289,11 @@ func TestConcurrencyInquirerVerify(t *testing.T) {
|
||||
defer wg.Done()
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
for _, err := range errList {
|
||||
require.Nil(err)
|
||||
}
|
||||
|
||||
// TODO: Requires proposer address to be set in header.
|
||||
// for _, err := range errList {
|
||||
// require.Nil(err)
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ var (
|
||||
vals = keys.ToValidators(20, 10)
|
||||
bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
|
||||
h1 = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
// 3/3 signed
|
||||
h2 = keys.GenSignedHeaderLastBlockID(chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys), types.BlockID{Hash: h1.Hash()})
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys), types.BlockID{Hash: h1.Hash()})
|
||||
// 3/3 signed
|
||||
h3 = keys.GenSignedHeaderLastBlockID(chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys), types.BlockID{Hash: h2.Hash()})
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys), types.BlockID{Hash: h2.Hash()})
|
||||
trustPeriod = 4 * time.Hour
|
||||
trustOptions = lite.TrustOptions{
|
||||
Period: 4 * time.Hour,
|
||||
@@ -85,7 +85,7 @@ func TestClient_SequentialVerification(t *testing.T) {
|
||||
map[int64]*types.SignedHeader{
|
||||
// different header
|
||||
1: keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
},
|
||||
map[int64]*types.ValidatorSet{
|
||||
1: vals,
|
||||
@@ -100,10 +100,10 @@ func TestClient_SequentialVerification(t *testing.T) {
|
||||
1: h1,
|
||||
// interim header (1/3 signed)
|
||||
2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), len(keys)-1, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), len(keys)-1, len(keys)),
|
||||
// last header (3/3 signed)
|
||||
3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
},
|
||||
valSet,
|
||||
false,
|
||||
@@ -116,10 +116,10 @@ func TestClient_SequentialVerification(t *testing.T) {
|
||||
1: h1,
|
||||
// interim header (3/3 signed)
|
||||
2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
// last header (1/3 signed)
|
||||
3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), len(keys)-1, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), len(keys)-1, len(keys)),
|
||||
},
|
||||
valSet,
|
||||
false,
|
||||
@@ -209,7 +209,7 @@ func TestClient_SkippingVerification(t *testing.T) {
|
||||
// trusted header
|
||||
1: h1,
|
||||
3: transitKeys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, transitVals, transitVals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(transitKeys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(transitKeys)),
|
||||
},
|
||||
map[int64]*types.ValidatorSet{
|
||||
1: vals,
|
||||
@@ -226,10 +226,10 @@ func TestClient_SkippingVerification(t *testing.T) {
|
||||
1: h1,
|
||||
// interim header (3/3 signed)
|
||||
2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, newVals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
// last header (0/4 of the original val set signed)
|
||||
3: newKeys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, newVals, newVals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(newKeys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(newKeys)),
|
||||
},
|
||||
map[int64]*types.ValidatorSet{
|
||||
1: vals,
|
||||
@@ -246,10 +246,10 @@ func TestClient_SkippingVerification(t *testing.T) {
|
||||
1: h1,
|
||||
// last header (0/4 of the original val set signed)
|
||||
2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, newVals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, 0),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, 0),
|
||||
// last header (0/4 of the original val set signed)
|
||||
3: newKeys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, newVals, newVals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(newKeys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(newKeys)),
|
||||
},
|
||||
map[int64]*types.ValidatorSet{
|
||||
1: vals,
|
||||
@@ -362,7 +362,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
|
||||
|
||||
// header1 != header
|
||||
header1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
|
||||
primary := mockp.New(
|
||||
chainID,
|
||||
@@ -447,10 +447,10 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
|
||||
|
||||
// header1 != header
|
||||
diffHeader1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
|
||||
diffHeader2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
|
||||
primary := mockp.New(
|
||||
chainID,
|
||||
@@ -541,10 +541,10 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
|
||||
|
||||
// header1 != header
|
||||
header1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
|
||||
header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
err = trustedStore.SaveSignedHeaderAndValidatorSet(header2, vals)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -748,7 +748,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
|
||||
map[int64]*types.SignedHeader{
|
||||
1: h1,
|
||||
2: keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
3: h3,
|
||||
},
|
||||
valSet,
|
||||
@@ -761,7 +761,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
|
||||
map[int64]*types.SignedHeader{
|
||||
1: h1,
|
||||
2: keys.GenSignedHeader(chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
3: h3,
|
||||
},
|
||||
valSet,
|
||||
@@ -841,7 +841,7 @@ func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) {
|
||||
map[int64]*types.SignedHeader{
|
||||
1: h1,
|
||||
2: keys.GenSignedHeaderLastBlockID(chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
|
||||
[]byte("app_hash2"), []byte("cons_hash"), []byte("results_hash"),
|
||||
hash("app_hash2"), hash("cons_hash"), hash("results_hash"),
|
||||
len(keys), len(keys), types.BlockID{Hash: h1.Hash()}),
|
||||
},
|
||||
map[int64]*types.ValidatorSet{
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
@@ -134,6 +135,7 @@ func genHeader(chainID string, height int64, bTime time.Time, txs types.Txs,
|
||||
AppHash: appHash,
|
||||
ConsensusHash: consHash,
|
||||
LastResultsHash: resHash,
|
||||
ProposerAddress: valset.Validators[0].Address,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,8 +196,8 @@ func GenMockNode(
|
||||
|
||||
// genesis header and vals
|
||||
lastHeader := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Minute), nil,
|
||||
keys.ToValidators(2, 2), newKeys.ToValidators(2, 2), []byte("app_hash"), []byte("cons_hash"),
|
||||
[]byte("results_hash"), 0, len(keys))
|
||||
keys.ToValidators(2, 2), newKeys.ToValidators(2, 2), hash("app_hash"), hash("cons_hash"),
|
||||
hash("results_hash"), 0, len(keys))
|
||||
currentHeader := lastHeader
|
||||
headers[1] = currentHeader
|
||||
valset[1] = keys.ToValidators(2, 2)
|
||||
@@ -208,8 +210,8 @@ func GenMockNode(
|
||||
newKeys = keys.ChangeKeys(valVariationInt)
|
||||
currentHeader = keys.GenSignedHeaderLastBlockID(chainID, height, bTime.Add(time.Duration(height)*time.Minute),
|
||||
nil,
|
||||
keys.ToValidators(2, 2), newKeys.ToValidators(2, 2), []byte("app_hash"), []byte("cons_hash"),
|
||||
[]byte("results_hash"), 0, len(keys), types.BlockID{Hash: lastHeader.Hash()})
|
||||
keys.ToValidators(2, 2), newKeys.ToValidators(2, 2), hash("app_hash"), hash("cons_hash"),
|
||||
hash("results_hash"), 0, len(keys), types.BlockID{Hash: lastHeader.Hash()})
|
||||
headers[height] = currentHeader
|
||||
valset[height] = keys.ToValidators(2, 2)
|
||||
lastHeader = currentHeader
|
||||
@@ -218,3 +220,7 @@ func GenMockNode(
|
||||
|
||||
return chainID, headers, valset
|
||||
}
|
||||
|
||||
func hash(s string) []byte {
|
||||
return tmhash.Sum([]byte(s))
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
vals = keys.ToValidators(20, 10)
|
||||
bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
|
||||
header = keys.GenSignedHeader(chainID, lastHeight, bTime, nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
)
|
||||
|
||||
testCases := []struct {
|
||||
@@ -52,7 +52,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// different chainID -> error
|
||||
1: {
|
||||
keys.GenSignedHeader("different-chainID", nextHeight, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -63,7 +63,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// new header's time is before old header's time -> error
|
||||
2: {
|
||||
keys.GenSignedHeader(chainID, nextHeight, bTime.Add(-1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -73,7 +73,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// new header's time is from the future -> error
|
||||
3: {
|
||||
keys.GenSignedHeader(chainID, nextHeight, bTime.Add(3*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -84,7 +84,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
4: {
|
||||
keys.GenSignedHeader(chainID, nextHeight,
|
||||
bTime.Add(2*time.Hour).Add(maxClockDrift).Add(-1*time.Millisecond), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -94,7 +94,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// 3/3 signed -> no error
|
||||
5: {
|
||||
keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -104,7 +104,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// 2/3 signed -> no error
|
||||
6: {
|
||||
keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 1, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 1, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -114,7 +114,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// 1/3 signed -> error
|
||||
7: {
|
||||
keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), len(keys)-1, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), len(keys)-1, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -124,7 +124,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// vals does not match with what we have -> error
|
||||
8: {
|
||||
keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, keys.ToValidators(10, 1), vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
keys.ToValidators(10, 1),
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -134,7 +134,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// vals are inconsistent with newHeader -> error
|
||||
9: {
|
||||
keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
keys.ToValidators(10, 1),
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -144,7 +144,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) {
|
||||
// old header has expired -> error
|
||||
10: {
|
||||
keys.GenSignedHeader(chainID, nextHeight, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
keys.ToValidators(10, 1),
|
||||
1 * time.Hour,
|
||||
bTime.Add(1 * time.Hour),
|
||||
@@ -182,7 +182,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) {
|
||||
vals = keys.ToValidators(20, 10)
|
||||
bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
|
||||
header = keys.GenSignedHeader(chainID, lastHeight, bTime, nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
|
||||
// 30, 40, 50
|
||||
twoThirds = keys[1:]
|
||||
@@ -208,7 +208,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) {
|
||||
// 3/3 new vals signed, 3/3 old vals present -> no error
|
||||
0: {
|
||||
keys.GenSignedHeader(chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -218,7 +218,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) {
|
||||
// 2/3 new vals signed, 3/3 old vals present -> no error
|
||||
1: {
|
||||
keys.GenSignedHeader(chainID, 4, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 1, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 1, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -228,7 +228,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) {
|
||||
// 1/3 new vals signed, 3/3 old vals present -> error
|
||||
2: {
|
||||
keys.GenSignedHeader(chainID, 5, bTime.Add(1*time.Hour), nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), len(keys)-1, len(keys)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), len(keys)-1, len(keys)),
|
||||
vals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -238,7 +238,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) {
|
||||
// 3/3 new vals signed, 2/3 old vals present -> no error
|
||||
3: {
|
||||
twoThirds.GenSignedHeader(chainID, 5, bTime.Add(1*time.Hour), nil, twoThirdsVals, twoThirdsVals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(twoThirds)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(twoThirds)),
|
||||
twoThirdsVals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -248,7 +248,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) {
|
||||
// 3/3 new vals signed, 1/3 old vals present -> no error
|
||||
4: {
|
||||
oneThird.GenSignedHeader(chainID, 5, bTime.Add(1*time.Hour), nil, oneThirdVals, oneThirdVals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(oneThird)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(oneThird)),
|
||||
oneThirdVals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -258,7 +258,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) {
|
||||
// 3/3 new vals signed, less than 1/3 old vals present -> error
|
||||
5: {
|
||||
lessThanOneThird.GenSignedHeader(chainID, 5, bTime.Add(1*time.Hour), nil, lessThanOneThirdVals, lessThanOneThirdVals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(lessThanOneThird)),
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(lessThanOneThird)),
|
||||
lessThanOneThirdVals,
|
||||
3 * time.Hour,
|
||||
bTime.Add(2 * time.Hour),
|
||||
@@ -298,7 +298,7 @@ func TestVerifyReturnsErrorIfTrustLevelIsInvalid(t *testing.T) {
|
||||
vals = keys.ToValidators(20, 10)
|
||||
bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
|
||||
header = keys.GenSignedHeader(chainID, lastHeight, bTime, nil, vals, vals,
|
||||
[]byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
||||
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
|
||||
)
|
||||
|
||||
err := lite.Verify(chainID, header, vals, header, vals, 2*time.Hour, time.Now(), maxClockDrift,
|
||||
|
||||
152
types/block.go
152
types/block.go
@@ -36,7 +36,8 @@ const (
|
||||
|
||||
// Block defines the atomic unit of a Tendermint blockchain.
|
||||
type Block struct {
|
||||
mtx sync.Mutex
|
||||
mtx sync.Mutex
|
||||
|
||||
Header `json:"header"`
|
||||
Data `json:"data"`
|
||||
Evidence EvidenceData `json:"evidence"`
|
||||
@@ -50,23 +51,12 @@ func (b *Block) ValidateBasic() error {
|
||||
if b == nil {
|
||||
return errors.New("nil block")
|
||||
}
|
||||
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
if len(b.ChainID) > MaxChainIDLen {
|
||||
return fmt.Errorf("chainID is too long. Max is %d, got %d", MaxChainIDLen, len(b.ChainID))
|
||||
}
|
||||
|
||||
if b.Height < 0 {
|
||||
return errors.New("negative Header.Height")
|
||||
} else if b.Height == 0 {
|
||||
return errors.New("zero Header.Height")
|
||||
}
|
||||
|
||||
// NOTE: Timestamp validation is subtle and handled elsewhere.
|
||||
|
||||
if err := b.LastBlockID.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("wrong Header.LastBlockID: %v", err)
|
||||
if err := b.Header.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("invalid header: %w", err)
|
||||
}
|
||||
|
||||
// Validate the last commit and its hash.
|
||||
@@ -78,9 +68,7 @@ func (b *Block) ValidateBasic() error {
|
||||
return fmt.Errorf("wrong LastCommit: %v", err)
|
||||
}
|
||||
}
|
||||
if err := ValidateHash(b.LastCommitHash); err != nil {
|
||||
return fmt.Errorf("wrong Header.LastCommitHash: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) {
|
||||
return fmt.Errorf("wrong Header.LastCommitHash. Expected %v, got %v",
|
||||
b.LastCommit.Hash(),
|
||||
@@ -88,12 +76,7 @@ func (b *Block) ValidateBasic() error {
|
||||
)
|
||||
}
|
||||
|
||||
// Validate the hash of the transactions.
|
||||
// NOTE: b.Data.Txs may be nil, but b.Data.Hash()
|
||||
// still works fine
|
||||
if err := ValidateHash(b.DataHash); err != nil {
|
||||
return fmt.Errorf("wrong Header.DataHash: %v", err)
|
||||
}
|
||||
// NOTE: b.Data.Txs may be nil, but b.Data.Hash() still works fine.
|
||||
if !bytes.Equal(b.DataHash, b.Data.Hash()) {
|
||||
return fmt.Errorf(
|
||||
"wrong Header.DataHash. Expected %v, got %v",
|
||||
@@ -102,32 +85,13 @@ func (b *Block) ValidateBasic() error {
|
||||
)
|
||||
}
|
||||
|
||||
// Basic validation of hashes related to application data.
|
||||
// Will validate fully against state in state#ValidateBlock.
|
||||
if err := ValidateHash(b.ValidatorsHash); err != nil {
|
||||
return fmt.Errorf("wrong Header.ValidatorsHash: %v", err)
|
||||
}
|
||||
if err := ValidateHash(b.NextValidatorsHash); err != nil {
|
||||
return fmt.Errorf("wrong Header.NextValidatorsHash: %v", err)
|
||||
}
|
||||
if err := ValidateHash(b.ConsensusHash); err != nil {
|
||||
return fmt.Errorf("wrong Header.ConsensusHash: %v", err)
|
||||
}
|
||||
// NOTE: AppHash is arbitrary length
|
||||
if err := ValidateHash(b.LastResultsHash); err != nil {
|
||||
return fmt.Errorf("wrong Header.LastResultsHash: %v", err)
|
||||
}
|
||||
|
||||
// Validate evidence and its hash.
|
||||
if err := ValidateHash(b.EvidenceHash); err != nil {
|
||||
return fmt.Errorf("wrong Header.EvidenceHash: %v", err)
|
||||
}
|
||||
// NOTE: b.Evidence.Evidence may be nil, but we're just looping.
|
||||
for i, ev := range b.Evidence.Evidence {
|
||||
if err := ev.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("invalid evidence (#%d): %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !bytes.Equal(b.EvidenceHash, b.Evidence.Hash()) {
|
||||
return fmt.Errorf("wrong Header.EvidenceHash. Expected %v, got %v",
|
||||
b.EvidenceHash,
|
||||
@@ -135,11 +99,6 @@ func (b *Block) ValidateBasic() error {
|
||||
)
|
||||
}
|
||||
|
||||
if len(b.ProposerAddress) != crypto.AddressSize {
|
||||
return fmt.Errorf("expected len(Header.ProposerAddress) to be %d, got %d",
|
||||
crypto.AddressSize, len(b.ProposerAddress))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -368,6 +327,63 @@ func (h *Header) Populate(
|
||||
h.ProposerAddress = proposerAddress
|
||||
}
|
||||
|
||||
// ValidateBasic performs stateless validation on a Header returning an error
|
||||
// if any validation fails.
|
||||
//
|
||||
// NOTE: Timestamp validation is subtle and handled elsewhere.
|
||||
func (h Header) ValidateBasic() error {
|
||||
if len(h.ChainID) > MaxChainIDLen {
|
||||
return fmt.Errorf("chainID is too long; got: %d, max: %d", len(h.ChainID), MaxChainIDLen)
|
||||
}
|
||||
|
||||
if h.Height < 0 {
|
||||
return errors.New("negative Height")
|
||||
} else if h.Height == 0 {
|
||||
return errors.New("zero Height")
|
||||
}
|
||||
|
||||
if err := h.LastBlockID.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("wrong LastBlockID: %w", err)
|
||||
}
|
||||
|
||||
if err := ValidateHash(h.LastCommitHash); err != nil {
|
||||
return fmt.Errorf("wrong LastCommitHash: %v", err)
|
||||
}
|
||||
|
||||
if err := ValidateHash(h.DataHash); err != nil {
|
||||
return fmt.Errorf("wrong DataHash: %v", err)
|
||||
}
|
||||
|
||||
if err := ValidateHash(h.EvidenceHash); err != nil {
|
||||
return fmt.Errorf("wrong EvidenceHash: %v", err)
|
||||
}
|
||||
|
||||
if len(h.ProposerAddress) != crypto.AddressSize {
|
||||
return fmt.Errorf(
|
||||
"invalid ProposerAddress length; got: %d, expected: %d",
|
||||
len(h.ProposerAddress), crypto.AddressSize,
|
||||
)
|
||||
}
|
||||
|
||||
// Basic validation of hashes related to application data.
|
||||
// Will validate fully against state in state#ValidateBlock.
|
||||
if err := ValidateHash(h.ValidatorsHash); err != nil {
|
||||
return fmt.Errorf("wrong ValidatorsHash: %v", err)
|
||||
}
|
||||
if err := ValidateHash(h.NextValidatorsHash); err != nil {
|
||||
return fmt.Errorf("wrong NextValidatorsHash: %v", err)
|
||||
}
|
||||
if err := ValidateHash(h.ConsensusHash); err != nil {
|
||||
return fmt.Errorf("wrong ConsensusHash: %v", err)
|
||||
}
|
||||
// NOTE: AppHash is arbitrary length
|
||||
if err := ValidateHash(h.LastResultsHash); err != nil {
|
||||
return fmt.Errorf("wrong LastResultsHash: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hash returns the hash of the header.
|
||||
// It computes a Merkle tree from the header fields
|
||||
// ordered as they appear in the Header.
|
||||
@@ -747,7 +763,8 @@ func (commit *Commit) StringIndented(indent string) string {
|
||||
// It is the basis of the lite client.
|
||||
type SignedHeader struct {
|
||||
*Header `json:"header"`
|
||||
Commit *Commit `json:"commit"`
|
||||
|
||||
Commit *Commit `json:"commit"`
|
||||
}
|
||||
|
||||
// ValidateBasic does basic consistency checks and makes sure the header
|
||||
@@ -756,35 +773,30 @@ type SignedHeader struct {
|
||||
// sure to use a Verifier to validate the signatures actually provide a
|
||||
// significantly strong proof for this header's validity.
|
||||
func (sh SignedHeader) ValidateBasic(chainID string) error {
|
||||
// Make sure the header is consistent with the commit.
|
||||
if sh.Header == nil {
|
||||
return errors.New("signedHeader missing header")
|
||||
return errors.New("missing header")
|
||||
}
|
||||
if sh.Commit == nil {
|
||||
return errors.New("signedHeader missing commit (precommit votes)")
|
||||
return errors.New("missing commit")
|
||||
}
|
||||
|
||||
if err := sh.Header.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("invalid header: %w", err)
|
||||
}
|
||||
if err := sh.Commit.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("invalid commit: %w", err)
|
||||
}
|
||||
|
||||
// Check ChainID.
|
||||
if sh.ChainID != chainID {
|
||||
return fmt.Errorf("signedHeader belongs to another chain '%s' not '%s'",
|
||||
sh.ChainID, chainID)
|
||||
return fmt.Errorf("header belongs to another chain %q, not %q", sh.ChainID, chainID)
|
||||
}
|
||||
// Check Height.
|
||||
|
||||
// Make sure the header is consistent with the commit.
|
||||
if sh.Commit.Height != sh.Height {
|
||||
return fmt.Errorf("signedHeader header and commit height mismatch: %v vs %v",
|
||||
sh.Height, sh.Commit.Height)
|
||||
return fmt.Errorf("header and commit height mismatch: %d vs %d", sh.Height, sh.Commit.Height)
|
||||
}
|
||||
// Check Hash.
|
||||
hhash := sh.Hash()
|
||||
chash := sh.Commit.BlockID.Hash
|
||||
if !bytes.Equal(hhash, chash) {
|
||||
return fmt.Errorf("signedHeader commit signs block %X, header is block %X",
|
||||
chash, hhash)
|
||||
}
|
||||
// ValidateBasic on the Commit.
|
||||
err := sh.Commit.ValidateBasic()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "commit.ValidateBasic failed during SignedHeader.ValidateBasic")
|
||||
if hhash, chash := sh.Hash(), sh.Commit.BlockID.Hash; !bytes.Equal(hhash, chash) {
|
||||
return fmt.Errorf("commit signs block %X, header is block %X", chash, hhash)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user