Browse Source

light: implement light block (#5298)

pull/5318/merge
Callum Waters 4 years ago
committed by GitHub
parent
commit
2b58a62721
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1344 additions and 1197 deletions
  1. +3
    -2
      CHANGELOG_PENDING.md
  2. +288
    -455
      light/client.go
  3. +9
    -9
      light/client_benchmark_test.go
  4. +106
    -167
      light/client_test.go
  5. +3
    -6
      light/errors.go
  6. +11
    -10
      light/example_test.go
  7. +2
    -5
      light/provider/errors.go
  8. +12
    -18
      light/provider/http/http.go
  9. +6
    -14
      light/provider/http/http_test.go
  10. +1
    -4
      light/provider/mock/deadmock.go
  11. +14
    -14
      light/provider/mock/mock.go
  12. +4
    -15
      light/provider/provider.go
  13. +23
    -23
      light/rpc/client.go
  14. +48
    -100
      light/store/db/db.go
  15. +60
    -56
      light/store/db/db_test.go
  16. +2
    -6
      light/store/errors.go
  17. +12
    -19
      light/store/store.go
  18. +6
    -2
      light/verifier.go
  19. +331
    -85
      proto/tendermint/types/types.pb.go
  20. +6
    -0
      proto/tendermint/types/types.proto
  21. +15
    -24
      statesync/stateprovider.go
  22. +0
    -110
      types/block.go
  23. +0
    -53
      types/block_test.go
  24. +221
    -0
      types/light.go
  25. +161
    -0
      types/light_test.go

+ 3
- 2
CHANGELOG_PENDING.md View File

@ -9,13 +9,14 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
- [crypto/secp256k1] \#5280 `secp256k1` has been removed from the Tendermint repo. (@marbar3778)
- CLI/RPC/Config
- [config] \#5315 Rename `prof_laddr` to `pprof_laddr` and move it to `rpc` section (@melekes)
- [rpc] \#5315 Remove `/unsafe_start_cpu_profiler`, `/unsafe_stop_cpu_profiler` and `/unsafe_write_heap_profile`. Please use pprof functionality instead (@melekes)
- [config] \#5315 Rename `prof_laddr` to `pprof_laddr` and move it to `rpc` section (@melekes)
- [rpc] \#5315 Remove `/unsafe_start_cpu_profiler`, `/unsafe_stop_cpu_profiler` and `/unsafe_write_heap_profile`. Please use pprof functionality instead (@melekes)
## FEATURES
- [privval] \#5239 Add `chainID` to requests from client. (@marbar3778)
- [config] Add `--consensus.double_sign_check_height` flag and `DoubleSignCheckHeight` config variable. See [ADR-51](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-051-double-signing-risk-reduction.md)
- [light] [\#5298](https://github.com/tendermint/tendermint/pull/5298) Morph validator set and signed header into light block (@cmwaters)
## IMPROVEMENTS


+ 288
- 455
light/client.go
File diff suppressed because it is too large
View File


+ 9
- 9
light/client_benchmark_test.go View File

@ -22,7 +22,7 @@ import (
// Remember that none of these benchmarks account for network latency.
var (
benchmarkFullNode = mockp.New(GenMockNode(chainID, 1000, 100, 1, bTime))
genesisHeader, _ = benchmarkFullNode.SignedHeader(1)
genesisBlock, _ = benchmarkFullNode.LightBlock(1)
)
func BenchmarkSequence(b *testing.B) {
@ -31,7 +31,7 @@ func BenchmarkSequence(b *testing.B) {
light.TrustOptions{
Period: 24 * time.Hour,
Height: 1,
Hash: genesisHeader.Hash(),
Hash: genesisBlock.Hash(),
},
benchmarkFullNode,
[]provider.Provider{benchmarkFullNode},
@ -45,7 +45,7 @@ func BenchmarkSequence(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, err = c.VerifyHeaderAtHeight(1000, bTime.Add(1000*time.Minute))
_, err = c.VerifyLightBlockAtHeight(1000, bTime.Add(1000*time.Minute))
if err != nil {
b.Fatal(err)
}
@ -58,7 +58,7 @@ func BenchmarkBisection(b *testing.B) {
light.TrustOptions{
Period: 24 * time.Hour,
Height: 1,
Hash: genesisHeader.Hash(),
Hash: genesisBlock.Hash(),
},
benchmarkFullNode,
[]provider.Provider{benchmarkFullNode},
@ -71,7 +71,7 @@ func BenchmarkBisection(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, err = c.VerifyHeaderAtHeight(1000, bTime.Add(1000*time.Minute))
_, err = c.VerifyLightBlockAtHeight(1000, bTime.Add(1000*time.Minute))
if err != nil {
b.Fatal(err)
}
@ -79,13 +79,13 @@ func BenchmarkBisection(b *testing.B) {
}
func BenchmarkBackwards(b *testing.B) {
trustedHeader, _ := benchmarkFullNode.SignedHeader(0)
trustedBlock, _ := benchmarkFullNode.LightBlock(0)
c, err := light.NewClient(
chainID,
light.TrustOptions{
Period: 24 * time.Hour,
Height: trustedHeader.Height,
Hash: trustedHeader.Hash(),
Height: trustedBlock.Height,
Hash: trustedBlock.Hash(),
},
benchmarkFullNode,
[]provider.Provider{benchmarkFullNode},
@ -98,7 +98,7 @@ func BenchmarkBackwards(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, err = c.VerifyHeaderAtHeight(1, bTime)
_, err = c.VerifyLightBlockAtHeight(1, bTime)
if err != nil {
b.Fatal(err)
}


+ 106
- 167
light/client_test.go View File

@ -53,6 +53,8 @@ var (
// last header (3/3 signed)
3: h3,
}
l1 = &types.LightBlock{SignedHeader: h1, ValidatorSet: vals}
l2 = &types.LightBlock{SignedHeader: h2, ValidatorSet: vals}
fullNode = mockp.New(
chainID,
headerSet,
@ -108,6 +110,11 @@ func TestValidateTrustOptions(t *testing.T) {
}
func TestMock(t *testing.T) {
l, _ := fullNode.LightBlock(3)
assert.Equal(t, int64(3), l.Height)
}
func TestClient_SequentialVerification(t *testing.T) {
newKeys := genPrivKeys(4)
newVals := newKeys.ToValidators(10, 1)
@ -212,7 +219,7 @@ func TestClient_SequentialVerification(t *testing.T) {
require.NoError(t, err)
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(3*time.Hour))
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(3*time.Hour))
if tc.verifyErr {
assert.Error(t, err)
} else {
@ -335,7 +342,7 @@ func TestClient_SkippingVerification(t *testing.T) {
require.NoError(t, err)
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(3*time.Hour))
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(3*time.Hour))
if tc.verifyErr {
assert.Error(t, err)
} else {
@ -346,18 +353,18 @@ func TestClient_SkippingVerification(t *testing.T) {
}
// start from a large header to make sure that the pivot height doesn't select a height outside
// start from a large light block to make sure that the pivot height doesn't select a height outside
// the appropriate range
func TestClientLargeBisectionVerification(t *testing.T) {
veryLargeFullNode := mockp.New(GenMockNode(chainID, 100, 3, 1, bTime))
h1, err := veryLargeFullNode.SignedHeader(90)
l1, err := veryLargeFullNode.LightBlock(90)
require.NoError(t, err)
c, err := light.NewClient(
chainID,
light.TrustOptions{
Period: 4 * time.Hour,
Height: 90,
Hash: h1.Hash(),
Height: l1.Height,
Hash: l1.Hash(),
},
veryLargeFullNode,
[]provider.Provider{veryLargeFullNode},
@ -367,7 +374,7 @@ func TestClientLargeBisectionVerification(t *testing.T) {
require.NoError(t, err)
h, err := c.Update(bTime.Add(100 * time.Minute))
assert.NoError(t, err)
h2, err := veryLargeFullNode.SignedHeader(100)
h2, err := veryLargeFullNode.LightBlock(100)
require.NoError(t, err)
assert.Equal(t, h, h2)
}
@ -387,15 +394,15 @@ func TestClientBisectionBetweenTrustedHeaders(t *testing.T) {
)
require.NoError(t, err)
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(2*time.Hour))
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(2*time.Hour))
require.NoError(t, err)
// confirm that the client already doesn't have the header
_, err = c.TrustedHeader(2)
// confirm that the client already doesn't have the light block
_, err = c.TrustedLightBlock(2)
require.Error(t, err)
// verify using bisection the header between the two trusted headers
_, err = c.VerifyHeaderAtHeight(2, bTime.Add(1*time.Hour))
// verify using bisection the light block between the two trusted light blocks
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(1*time.Hour))
assert.NoError(t, err)
}
@ -409,20 +416,16 @@ func TestClient_Cleanup(t *testing.T) {
light.Logger(log.TestingLogger()),
)
require.NoError(t, err)
_, err = c.TrustedHeader(1)
_, err = c.TrustedLightBlock(1)
require.NoError(t, err)
err = c.Cleanup()
require.NoError(t, err)
// Check no headers/valsets exist after Cleanup.
h, err := c.TrustedHeader(1)
// Check no light blocks exist after Cleanup.
l, err := c.TrustedLightBlock(1)
assert.Error(t, err)
assert.Nil(t, h)
valSet, _, err := c.TrustedValidatorSet(1)
assert.Error(t, err)
assert.Nil(t, valSet)
assert.Nil(t, l)
}
// trustedHeader.Height == options.Height
@ -430,7 +433,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
// 1. options.Hash == trustedHeader.Hash
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
err := trustedStore.SaveLightBlock(l1)
require.NoError(t, err)
c, err := light.NewClient(
@ -443,23 +446,17 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
)
require.NoError(t, err)
h, err := c.TrustedHeader(1)
l, err := c.TrustedLightBlock(1)
assert.NoError(t, err)
assert.NotNil(t, h)
assert.Equal(t, h.Hash(), h1.Hash())
valSet, _, err := c.TrustedValidatorSet(1)
assert.NoError(t, err)
assert.NotNil(t, valSet)
if assert.NotNil(t, valSet) {
assert.Equal(t, h.ValidatorsHash.Bytes(), valSet.Hash())
}
assert.NotNil(t, l)
assert.Equal(t, l.Hash(), h1.Hash())
assert.Equal(t, l.ValidatorSet.Hash(), h1.ValidatorsHash.Bytes())
}
// 2. options.Hash != trustedHeader.Hash
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
err := trustedStore.SaveLightBlock(l1)
require.NoError(t, err)
// header1 != header
@ -489,17 +486,11 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
)
require.NoError(t, err)
h, err := c.TrustedHeader(1)
assert.NoError(t, err)
if assert.NotNil(t, h) {
assert.Equal(t, h.Hash(), header1.Hash())
}
valSet, _, err := c.TrustedValidatorSet(1)
l, err := c.TrustedLightBlock(1)
assert.NoError(t, err)
assert.NotNil(t, valSet)
if assert.NotNil(t, valSet) {
assert.Equal(t, h.ValidatorsHash.Bytes(), valSet.Hash())
if assert.NotNil(t, l) {
assert.Equal(t, l.Hash(), header1.Hash())
assert.NoError(t, l.ValidateBasic(chainID))
}
}
}
@ -509,7 +500,7 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
// 1. options.Hash == trustedHeader.Hash
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
err := trustedStore.SaveLightBlock(l1)
require.NoError(t, err)
c, err := light.NewClient(
@ -527,24 +518,18 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
require.NoError(t, err)
// Check we still have the 1st header (+header+).
h, err := c.TrustedHeader(1)
l, err := c.TrustedLightBlock(1)
assert.NoError(t, err)
assert.NotNil(t, h)
assert.Equal(t, h.Hash(), h1.Hash())
valSet, _, err := c.TrustedValidatorSet(1)
assert.NoError(t, err)
assert.NotNil(t, valSet)
if assert.NotNil(t, valSet) {
assert.Equal(t, h.ValidatorsHash.Bytes(), valSet.Hash())
}
assert.NotNil(t, l)
assert.Equal(t, l.Hash(), h1.Hash())
assert.NoError(t, l.ValidateBasic(chainID))
}
// 2. options.Hash != trustedHeader.Hash
// This could happen if previous provider was lying to us.
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
err := trustedStore.SaveLightBlock(l1)
require.NoError(t, err)
// header1 != header
@ -578,13 +563,9 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
require.NoError(t, err)
// Check we no longer have the invalid 1st header (+header+).
h, err := c.TrustedHeader(1)
assert.Error(t, err)
assert.Nil(t, h)
valSet, _, err := c.TrustedValidatorSet(1)
l, err := c.TrustedLightBlock(1)
assert.Error(t, err)
assert.Nil(t, valSet)
assert.Nil(t, l)
}
}
@ -594,10 +575,10 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
{
// load the first three headers into the trusted store
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
err := trustedStore.SaveLightBlock(l1)
require.NoError(t, err)
err = trustedStore.SaveSignedHeaderAndValidatorSet(h2, vals)
err = trustedStore.SaveLightBlock(l2)
require.NoError(t, err)
c, err := light.NewClient(
@ -610,38 +591,28 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
)
require.NoError(t, err)
// Check we still have the 1st header (+header+).
h, err := c.TrustedHeader(1)
assert.NoError(t, err)
assert.NotNil(t, h)
assert.Equal(t, h.Hash(), h1.Hash())
valSet, _, err := c.TrustedValidatorSet(1)
// Check we still have the 1st light block.
l, err := c.TrustedLightBlock(1)
assert.NoError(t, err)
assert.NotNil(t, valSet)
if assert.NotNil(t, valSet) {
assert.Equal(t, h.ValidatorsHash.Bytes(), valSet.Hash())
}
assert.NotNil(t, l)
assert.Equal(t, l.Hash(), h1.Hash())
assert.NoError(t, l.ValidateBasic(chainID))
// Check we no longer have 2nd header (+header2+).
h, err = c.TrustedHeader(2)
// Check we no longer have 2nd light block.
l, err = c.TrustedLightBlock(2)
assert.Error(t, err)
assert.Nil(t, h)
assert.Nil(t, l)
valSet, _, err = c.TrustedValidatorSet(2)
l, err = c.TrustedLightBlock(3)
assert.Error(t, err)
assert.Nil(t, valSet)
h, err = c.TrustedHeader(3)
assert.Error(t, err)
assert.Nil(t, h)
assert.Nil(t, l)
}
// 2. options.Hash != trustedHeader.Hash
// This could happen if previous provider was lying to us.
{
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals)
err := trustedStore.SaveLightBlock(l1)
require.NoError(t, err)
// header1 != header
@ -650,7 +621,10 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
err = trustedStore.SaveSignedHeaderAndValidatorSet(header2, vals)
err = trustedStore.SaveLightBlock(&types.LightBlock{
SignedHeader: header2,
ValidatorSet: vals,
})
require.NoError(t, err)
primary := mockp.New(
@ -675,27 +649,17 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
)
require.NoError(t, err)
// Check we have swapped invalid 1st header (+header+) with correct one (+header1+).
h, err := c.TrustedHeader(1)
assert.NoError(t, err)
assert.NotNil(t, h)
assert.Equal(t, h.Hash(), header1.Hash())
valSet, _, err := c.TrustedValidatorSet(1)
// Check we have swapped invalid 1st light block (+lightblock+) with correct one (+lightblock2+).
l, err := c.TrustedLightBlock(1)
assert.NoError(t, err)
assert.NotNil(t, valSet)
if assert.NotNil(t, valSet) {
assert.Equal(t, h.ValidatorsHash.Bytes(), valSet.Hash())
}
assert.NotNil(t, l)
assert.Equal(t, l.Hash(), header1.Hash())
assert.NoError(t, l.ValidateBasic(chainID))
// Check we no longer have invalid 2nd header (+header2+).
h, err = c.TrustedHeader(2)
// Check we no longer have invalid 2nd light block (+lightblock2+).
l, err = c.TrustedLightBlock(2)
assert.Error(t, err)
assert.Nil(t, h)
valSet, _, err = c.TrustedValidatorSet(2)
assert.Error(t, err)
assert.Nil(t, valSet)
assert.Nil(t, l)
}
}
@ -711,16 +675,11 @@ func TestClient_Update(t *testing.T) {
require.NoError(t, err)
// should result in downloading & verifying header #3
h, err := c.Update(bTime.Add(2 * time.Hour))
assert.NoError(t, err)
if assert.NotNil(t, h) {
assert.EqualValues(t, 3, h.Height)
}
valSet, _, err := c.TrustedValidatorSet(3)
l, err := c.Update(bTime.Add(2 * time.Hour))
assert.NoError(t, err)
if assert.NotNil(t, valSet) {
assert.Equal(t, h.ValidatorsHash.Bytes(), valSet.Hash())
if assert.NotNil(t, l) {
assert.EqualValues(t, 3, l.Height)
assert.NoError(t, l.ValidateBasic(chainID))
}
}
@ -735,7 +694,7 @@ func TestClient_Concurrency(t *testing.T) {
)
require.NoError(t, err)
_, err = c.VerifyHeaderAtHeight(2, bTime.Add(2*time.Hour))
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(2*time.Hour))
require.NoError(t, err)
var wg sync.WaitGroup
@ -744,7 +703,7 @@ func TestClient_Concurrency(t *testing.T) {
go func() {
defer wg.Done()
// NOTE: Cleanup, Stop, VerifyHeaderAtHeight and Verify are not supposed
// NOTE: Cleanup, Stop, VerifyLightBlockAtHeight and Verify are not supposed
// to be concurrenly safe.
assert.Equal(t, chainID, c.ChainID())
@ -755,13 +714,9 @@ func TestClient_Concurrency(t *testing.T) {
_, err = c.FirstTrustedHeight()
assert.NoError(t, err)
h, err := c.TrustedHeader(1)
l, err := c.TrustedLightBlock(1)
assert.NoError(t, err)
assert.NotNil(t, h)
vals, _, err := c.TrustedValidatorSet(2)
assert.NoError(t, err)
assert.NotNil(t, vals)
assert.NotNil(t, l)
}()
}
@ -789,7 +744,7 @@ func TestClientReplacesPrimaryWithWitnessIfPrimaryIsUnavailable(t *testing.T) {
func TestClient_BackwardsVerification(t *testing.T) {
{
trustHeader, _ := largeFullNode.SignedHeader(6)
trustHeader, _ := largeFullNode.LightBlock(6)
c, err := light.NewClient(
chainID,
light.TrustOptions{
@ -805,42 +760,38 @@ func TestClient_BackwardsVerification(t *testing.T) {
require.NoError(t, err)
// 1) verify before the trusted header using backwards => expect no error
h, err := c.VerifyHeaderAtHeight(5, bTime.Add(6*time.Minute))
h, err := c.VerifyLightBlockAtHeight(5, bTime.Add(6*time.Minute))
require.NoError(t, err)
if assert.NotNil(t, h) {
assert.EqualValues(t, 5, h.Height)
}
// 2) untrusted header is expired but trusted header is not => expect no error
h, err = c.VerifyHeaderAtHeight(3, bTime.Add(8*time.Minute))
h, err = c.VerifyLightBlockAtHeight(3, bTime.Add(8*time.Minute))
assert.NoError(t, err)
assert.NotNil(t, h)
// 3) already stored headers should return the header without error
h, err = c.VerifyHeaderAtHeight(5, bTime.Add(6*time.Minute))
h, err = c.VerifyLightBlockAtHeight(5, bTime.Add(6*time.Minute))
assert.NoError(t, err)
assert.NotNil(t, h)
// 4a) First verify latest header
_, err = c.VerifyHeaderAtHeight(9, bTime.Add(9*time.Minute))
_, err = c.VerifyLightBlockAtHeight(9, bTime.Add(9*time.Minute))
require.NoError(t, err)
// 4b) Verify backwards using bisection => expect no error
_, err = c.VerifyHeaderAtHeight(7, bTime.Add(10*time.Minute))
_, err = c.VerifyLightBlockAtHeight(7, bTime.Add(9*time.Minute))
assert.NoError(t, err)
// shouldn't have verified this header in the process
_, err = c.TrustedHeader(8)
_, err = c.TrustedLightBlock(8)
assert.Error(t, err)
// 5) trusted header has expired => expect error
_, err = c.VerifyHeaderAtHeight(1, bTime.Add(20*time.Minute))
// 5) Try bisection method, but closest header (at 7) has expired
// so expect error
_, err = c.VerifyLightBlockAtHeight(8, bTime.Add(12*time.Minute))
assert.Error(t, err)
// 6) Try bisection method, but closest header (at 7) has expired
// so change to backwards => expect no error
_, err = c.VerifyHeaderAtHeight(8, bTime.Add(12*time.Minute))
assert.NoError(t, err)
}
{
testCases := []struct {
@ -852,7 +803,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
chainID,
map[int64]*types.SignedHeader{
1: h1,
2: keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
2: keys.GenSignedHeader(chainID, 1, bTime.Add(30*time.Minute), nil, vals, vals,
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
3: h3,
},
@ -866,7 +817,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,
hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
hash("app_hash2"), hash("cons_hash23"), hash("results_hash30"), 0, len(keys)),
3: h3,
},
valSet,
@ -874,7 +825,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
},
}
for _, tc := range testCases {
for idx, tc := range testCases {
c, err := light.NewClient(
chainID,
light.TrustOptions{
@ -887,10 +838,10 @@ func TestClient_BackwardsVerification(t *testing.T) {
dbs.New(dbm.NewMemDB(), chainID),
light.Logger(log.TestingLogger()),
)
require.NoError(t, err)
require.NoError(t, err, idx)
_, err = c.VerifyHeaderAtHeight(2, bTime.Add(1*time.Hour).Add(1*time.Second))
assert.Error(t, err)
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(1*time.Hour).Add(1*time.Second))
assert.Error(t, err, idx)
}
}
}
@ -898,7 +849,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
func TestClient_NewClientFromTrustedStore(t *testing.T) {
// 1) Initiate DB and fill with a "trusted" header
db := dbs.New(dbm.NewMemDB(), chainID)
err := db.SaveSignedHeaderAndValidatorSet(h1, vals)
err := db.SaveLightBlock(l1)
require.NoError(t, err)
c, err := light.NewClientFromTrustedStore(
@ -910,18 +861,11 @@ func TestClient_NewClientFromTrustedStore(t *testing.T) {
)
require.NoError(t, err)
// 2) Check header exists (deadNode is being used to ensure we're not getting
// 2) Check light block exists (deadNode is being used to ensure we're not getting
// it from primary)
h, err := c.TrustedHeader(1)
assert.NoError(t, err)
assert.EqualValues(t, 1, h.Height)
valSet, _, err := c.TrustedValidatorSet(1)
h, err := c.TrustedLightBlock(1)
assert.NoError(t, err)
assert.NotNil(t, valSet)
if assert.NotNil(t, valSet) {
assert.Equal(t, h.ValidatorsHash.Bytes(), valSet.Hash())
}
assert.EqualValues(t, l1.Height, h.Height)
}
func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) {
@ -967,18 +911,18 @@ func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) {
assert.EqualValues(t, 2, len(c.Witnesses()))
// witness behaves incorrectly -> removed from list, no error
h, err := c.VerifyHeaderAtHeight(2, bTime.Add(2*time.Hour))
l, err := c.VerifyLightBlockAtHeight(2, bTime.Add(2*time.Hour))
assert.NoError(t, err)
assert.EqualValues(t, 1, len(c.Witnesses()))
// header should still be verified
assert.EqualValues(t, 2, h.Height)
// light block should still be verified
assert.EqualValues(t, 2, l.Height)
// remaining witnesses doesn't have header -> error
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(2*time.Hour))
// remaining witnesses don't have light block -> error
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(2*time.Hour))
if assert.Error(t, err) {
assert.Equal(t, "awaiting response from all witnesses exceeded dropout time", err.Error())
}
// witness does not have a header -> left in the list
// witness does not have a light block -> left in the list
assert.EqualValues(t, 1, len(c.Witnesses()))
}
@ -1017,21 +961,16 @@ func TestClient_TrustedValidatorSet(t *testing.T) {
chainID,
trustOptions,
noValSetNode,
[]provider.Provider{fullNode, badValSetNode, fullNode},
[]provider.Provider{badValSetNode, fullNode, fullNode},
dbs.New(dbm.NewMemDB(), chainID),
light.Logger(log.TestingLogger()),
)
require.NoError(t, err)
assert.Equal(t, 2, len(c.Witnesses()))
_, err = c.VerifyHeaderAtHeight(2, bTime.Add(2*time.Hour).Add(1*time.Second))
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(2*time.Hour).Add(1*time.Second))
assert.NoError(t, err)
assert.Equal(t, 1, len(c.Witnesses()))
valSet, height, err := c.TrustedValidatorSet(0)
assert.NoError(t, err)
assert.NotNil(t, valSet)
assert.EqualValues(t, 2, height)
}
func TestClientReportsConflictingHeadersEvidence(t *testing.T) {
@ -1063,7 +1002,7 @@ func TestClientReportsConflictingHeadersEvidence(t *testing.T) {
require.NoError(t, err)
// Check verification returns an error.
_, err = c.VerifyHeaderAtHeight(2, bTime.Add(2*time.Hour))
_, err = c.VerifyLightBlockAtHeight(2, bTime.Add(2*time.Hour))
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "does not match one")
}
@ -1085,14 +1024,14 @@ func TestClientPrunesHeadersAndValidatorSets(t *testing.T) {
light.PruningSize(1),
)
require.NoError(t, err)
_, err = c.TrustedHeader(1)
_, err = c.TrustedLightBlock(1)
require.NoError(t, err)
h, err := c.Update(bTime.Add(2 * time.Hour))
require.NoError(t, err)
require.Equal(t, int64(3), h.Height)
_, err = c.TrustedHeader(1)
_, err = c.TrustedLightBlock(1)
assert.Error(t, err)
}
@ -1157,7 +1096,7 @@ func TestClientEnsureValidHeadersAndValSets(t *testing.T) {
)
require.NoError(t, err)
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(2*time.Hour))
_, err = c.VerifyLightBlockAtHeight(3, bTime.Add(2*time.Hour))
if tc.err {
assert.Error(t, err)
} else {


+ 3
- 6
light/errors.go View File

@ -87,8 +87,7 @@ type badWitnessCode int
const (
noResponse badWitnessCode = iota + 1
invalidHeader
invalidValidatorSet
invalidLightBlock
)
// errBadWitness is returned when the witness either does not respond or
@ -103,10 +102,8 @@ func (e errBadWitness) Error() string {
switch e.Code {
case noResponse:
return fmt.Sprintf("failed to get a header/vals from witness: %v", e.Reason)
case invalidHeader:
return fmt.Sprintf("witness sent us invalid header: %v", e.Reason)
case invalidValidatorSet:
return fmt.Sprintf("witness sent us invalid validator set: %v", e.Reason)
case invalidLightBlock:
return fmt.Sprintf("witness sent us an invalid light block: %v", e.Reason)
default:
return fmt.Sprintf("unknown code: %d", e.Code)
}


+ 11
- 10
light/example_test.go View File

@ -11,6 +11,7 @@ import (
dbm "github.com/tendermint/tm-db"
"github.com/tendermint/tendermint/abci/example/kvstore"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/light"
"github.com/tendermint/tendermint/light/provider"
httpp "github.com/tendermint/tendermint/light/provider/http"
@ -39,7 +40,7 @@ func ExampleClient_Update() {
stdlog.Fatal(err)
}
header, err := primary.SignedHeader(2)
block, err := primary.LightBlock(2)
if err != nil {
stdlog.Fatal(err)
}
@ -54,12 +55,12 @@ func ExampleClient_Update() {
light.TrustOptions{
Period: 504 * time.Hour, // 21 days
Height: 2,
Hash: header.Hash(),
Hash: block.Hash(),
},
primary,
[]provider.Provider{primary}, // NOTE: primary should not be used here
dbs.New(db, chainID),
// Logger(log.TestingLogger()),
light.Logger(log.TestingLogger()),
)
if err != nil {
stdlog.Fatal(err)
@ -87,8 +88,8 @@ func ExampleClient_Update() {
// Output: successful update
}
// Manually getting headers and verifying them.
func ExampleClient_VerifyHeaderAtHeight() {
// Manually getting light blocks and verifying them.
func ExampleClient_VerifyLightBlockAtHeight() {
// give Tendermint time to generate some blocks
time.Sleep(5 * time.Second)
@ -108,7 +109,7 @@ func ExampleClient_VerifyHeaderAtHeight() {
stdlog.Fatal(err)
}
header, err := primary.SignedHeader(2)
block, err := primary.LightBlock(2)
if err != nil {
stdlog.Fatal(err)
}
@ -123,12 +124,12 @@ func ExampleClient_VerifyHeaderAtHeight() {
light.TrustOptions{
Period: 504 * time.Hour, // 21 days
Height: 2,
Hash: header.Hash(),
Hash: block.Hash(),
},
primary,
[]provider.Provider{primary}, // NOTE: primary should not be used here
dbs.New(db, chainID),
// Logger(log.TestingLogger()),
light.Logger(log.TestingLogger()),
)
if err != nil {
stdlog.Fatal(err)
@ -137,12 +138,12 @@ func ExampleClient_VerifyHeaderAtHeight() {
c.Cleanup()
}()
_, err = c.VerifyHeaderAtHeight(3, time.Now())
_, err = c.VerifyLightBlockAtHeight(3, time.Now())
if err != nil {
stdlog.Fatal(err)
}
h, err := c.TrustedHeader(3)
h, err := c.TrustedLightBlock(3)
if err != nil {
stdlog.Fatal(err)
}


+ 2
- 5
light/provider/errors.go View File

@ -3,10 +3,7 @@ package provider
import "errors"
var (
// ErrSignedHeaderNotFound is returned when a provider can't find the
// ErrLightBlockNotFound is returned when a provider can't find the
// requested header.
ErrSignedHeaderNotFound = errors.New("signed header not found")
// ErrValidatorSetNotFound is returned when a provider can't find the
// requested validator set.
ErrValidatorSetNotFound = errors.New("validator set not found")
ErrLightBlockNotFound = errors.New("light block not found")
)

+ 12
- 18
light/provider/http/http.go View File

@ -55,9 +55,9 @@ func (p *http) String() string {
return fmt.Sprintf("http{%s}", p.client.Remote())
}
// SignedHeader fetches a SignedHeader at the given height and checks the
// LightBlock fetches a LightBlock at the given height and checks the
// chainID matches.
func (p *http) SignedHeader(height int64) (*types.SignedHeader, error) {
func (p *http) LightBlock(height int64) (*types.LightBlock, error) {
h, err := validateHeight(height)
if err != nil {
return nil, err
@ -65,9 +65,9 @@ func (p *http) SignedHeader(height int64) (*types.SignedHeader, error) {
commit, err := p.client.Commit(h)
if err != nil {
// TODO: standartise errors on the RPC side
// TODO: standardize errors on the RPC side
if regexpMissingHeight.MatchString(err.Error()) {
return nil, provider.ErrSignedHeaderNotFound
return nil, provider.ErrLightBlockNotFound
}
return nil, err
}
@ -81,23 +81,12 @@ func (p *http) SignedHeader(height int64) (*types.SignedHeader, error) {
return nil, fmt.Errorf("expected chainID %s, got %s", p.chainID, commit.Header.ChainID)
}
return &commit.SignedHeader, nil
}
// ValidatorSet fetches a ValidatorSet at the given height. Multiple HTTP
// requests might be required if the validator set size is over 100.
func (p *http) ValidatorSet(height int64) (*types.ValidatorSet, error) {
h, err := validateHeight(height)
if err != nil {
return nil, err
}
maxPerPage := 100
res, err := p.client.Validators(h, nil, &maxPerPage)
if err != nil {
// TODO: standartise errors on the RPC side
// TODO: standardize errors on the RPC side
if regexpMissingHeight.MatchString(err.Error()) {
return nil, provider.ErrValidatorSetNotFound
return nil, provider.ErrLightBlockNotFound
}
return nil, err
}
@ -119,7 +108,12 @@ func (p *http) ValidatorSet(height int64) (*types.ValidatorSet, error) {
page++
}
return types.ValidatorSetFromExistingValidators(vals)
valset := types.NewValidatorSet(vals)
return &types.LightBlock{
SignedHeader: &commit.SignedHeader,
ValidatorSet: valset,
}, nil
}
// ReportEvidence calls `/broadcast_evidence` endpoint.


+ 6
- 14
light/provider/http/http_test.go View File

@ -65,7 +65,7 @@ func TestProvider(t *testing.T) {
require.NoError(t, err)
// let's get the highest block
sh, err := p.SignedHeader(0)
sh, err := p.LightBlock(0)
require.NoError(t, err)
assert.True(t, sh.Height < 1000)
@ -75,24 +75,16 @@ func TestProvider(t *testing.T) {
// historical queries now work :)
lower := sh.Height - 3
sh, err = p.SignedHeader(lower)
sh, err = p.LightBlock(lower)
require.NoError(t, err)
assert.Equal(t, lower, sh.Height)
// fetching missing heights (both future and pruned) should return appropriate errors
_, err = p.SignedHeader(1000)
_, err = p.LightBlock(1000)
require.Error(t, err)
assert.Equal(t, provider.ErrSignedHeaderNotFound, err)
assert.Equal(t, provider.ErrLightBlockNotFound, err)
_, err = p.ValidatorSet(1000)
_, err = p.LightBlock(1)
require.Error(t, err)
assert.Equal(t, provider.ErrValidatorSetNotFound, err)
_, err = p.SignedHeader(1)
require.Error(t, err)
assert.Equal(t, provider.ErrSignedHeaderNotFound, err)
_, err = p.ValidatorSet(1)
require.Error(t, err)
assert.Equal(t, provider.ErrValidatorSetNotFound, err)
assert.Equal(t, provider.ErrLightBlockNotFound, err)
}

+ 1
- 4
light/provider/mock/deadmock.go View File

@ -22,13 +22,10 @@ func (p *deadMock) ChainID() string { return p.chainID }
func (p *deadMock) String() string { return "deadMock" }
func (p *deadMock) SignedHeader(height int64) (*types.SignedHeader, error) {
func (p *deadMock) LightBlock(height int64) (*types.LightBlock, error) {
return nil, errNoResp
}
func (p *deadMock) ValidatorSet(height int64) (*types.ValidatorSet, error) {
return nil, errNoResp
}
func (p *deadMock) ReportEvidence(ev types.Evidence) error {
return errNoResp
}

+ 14
- 14
light/provider/mock/mock.go View File

@ -47,24 +47,24 @@ func (p *Mock) String() string {
return fmt.Sprintf("Mock{headers: %s, vals: %v}", headers.String(), vals.String())
}
func (p *Mock) SignedHeader(height int64) (*types.SignedHeader, error) {
func (p *Mock) LightBlock(height int64) (*types.LightBlock, error) {
if height == 0 && len(p.headers) > 0 {
return p.headers[int64(len(p.headers))], nil
sh := p.headers[int64(len(p.headers))]
vals := p.vals[int64(len(p.vals))]
return &types.LightBlock{
SignedHeader: sh,
ValidatorSet: vals,
}, nil
}
if _, ok := p.headers[height]; ok {
return p.headers[height], nil
sh := p.headers[height]
vals := p.vals[height]
return &types.LightBlock{
SignedHeader: sh,
ValidatorSet: vals,
}, nil
}
return nil, provider.ErrSignedHeaderNotFound
}
func (p *Mock) ValidatorSet(height int64) (*types.ValidatorSet, error) {
if height == 0 && len(p.vals) > 0 {
return p.vals[int64(len(p.vals))], nil
}
if _, ok := p.vals[height]; ok {
return p.vals[height], nil
}
return nil, provider.ErrValidatorSetNotFound
return nil, provider.ErrLightBlockNotFound
}
func (p *Mock) ReportEvidence(ev types.Evidence) error {


+ 4
- 15
light/provider/provider.go View File

@ -10,28 +10,17 @@ type Provider interface {
// ChainID returns the blockchain ID.
ChainID() string
// SignedHeader returns the SignedHeader that corresponds to the given
// LightBlock returns the LightBlock that corresponds to the given
// height.
//
// 0 - the latest.
// height must be >= 0.
//
// If the provider fails to fetch the SignedHeader due to the IO or other
// If the provider fails to fetch the LightBlock due to the IO or other
// issues, an error will be returned.
// If there's no SignedHeader for the given height, ErrSignedHeaderNotFound
// If there's no LightBlock for the given height, ErrLightBlockNotFound
// error is returned.
SignedHeader(height int64) (*types.SignedHeader, error)
// ValidatorSet returns the ValidatorSet that corresponds to height.
//
// 0 - the latest.
// height must be >= 0.
//
// If the provider fails to fetch the ValidatorSet due to the IO or other
// issues, an error will be returned.
// If there's no ValidatorSet for the given height, ErrValidatorSetNotFound
// error is returned.
ValidatorSet(height int64) (*types.ValidatorSet, error)
LightBlock(height int64) (*types.LightBlock, error)
// ReportEvidence reports an evidence of misbehavior.
ReportEvidence(ev types.Evidence) error


+ 23
- 23
light/rpc/client.go View File

@ -95,7 +95,7 @@ func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes,
// Update the light client if we're behind.
// NOTE: AppHash for height H is in header H+1.
h, err := c.updateLightClientIfNeededTo(resp.Height + 1)
l, err := c.updateLightClientIfNeededTo(resp.Height + 1)
if err != nil {
return nil, err
}
@ -111,7 +111,7 @@ func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes,
kp := merkle.KeyPath{}
kp = kp.AppendKey([]byte(storeName), merkle.KeyEncodingURL)
kp = kp.AppendKey(resp.Key, merkle.KeyEncodingURL)
err = c.prt.VerifyValue(resp.ProofOps, h.AppHash, kp.String(), resp.Value)
err = c.prt.VerifyValue(resp.ProofOps, l.AppHash, kp.String(), resp.Value)
if err != nil {
return nil, fmt.Errorf("verify value proof: %w", err)
}
@ -120,7 +120,7 @@ func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes,
// OR validate the ansence proof against the trusted header.
// XXX How do we encode the key into a string...
err = c.prt.VerifyAbsence(resp.ProofOps, h.AppHash, string(resp.Key))
err = c.prt.VerifyAbsence(resp.ProofOps, l.AppHash, string(resp.Key))
if err != nil {
return nil, fmt.Errorf("verify absence proof: %w", err)
}
@ -178,13 +178,13 @@ func (c *Client) ConsensusParams(height *int64) (*ctypes.ResultConsensusParams,
}
// Update the light client if we're behind.
h, err := c.updateLightClientIfNeededTo(res.BlockHeight)
l, err := c.updateLightClientIfNeededTo(res.BlockHeight)
if err != nil {
return nil, err
}
// Verify hash.
if cH, tH := types.HashConsensusParams(res.ConsensusParams), h.ConsensusHash; !bytes.Equal(cH, tH) {
if cH, tH := types.HashConsensusParams(res.ConsensusParams), l.ConsensusHash; !bytes.Equal(cH, tH) {
return nil, fmt.Errorf("params hash %X does not match trusted hash %X",
cH, tH)
}
@ -224,7 +224,7 @@ func (c *Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlock
// Verify each of the BlockMetas.
for _, meta := range res.BlockMetas {
h, err := c.lc.TrustedHeader(meta.Header.Height)
h, err := c.lc.TrustedLightBlock(meta.Header.Height)
if err != nil {
return nil, fmt.Errorf("trusted header %d: %w", meta.Header.Height, err)
}
@ -261,13 +261,13 @@ func (c *Client) Block(height *int64) (*ctypes.ResultBlock, error) {
}
// Update the light client if we're behind.
h, err := c.updateLightClientIfNeededTo(res.Block.Height)
l, err := c.updateLightClientIfNeededTo(res.Block.Height)
if err != nil {
return nil, err
}
// Verify block.
if bH, tH := res.Block.Hash(), h.Hash(); !bytes.Equal(bH, tH) {
if bH, tH := res.Block.Hash(), l.Hash(); !bytes.Equal(bH, tH) {
return nil, fmt.Errorf("block header %X does not match with trusted header %X",
bH, tH)
}
@ -295,13 +295,13 @@ func (c *Client) BlockByHash(hash []byte) (*ctypes.ResultBlock, error) {
}
// Update the light client if we're behind.
h, err := c.updateLightClientIfNeededTo(res.Block.Height)
l, err := c.updateLightClientIfNeededTo(res.Block.Height)
if err != nil {
return nil, err
}
// Verify block.
if bH, tH := res.Block.Hash(), h.Hash(); !bytes.Equal(bH, tH) {
if bH, tH := res.Block.Hash(), l.Hash(); !bytes.Equal(bH, tH) {
return nil, fmt.Errorf("block header %X does not match with trusted header %X",
bH, tH)
}
@ -336,7 +336,7 @@ func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error)
}
// Update the light client if we're behind.
trustedHeader, err := c.updateLightClientIfNeededTo(h + 1)
trustedBlock, err := c.updateLightClientIfNeededTo(h + 1)
if err != nil {
return nil, err
}
@ -364,9 +364,9 @@ func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error)
rH := merkle.HashFromByteSlices([][]byte{bbeBytes, results.Hash(), ebeBytes})
// Verify block results.
if !bytes.Equal(rH, trustedHeader.LastResultsHash) {
if !bytes.Equal(rH, trustedBlock.LastResultsHash) {
return nil, fmt.Errorf("last results %X does not match with trusted last results %X",
rH, trustedHeader.LastResultsHash)
rH, trustedBlock.LastResultsHash)
}
return res, nil
@ -387,13 +387,13 @@ func (c *Client) Commit(height *int64) (*ctypes.ResultCommit, error) {
}
// Update the light client if we're behind.
h, err := c.updateLightClientIfNeededTo(res.Height)
l, err := c.updateLightClientIfNeededTo(res.Height)
if err != nil {
return nil, err
}
// Verify commit.
if rH, tH := res.Hash(), h.Hash(); !bytes.Equal(rH, tH) {
if rH, tH := res.Hash(), l.Hash(); !bytes.Equal(rH, tH) {
return nil, fmt.Errorf("header %X does not match with trusted header %X",
rH, tH)
}
@ -415,13 +415,13 @@ func (c *Client) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
}
// Update the light client if we're behind.
h, err := c.updateLightClientIfNeededTo(res.Height)
l, err := c.updateLightClientIfNeededTo(res.Height)
if err != nil {
return nil, err
}
// Validate the proof.
return res, res.Proof.Validate(h.DataHash)
return res, res.Proof.Validate(l.DataHash)
}
func (c *Client) TxSearch(query string, prove bool, page, perPage *int, orderBy string) (
@ -452,7 +452,7 @@ func (c *Client) Validators(height *int64, page, perPage *int) (*ctypes.ResultVa
}
// Update the light client if we're behind.
h, err := c.updateLightClientIfNeededTo(updateHeight)
l, err := c.updateLightClientIfNeededTo(updateHeight)
if err != nil {
return nil, err
}
@ -462,9 +462,9 @@ func (c *Client) Validators(height *int64, page, perPage *int) (*ctypes.ResultVa
case 1:
// if it's the first block we need to validate with the current validator hash as opposed to the
// next validator hash
tH = h.ValidatorsHash
tH = l.ValidatorsHash
default:
tH = h.NextValidatorsHash
tH = l.NextValidatorsHash
}
// Verify validators.
@ -495,12 +495,12 @@ func (c *Client) UnsubscribeAll(ctx context.Context, subscriber string) error {
return c.next.UnsubscribeAll(ctx, subscriber)
}
func (c *Client) updateLightClientIfNeededTo(height int64) (*types.SignedHeader, error) {
h, err := c.lc.VerifyHeaderAtHeight(height, time.Now())
func (c *Client) updateLightClientIfNeededTo(height int64) (*types.LightBlock, error) {
l, err := c.lc.VerifyLightBlockAtHeight(height, time.Now())
if err != nil {
return nil, fmt.Errorf("failed to update light client to %d: %w", height, err)
}
return h, nil
return l, nil
}
func (c *Client) RegisterOpDecoder(typ string, dec merkle.OpDecoder) {


+ 48
- 100
light/store/db/db.go View File

@ -6,7 +6,6 @@ import (
"regexp"
"strconv"
"github.com/gogo/protobuf/proto"
dbm "github.com/tendermint/tm-db"
tmsync "github.com/tendermint/tendermint/libs/sync"
@ -40,30 +39,22 @@ func New(db dbm.DB, prefix string) store.Store {
return &dbs{db: db, prefix: prefix, size: size}
}
// SaveSignedHeaderAndValidatorSet persists SignedHeader and ValidatorSet to
// the db.
// SaveLightBlock persists LightBlock to the db.
//
// Safe for concurrent use by multiple goroutines.
func (s *dbs) SaveSignedHeaderAndValidatorSet(sh *types.SignedHeader, valSet *types.ValidatorSet) error {
if sh.Height <= 0 {
func (s *dbs) SaveLightBlock(lb *types.LightBlock) error {
if lb.Height <= 0 {
panic("negative or zero height")
}
pbsh := sh.ToProto()
shBz, err := proto.Marshal(pbsh)
if err != nil {
return fmt.Errorf("marshalling SignedHeader: %w", err)
}
pbvs, err := valSet.ToProto()
lbpb, err := lb.ToProto()
if err != nil {
return fmt.Errorf("unable to transition validator set to protobuf: %w", err)
return fmt.Errorf("unable to convert light block to protobuf: %w", err)
}
valSetBz, err := proto.Marshal(pbvs)
lbBz, err := lbpb.Marshal()
if err != nil {
return fmt.Errorf("marshalling validator set: %w", err)
return fmt.Errorf("marshalling LightBlock: %w", err)
}
s.mtx.Lock()
@ -71,10 +62,7 @@ func (s *dbs) SaveSignedHeaderAndValidatorSet(sh *types.SignedHeader, valSet *ty
b := s.db.NewBatch()
defer b.Close()
if err = b.Set(s.shKey(sh.Height), shBz); err != nil {
return err
}
if err = b.Set(s.vsKey(sh.Height), valSetBz); err != nil {
if err = b.Set(s.lbKey(lb.Height), lbBz); err != nil {
return err
}
if err = b.Set(sizeKey, marshalSize(s.size+1)); err != nil {
@ -88,11 +76,11 @@ func (s *dbs) SaveSignedHeaderAndValidatorSet(sh *types.SignedHeader, valSet *ty
return nil
}
// DeleteSignedHeaderAndValidatorSet deletes SignedHeader and ValidatorSet from
// DeleteLightBlockAndValidatorSet deletes the LightBlock from
// the db.
//
// Safe for concurrent use by multiple goroutines.
func (s *dbs) DeleteSignedHeaderAndValidatorSet(height int64) error {
func (s *dbs) DeleteLightBlock(height int64) error {
if height <= 0 {
panic("negative or zero height")
}
@ -102,10 +90,7 @@ func (s *dbs) DeleteSignedHeaderAndValidatorSet(height int64) error {
b := s.db.NewBatch()
defer b.Close()
if err := b.Delete(s.shKey(height)); err != nil {
return err
}
if err := b.Delete(s.vsKey(height)); err != nil {
if err := b.Delete(s.lbKey(height)); err != nil {
return err
}
if err := b.Set(sizeKey, marshalSize(s.size-1)); err != nil {
@ -119,73 +104,43 @@ func (s *dbs) DeleteSignedHeaderAndValidatorSet(height int64) error {
return nil
}
// SignedHeader loads SignedHeader at the given height.
// LightBlock retrieves the LightBlock at the given height.
//
// Safe for concurrent use by multiple goroutines.
func (s *dbs) SignedHeader(height int64) (*types.SignedHeader, error) {
func (s *dbs) LightBlock(height int64) (*types.LightBlock, error) {
if height <= 0 {
panic("negative or zero height")
}
bz, err := s.db.Get(s.shKey(height))
bz, err := s.db.Get(s.lbKey(height))
if err != nil {
panic(err)
}
if len(bz) == 0 {
return nil, store.ErrSignedHeaderNotFound
return nil, store.ErrLightBlockNotFound
}
var pbsh tmproto.SignedHeader
err = proto.Unmarshal(bz, &pbsh)
var lbpb tmproto.LightBlock
err = lbpb.Unmarshal(bz)
if err != nil {
return nil, err
return nil, fmt.Errorf("unmarshal error: %w", err)
}
signedHeader, err := types.SignedHeaderFromProto(&pbsh)
lightBlock, err := types.LightBlockFromProto(&lbpb)
if err != nil {
return nil, err
return nil, fmt.Errorf("proto conversion error: %w", err)
}
return signedHeader, err
return lightBlock, err
}
// ValidatorSet loads ValidatorSet at the given height.
// LastLightBlockHeight returns the last LightBlock height stored.
//
// Safe for concurrent use by multiple goroutines.
func (s *dbs) ValidatorSet(height int64) (*types.ValidatorSet, error) {
if height <= 0 {
panic("negative or zero height")
}
bz, err := s.db.Get(s.vsKey(height))
if err != nil {
panic(err)
}
if len(bz) == 0 {
return nil, store.ErrValidatorSetNotFound
}
var pbvs tmproto.ValidatorSet
err = proto.Unmarshal(bz, &pbvs)
if err != nil {
return nil, err
}
valSet, err := types.ValidatorSetFromProto(&pbvs)
if err != nil {
return nil, err
}
return valSet, err
}
// LastSignedHeaderHeight returns the last SignedHeader height stored.
//
// Safe for concurrent use by multiple goroutines.
func (s *dbs) LastSignedHeaderHeight() (int64, error) {
func (s *dbs) LastLightBlockHeight() (int64, error) {
itr, err := s.db.ReverseIterator(
s.shKey(1),
append(s.shKey(1<<63-1), byte(0x00)),
s.lbKey(1),
append(s.lbKey(1<<63-1), byte(0x00)),
)
if err != nil {
panic(err)
@ -194,7 +149,7 @@ func (s *dbs) LastSignedHeaderHeight() (int64, error) {
for itr.Valid() {
key := itr.Key()
_, height, ok := parseShKey(key)
_, height, ok := parseLbKey(key)
if ok {
return height, nil
}
@ -204,13 +159,13 @@ func (s *dbs) LastSignedHeaderHeight() (int64, error) {
return -1, itr.Error()
}
// FirstSignedHeaderHeight returns the first SignedHeader height stored.
// FirstLightBlockHeight returns the first LightBlock height stored.
//
// Safe for concurrent use by multiple goroutines.
func (s *dbs) FirstSignedHeaderHeight() (int64, error) {
func (s *dbs) FirstLightBlockHeight() (int64, error) {
itr, err := s.db.Iterator(
s.shKey(1),
append(s.shKey(1<<63-1), byte(0x00)),
s.lbKey(1),
append(s.lbKey(1<<63-1), byte(0x00)),
)
if err != nil {
panic(err)
@ -219,7 +174,7 @@ func (s *dbs) FirstSignedHeaderHeight() (int64, error) {
for itr.Valid() {
key := itr.Key()
_, height, ok := parseShKey(key)
_, height, ok := parseLbKey(key)
if ok {
return height, nil
}
@ -229,18 +184,18 @@ func (s *dbs) FirstSignedHeaderHeight() (int64, error) {
return -1, itr.Error()
}
// SignedHeaderBefore iterates over headers until it finds a header before
// the given height. It returns ErrSignedHeaderNotFound if no such header exists.
// LightBlockBefore iterates over light blocks until it finds a block before
// the given height. It returns ErrLightBlockNotFound if no such block exists.
//
// Safe for concurrent use by multiple goroutines.
func (s *dbs) SignedHeaderBefore(height int64) (*types.SignedHeader, error) {
func (s *dbs) LightBlockBefore(height int64) (*types.LightBlock, error) {
if height <= 0 {
panic("negative or zero height")
}
itr, err := s.db.ReverseIterator(
s.shKey(1),
s.shKey(height),
s.lbKey(1),
s.lbKey(height),
)
if err != nil {
panic(err)
@ -249,9 +204,9 @@ func (s *dbs) SignedHeaderBefore(height int64) (*types.SignedHeader, error) {
for itr.Valid() {
key := itr.Key()
_, existingHeight, ok := parseShKey(key)
_, existingHeight, ok := parseLbKey(key)
if ok {
return s.SignedHeader(existingHeight)
return s.LightBlock(existingHeight)
}
itr.Next()
}
@ -259,7 +214,7 @@ func (s *dbs) SignedHeaderBefore(height int64) (*types.SignedHeader, error) {
return nil, err
}
return nil, store.ErrSignedHeaderNotFound
return nil, store.ErrLightBlockNotFound
}
// Prune prunes header & validator set pairs until there are only size pairs
@ -279,8 +234,8 @@ func (s *dbs) Prune(size uint16) error {
// 2) Iterate over headers and perform a batch operation.
itr, err := s.db.Iterator(
s.shKey(1),
append(s.shKey(1<<63-1), byte(0x00)),
s.lbKey(1),
append(s.lbKey(1<<63-1), byte(0x00)),
)
if err != nil {
return err
@ -293,12 +248,9 @@ func (s *dbs) Prune(size uint16) error {
pruned := 0
for itr.Valid() && numToPrune > 0 {
key := itr.Key()
_, height, ok := parseShKey(key)
_, height, ok := parseLbKey(key)
if ok {
if err = b.Delete(s.shKey(height)); err != nil {
return err
}
if err = b.Delete(s.vsKey(height)); err != nil {
if err = b.Delete(s.lbKey(height)); err != nil {
return err
}
}
@ -337,15 +289,11 @@ func (s *dbs) Size() uint16 {
return s.size
}
func (s *dbs) shKey(height int64) []byte {
return []byte(fmt.Sprintf("sh/%s/%020d", s.prefix, height))
}
func (s *dbs) vsKey(height int64) []byte {
return []byte(fmt.Sprintf("vs/%s/%020d", s.prefix, height))
func (s *dbs) lbKey(height int64) []byte {
return []byte(fmt.Sprintf("lb/%s/%020d", s.prefix, height))
}
var keyPattern = regexp.MustCompile(`^(sh|vs)/([^/]*)/([0-9]+)$`)
var keyPattern = regexp.MustCompile(`^(lb)/([^/]*)/([0-9]+)$`)
func parseKey(key []byte) (part string, prefix string, height int64, ok bool) {
submatch := keyPattern.FindSubmatch(key)
@ -362,10 +310,10 @@ func parseKey(key []byte) (part string, prefix string, height int64, ok bool) {
return
}
func parseShKey(key []byte) (prefix string, height int64, ok bool) {
func parseLbKey(key []byte) (prefix string, height int64, ok bool) {
var part string
part, prefix, height, ok = parseKey(key)
if part != "sh" {
if part != "lb" {
return "", 0, false
}
return


+ 60
- 56
light/store/db/db_test.go View File

@ -3,6 +3,7 @@ package db
import (
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -10,91 +11,78 @@ import (
dbm "github.com/tendermint/tm-db"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash"
tmrand "github.com/tendermint/tendermint/libs/rand"
"github.com/tendermint/tendermint/types"
)
func TestLast_FirstSignedHeaderHeight(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "TestLast_FirstSignedHeaderHeight")
vals, _ := types.RandValidatorSet(10, 100)
func TestLast_FirstLightBlockHeight(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "TestLast_FirstLightBlockHeight")
// Empty store
height, err := dbStore.LastSignedHeaderHeight()
height, err := dbStore.LastLightBlockHeight()
require.NoError(t, err)
assert.EqualValues(t, -1, height)
height, err = dbStore.FirstSignedHeaderHeight()
height, err = dbStore.FirstLightBlockHeight()
require.NoError(t, err)
assert.EqualValues(t, -1, height)
// 1 key
err = dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: 1}}, vals)
err = dbStore.SaveLightBlock(randLightBlock(int64(1)))
require.NoError(t, err)
height, err = dbStore.LastSignedHeaderHeight()
height, err = dbStore.LastLightBlockHeight()
require.NoError(t, err)
assert.EqualValues(t, 1, height)
height, err = dbStore.FirstSignedHeaderHeight()
height, err = dbStore.FirstLightBlockHeight()
require.NoError(t, err)
assert.EqualValues(t, 1, height)
}
func Test_SaveSignedHeaderAndValidatorSet(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "Test_SaveSignedHeaderAndValidatorSet")
vals, _ := types.RandValidatorSet(10, 100)
func Test_SaveLightBlock(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "Test_SaveLightBlockAndValidatorSet")
// Empty store
h, err := dbStore.SignedHeader(1)
h, err := dbStore.LightBlock(1)
require.Error(t, err)
assert.Nil(t, h)
valSet, err := dbStore.ValidatorSet(1)
require.Error(t, err)
assert.Nil(t, valSet)
// 1 key
pa := vals.Validators[0].Address
err = dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: 1, ProposerAddress: pa}}, vals)
err = dbStore.SaveLightBlock(randLightBlock(1))
require.NoError(t, err)
h, err = dbStore.SignedHeader(1)
require.NoError(t, err)
assert.NotNil(t, h)
size := dbStore.Size()
assert.Equal(t, uint16(1), size)
t.Log(size)
valSet, err = dbStore.ValidatorSet(1)
h, err = dbStore.LightBlock(1)
require.NoError(t, err)
assert.NotNil(t, valSet)
assert.NotNil(t, h)
// Empty store
err = dbStore.DeleteSignedHeaderAndValidatorSet(1)
err = dbStore.DeleteLightBlock(1)
require.NoError(t, err)
h, err = dbStore.SignedHeader(1)
h, err = dbStore.LightBlock(1)
require.Error(t, err)
assert.Nil(t, h)
valSet, err = dbStore.ValidatorSet(1)
require.Error(t, err)
assert.Nil(t, valSet)
}
func Test_SignedHeaderBefore(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "Test_SignedHeaderBefore")
valSet, _ := types.RandValidatorSet(10, 100)
pa := valSet.Proposer.Address
func Test_LightBlockBefore(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "Test_LightBlockBefore")
assert.Panics(t, func() {
_, _ = dbStore.SignedHeaderBefore(0)
_, _ = dbStore.SignedHeaderBefore(100)
_, _ = dbStore.LightBlockBefore(0)
_, _ = dbStore.LightBlockBefore(100)
})
err := dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: 2, ProposerAddress: pa}}, valSet)
err := dbStore.SaveLightBlock(randLightBlock(int64(2)))
require.NoError(t, err)
h, err := dbStore.SignedHeaderBefore(3)
h, err := dbStore.LightBlockBefore(3)
require.NoError(t, err)
if assert.NotNil(t, h) {
assert.EqualValues(t, 2, h.Height)
@ -103,7 +91,6 @@ func Test_SignedHeaderBefore(t *testing.T) {
func Test_Prune(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "Test_Prune")
valSet, _ := types.RandValidatorSet(10, 100)
// Empty store
assert.EqualValues(t, 0, dbStore.Size())
@ -111,8 +98,7 @@ func Test_Prune(t *testing.T) {
require.NoError(t, err)
// One header
err = dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: 2}}, valSet)
err = dbStore.SaveLightBlock(randLightBlock(2))
require.NoError(t, err)
assert.EqualValues(t, 1, dbStore.Size())
@ -127,8 +113,7 @@ func Test_Prune(t *testing.T) {
// Multiple headers
for i := 1; i <= 10; i++ {
err = dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: int64(i)}}, valSet)
err = dbStore.SaveLightBlock(randLightBlock(int64(i)))
require.NoError(t, err)
}
@ -143,7 +128,6 @@ func Test_Prune(t *testing.T) {
func Test_Concurrency(t *testing.T) {
dbStore := New(dbm.NewMemDB(), "Test_Prune")
vals, _ := types.RandValidatorSet(10, 100)
var wg sync.WaitGroup
for i := 1; i <= 100; i++ {
@ -151,24 +135,19 @@ func Test_Concurrency(t *testing.T) {
go func(i int64) {
defer wg.Done()
err := dbStore.SaveSignedHeaderAndValidatorSet(
&types.SignedHeader{Header: &types.Header{Height: i,
ProposerAddress: tmrand.Bytes(crypto.AddressSize)}}, vals)
err := dbStore.SaveLightBlock(randLightBlock(i))
require.NoError(t, err)
_, err = dbStore.SignedHeader(i)
_, err = dbStore.LightBlock(i)
if err != nil {
t.Log(err)
}
_, err = dbStore.ValidatorSet(i)
if err != nil {
t.Log(err) // could not find validator set
}
_, err = dbStore.LastSignedHeaderHeight()
_, err = dbStore.LastLightBlockHeight()
if err != nil {
t.Log(err)
}
_, err = dbStore.FirstSignedHeaderHeight()
_, err = dbStore.FirstLightBlockHeight()
if err != nil {
t.Log(err)
}
@ -179,7 +158,7 @@ func Test_Concurrency(t *testing.T) {
}
_ = dbStore.Size()
err = dbStore.DeleteSignedHeaderAndValidatorSet(1)
err = dbStore.DeleteLightBlock(1)
if err != nil {
t.Log(err)
}
@ -188,3 +167,28 @@ func Test_Concurrency(t *testing.T) {
wg.Wait()
}
func randLightBlock(height int64) *types.LightBlock {
vals, _ := types.RandValidatorSet(2, 1)
return &types.LightBlock{
SignedHeader: &types.SignedHeader{
Header: &types.Header{
ChainID: tmrand.Str(12),
Height: height,
Time: time.Now(),
LastBlockID: types.BlockID{},
LastCommitHash: crypto.CRandBytes(tmhash.Size),
DataHash: crypto.CRandBytes(tmhash.Size),
ValidatorsHash: crypto.CRandBytes(tmhash.Size),
NextValidatorsHash: crypto.CRandBytes(tmhash.Size),
ConsensusHash: crypto.CRandBytes(tmhash.Size),
AppHash: crypto.CRandBytes(tmhash.Size),
LastResultsHash: crypto.CRandBytes(tmhash.Size),
EvidenceHash: crypto.CRandBytes(tmhash.Size),
ProposerAddress: crypto.CRandBytes(crypto.AddressSize),
},
Commit: &types.Commit{},
},
ValidatorSet: vals,
}
}

+ 2
- 6
light/store/errors.go View File

@ -3,11 +3,7 @@ package store
import "errors"
var (
// ErrSignedHeaderNotFound is returned when a store does not have the
// ErrLightBlockNotFound is returned when a store does not have the
// requested header.
ErrSignedHeaderNotFound = errors.New("signed header not found")
// ErrValidatorSetNotFound is returned when a store does not have the
// requested validator set.
ErrValidatorSetNotFound = errors.New("validator set not found")
ErrLightBlockNotFound = errors.New("light block not found")
)

+ 12
- 19
light/store/store.go View File

@ -8,43 +8,36 @@ type Store interface {
// ValidatorSet (h: sh.Height).
//
// height must be > 0.
SaveSignedHeaderAndValidatorSet(sh *types.SignedHeader, valSet *types.ValidatorSet) error
SaveLightBlock(lb *types.LightBlock) error
// DeleteSignedHeaderAndValidatorSet deletes SignedHeader (h: height) and
// ValidatorSet (h: height).
//
// height must be > 0.
DeleteSignedHeaderAndValidatorSet(height int64) error
DeleteLightBlock(height int64) error
// SignedHeader returns the SignedHeader that corresponds to the given
// LightBlock returns the LightBlock that corresponds to the given
// height.
//
// height must be > 0.
//
// If SignedHeader is not found, ErrSignedHeaderNotFound is returned.
SignedHeader(height int64) (*types.SignedHeader, error)
// If LightBlock is not found, ErrLightBlockNotFound is returned.
LightBlock(height int64) (*types.LightBlock, error)
// ValidatorSet returns the ValidatorSet that corresponds to height.
//
// height must be > 0.
//
// If ValidatorSet is not found, ErrValidatorSetNotFound is returned.
ValidatorSet(height int64) (*types.ValidatorSet, error)
// LastSignedHeaderHeight returns the last (newest) SignedHeader height.
// LastLightBlockHeight returns the last (newest) LightBlock height.
//
// If the store is empty, -1 and nil error are returned.
LastSignedHeaderHeight() (int64, error)
LastLightBlockHeight() (int64, error)
// FirstSignedHeaderHeight returns the first (oldest) SignedHeader height.
// FirstLightBlockHeight returns the first (oldest) LightBlock height.
//
// If the store is empty, -1 and nil error are returned.
FirstSignedHeaderHeight() (int64, error)
FirstLightBlockHeight() (int64, error)
// SignedHeaderBefore returns the SignedHeader before a certain height.
// LightBlockBefore returns the LightBlock before a certain height.
//
// height must be > 0 && <= LastSignedHeaderHeight.
SignedHeaderBefore(height int64) (*types.SignedHeader, error)
// height must be > 0 && <= LastLightBlockHeight.
LightBlockBefore(height int64) (*types.LightBlock, error)
// Prune removes headers & the associated validator sets when Store reaches a
// defined size (number of header & validator set pairs).


+ 6
- 2
light/verifier.go View File

@ -224,11 +224,15 @@ func HeaderExpired(h *types.SignedHeader, trustingPeriod time.Duration, now time
// of the trusted header
//
// For any of these cases ErrInvalidHeader is returned.
func VerifyBackwards(chainID string, untrustedHeader, trustedHeader *types.SignedHeader) error {
if err := untrustedHeader.ValidateBasic(chainID); err != nil {
func VerifyBackwards(untrustedHeader, trustedHeader *types.Header) error {
if err := untrustedHeader.ValidateBasic(); err != nil {
return ErrInvalidHeader{err}
}
if untrustedHeader.ChainID != trustedHeader.ChainID {
return ErrInvalidHeader{errors.New("header belongs to another chain")}
}
if !untrustedHeader.Time.Before(trustedHeader.Time) {
return ErrInvalidHeader{
fmt.Errorf("expected older header time %v to be before new header time %v",


+ 331
- 85
proto/tendermint/types/types.pb.go View File

@ -873,6 +873,58 @@ func (m *SignedHeader) GetCommit() *Commit {
return nil
}
type LightBlock struct {
SignedHeader *SignedHeader `protobuf:"bytes,1,opt,name=signed_header,json=signedHeader,proto3" json:"signed_header,omitempty"`
ValidatorSet *ValidatorSet `protobuf:"bytes,2,opt,name=validator_set,json=validatorSet,proto3" json:"validator_set,omitempty"`
}
func (m *LightBlock) Reset() { *m = LightBlock{} }
func (m *LightBlock) String() string { return proto.CompactTextString(m) }
func (*LightBlock) ProtoMessage() {}
func (*LightBlock) Descriptor() ([]byte, []int) {
return fileDescriptor_d3a6e55e2345de56, []int{10}
}
func (m *LightBlock) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *LightBlock) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_LightBlock.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *LightBlock) XXX_Merge(src proto.Message) {
xxx_messageInfo_LightBlock.Merge(m, src)
}
func (m *LightBlock) XXX_Size() int {
return m.Size()
}
func (m *LightBlock) XXX_DiscardUnknown() {
xxx_messageInfo_LightBlock.DiscardUnknown(m)
}
var xxx_messageInfo_LightBlock proto.InternalMessageInfo
func (m *LightBlock) GetSignedHeader() *SignedHeader {
if m != nil {
return m.SignedHeader
}
return nil
}
func (m *LightBlock) GetValidatorSet() *ValidatorSet {
if m != nil {
return m.ValidatorSet
}
return nil
}
type BlockMeta struct {
BlockID BlockID `protobuf:"bytes,1,opt,name=block_id,json=blockId,proto3" json:"block_id"`
BlockSize int64 `protobuf:"varint,2,opt,name=block_size,json=blockSize,proto3" json:"block_size,omitempty"`
@ -884,7 +936,7 @@ func (m *BlockMeta) Reset() { *m = BlockMeta{} }
func (m *BlockMeta) String() string { return proto.CompactTextString(m) }
func (*BlockMeta) ProtoMessage() {}
func (*BlockMeta) Descriptor() ([]byte, []int) {
return fileDescriptor_d3a6e55e2345de56, []int{10}
return fileDescriptor_d3a6e55e2345de56, []int{11}
}
func (m *BlockMeta) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -952,7 +1004,7 @@ func (m *TxProof) Reset() { *m = TxProof{} }
func (m *TxProof) String() string { return proto.CompactTextString(m) }
func (*TxProof) ProtoMessage() {}
func (*TxProof) Descriptor() ([]byte, []int) {
return fileDescriptor_d3a6e55e2345de56, []int{11}
return fileDescriptor_d3a6e55e2345de56, []int{12}
}
func (m *TxProof) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -1015,6 +1067,7 @@ func init() {
proto.RegisterType((*CommitSig)(nil), "tendermint.types.CommitSig")
proto.RegisterType((*Proposal)(nil), "tendermint.types.Proposal")
proto.RegisterType((*SignedHeader)(nil), "tendermint.types.SignedHeader")
proto.RegisterType((*LightBlock)(nil), "tendermint.types.LightBlock")
proto.RegisterType((*BlockMeta)(nil), "tendermint.types.BlockMeta")
proto.RegisterType((*TxProof)(nil), "tendermint.types.TxProof")
}
@ -1022,89 +1075,93 @@ func init() {
func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) }
var fileDescriptor_d3a6e55e2345de56 = []byte{
// 1312 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcf, 0x6e, 0xdb, 0xc6,
0x13, 0x36, 0x25, 0xca, 0x92, 0x46, 0x96, 0x2d, 0x2f, 0x9c, 0x44, 0x51, 0x62, 0x99, 0xd0, 0x0f,
0xbf, 0xd6, 0x49, 0x03, 0x2a, 0x75, 0x8a, 0xfe, 0x41, 0xd1, 0x83, 0x64, 0x3b, 0x89, 0x10, 0x5b,
0x56, 0x29, 0x25, 0x45, 0x7b, 0x21, 0x28, 0x71, 0x23, 0xb1, 0xa1, 0xb8, 0x04, 0xb9, 0x72, 0xed,
0x3c, 0x41, 0xe1, 0x53, 0xfa, 0x00, 0x3a, 0xb5, 0x87, 0xde, 0xfb, 0x06, 0x3d, 0xe5, 0x98, 0x5b,
0x7b, 0x69, 0x5a, 0x38, 0x40, 0xd1, 0xc7, 0x28, 0xf6, 0x8f, 0x28, 0xca, 0xb2, 0xdb, 0x20, 0x08,
0x7a, 0x11, 0x76, 0x67, 0xbe, 0x99, 0xdd, 0xf9, 0xf6, 0xdb, 0x1d, 0x0a, 0xae, 0x53, 0xec, 0xd9,
0x38, 0x18, 0x3a, 0x1e, 0xad, 0xd2, 0x63, 0x1f, 0x87, 0xe2, 0x57, 0xf7, 0x03, 0x42, 0x09, 0x2a,
0x4c, 0xbd, 0x3a, 0xb7, 0x97, 0xd6, 0xfa, 0xa4, 0x4f, 0xb8, 0xb3, 0xca, 0x46, 0x02, 0x57, 0xda,
0xe8, 0x13, 0xd2, 0x77, 0x71, 0x95, 0xcf, 0xba, 0xa3, 0xc7, 0x55, 0xea, 0x0c, 0x71, 0x48, 0xad,
0xa1, 0x2f, 0x01, 0x5a, 0x6c, 0x19, 0xd7, 0xe9, 0x86, 0xd5, 0xae, 0x43, 0x67, 0x96, 0x2a, 0xad,
0xc7, 0x10, 0xbd, 0xe0, 0xd8, 0xa7, 0x84, 0x65, 0x23, 0x8f, 0xa5, 0xbb, 0x1c, 0x73, 0x1f, 0xe2,
0x20, 0x74, 0x88, 0x17, 0x0f, 0xaf, 0x7c, 0x02, 0xf9, 0x96, 0x15, 0xd0, 0x36, 0xa6, 0xf7, 0xb1,
0x65, 0xe3, 0x00, 0xad, 0x41, 0x8a, 0x12, 0x6a, 0xb9, 0x45, 0x45, 0x53, 0x36, 0xf3, 0x86, 0x98,
0x20, 0x04, 0xea, 0xc0, 0x0a, 0x07, 0xc5, 0x84, 0xa6, 0x6c, 0x2e, 0x19, 0x7c, 0x5c, 0x19, 0x80,
0xca, 0x42, 0x59, 0x84, 0xe3, 0xd9, 0xf8, 0x68, 0x12, 0xc1, 0x27, 0xcc, 0xda, 0x3d, 0xa6, 0x38,
0x94, 0x21, 0x62, 0x82, 0x3e, 0x80, 0x14, 0xdf, 0x5d, 0x31, 0xa9, 0x29, 0x9b, 0xb9, 0xad, 0xa2,
0x1e, 0x23, 0x4a, 0xec, 0x5e, 0x6f, 0x31, 0x7f, 0x5d, 0x7d, 0xfe, 0x72, 0x63, 0xc1, 0x10, 0xe0,
0x8a, 0x0b, 0xe9, 0xba, 0x4b, 0x7a, 0x4f, 0x1a, 0x3b, 0xd1, 0x46, 0x94, 0xe9, 0x46, 0xd0, 0x3e,
0xac, 0xf8, 0x56, 0x40, 0xcd, 0x10, 0x53, 0x73, 0xc0, 0xab, 0xe0, 0x8b, 0xe6, 0xb6, 0x36, 0xf4,
0xb3, 0xe7, 0xa0, 0xcf, 0x14, 0x2b, 0x57, 0xc9, 0xfb, 0x71, 0x63, 0xe5, 0x4f, 0x15, 0x16, 0x25,
0x19, 0x9f, 0x41, 0x5a, 0x92, 0xc6, 0x17, 0xcc, 0x6d, 0xad, 0xc7, 0x33, 0x4a, 0x97, 0xbe, 0x4d,
0xbc, 0x10, 0x7b, 0xe1, 0x28, 0x94, 0xf9, 0x26, 0x31, 0xe8, 0x1d, 0xc8, 0xf4, 0x06, 0x96, 0xe3,
0x99, 0x8e, 0xcd, 0x77, 0x94, 0xad, 0xe7, 0x4e, 0x5f, 0x6e, 0xa4, 0xb7, 0x99, 0xad, 0xb1, 0x63,
0xa4, 0xb9, 0xb3, 0x61, 0xa3, 0xcb, 0xb0, 0x38, 0xc0, 0x4e, 0x7f, 0x40, 0x39, 0x2d, 0x49, 0x43,
0xce, 0xd0, 0xc7, 0xa0, 0x32, 0x41, 0x14, 0x55, 0xbe, 0x76, 0x49, 0x17, 0x6a, 0xd1, 0x27, 0x6a,
0xd1, 0x3b, 0x13, 0xb5, 0xd4, 0x33, 0x6c, 0xe1, 0x67, 0xbf, 0x6f, 0x28, 0x06, 0x8f, 0x40, 0xdb,
0x90, 0x77, 0xad, 0x90, 0x9a, 0x5d, 0x46, 0x1b, 0x5b, 0x3e, 0xc5, 0x53, 0x5c, 0x9d, 0x27, 0x44,
0x12, 0x2b, 0xb7, 0x9e, 0x63, 0x51, 0xc2, 0x64, 0xa3, 0x4d, 0x28, 0xf0, 0x24, 0x3d, 0x32, 0x1c,
0x3a, 0xd4, 0xe4, 0xbc, 0x2f, 0x72, 0xde, 0x97, 0x99, 0x7d, 0x9b, 0x9b, 0xef, 0xb3, 0x13, 0xb8,
0x06, 0x59, 0xdb, 0xa2, 0x96, 0x80, 0xa4, 0x39, 0x24, 0xc3, 0x0c, 0xdc, 0xf9, 0x2e, 0xac, 0x1c,
0x5a, 0xae, 0x63, 0x5b, 0x94, 0x04, 0xa1, 0x80, 0x64, 0x44, 0x96, 0xa9, 0x99, 0x03, 0x6f, 0xc3,
0x9a, 0x87, 0x8f, 0xa8, 0x79, 0x16, 0x9d, 0xe5, 0x68, 0xc4, 0x7c, 0x8f, 0x66, 0x23, 0xfe, 0x0f,
0xcb, 0xbd, 0x09, 0xf9, 0x02, 0x0b, 0x1c, 0x9b, 0x8f, 0xac, 0x1c, 0x76, 0x15, 0x32, 0x96, 0xef,
0x0b, 0x40, 0x8e, 0x03, 0xd2, 0x96, 0xef, 0x73, 0xd7, 0x4d, 0x58, 0xe5, 0x35, 0x06, 0x38, 0x1c,
0xb9, 0x54, 0x26, 0x59, 0xe2, 0x98, 0x15, 0xe6, 0x30, 0x84, 0x9d, 0x63, 0xff, 0x07, 0x79, 0x7c,
0xe8, 0xd8, 0xd8, 0xeb, 0x61, 0x81, 0xcb, 0x73, 0xdc, 0xd2, 0xc4, 0xc8, 0x41, 0x37, 0xa0, 0xe0,
0x07, 0xc4, 0x27, 0x21, 0x0e, 0x4c, 0xcb, 0xb6, 0x03, 0x1c, 0x86, 0xc5, 0x65, 0x91, 0x6f, 0x62,
0xaf, 0x09, 0x73, 0xe5, 0x16, 0xa8, 0x3b, 0x16, 0xb5, 0x50, 0x01, 0x92, 0xf4, 0x28, 0x2c, 0x2a,
0x5a, 0x72, 0x73, 0xc9, 0x60, 0xc3, 0x73, 0xaf, 0xdb, 0x5f, 0x09, 0x50, 0x1f, 0x11, 0x8a, 0xd1,
0x1d, 0x50, 0xd9, 0xd1, 0x71, 0x45, 0x2e, 0x9f, 0xa7, 0xf1, 0xb6, 0xd3, 0xf7, 0xb0, 0xbd, 0x1f,
0xf6, 0x3b, 0xc7, 0x3e, 0x36, 0x38, 0x38, 0x26, 0xb1, 0xc4, 0x8c, 0xc4, 0xd6, 0x20, 0x15, 0x90,
0x91, 0x67, 0x73, 0xe5, 0xa5, 0x0c, 0x31, 0x41, 0xbb, 0x90, 0x89, 0x94, 0xa3, 0xfe, 0x9b, 0x72,
0x56, 0x98, 0x72, 0x98, 0xae, 0xa5, 0xc1, 0x48, 0x77, 0xa5, 0x80, 0xea, 0x90, 0x8d, 0x1e, 0x34,
0xa9, 0xc0, 0xd7, 0x13, 0xf1, 0x34, 0x0c, 0xbd, 0x07, 0xab, 0x91, 0x1e, 0x22, 0x42, 0x85, 0x0a,
0x0b, 0x91, 0x43, 0x32, 0x3a, 0x23, 0x35, 0x53, 0x3c, 0x4a, 0x69, 0x5e, 0xd7, 0x54, 0x6a, 0x0d,
0xfe, 0x3a, 0x5d, 0x87, 0x6c, 0xe8, 0xf4, 0x3d, 0x8b, 0x8e, 0x02, 0x2c, 0xd5, 0x38, 0x35, 0x54,
0xbe, 0x4b, 0xc0, 0xa2, 0x50, 0x77, 0x8c, 0x37, 0xe5, 0x7c, 0xde, 0x12, 0x17, 0xf1, 0x96, 0x7c,
0x73, 0xde, 0x6a, 0x00, 0xd1, 0x66, 0xc2, 0xa2, 0xaa, 0x25, 0x37, 0x73, 0x5b, 0xd7, 0xe6, 0x13,
0x89, 0x2d, 0xb6, 0x9d, 0xbe, 0xbc, 0xbc, 0xb1, 0xa0, 0x48, 0x41, 0xa9, 0xd8, 0x3b, 0xf9, 0x29,
0x64, 0xbb, 0x0e, 0x35, 0xad, 0x20, 0xb0, 0x8e, 0x39, 0x85, 0xb9, 0xad, 0x72, 0x3c, 0x2b, 0x6b,
0x30, 0x3a, 0x6b, 0x30, 0x7a, 0xdd, 0xa1, 0x35, 0x86, 0x32, 0x32, 0x5d, 0x39, 0xaa, 0xfc, 0xa6,
0x40, 0x36, 0x5a, 0x10, 0xd5, 0x20, 0x3f, 0x29, 0xd4, 0x7c, 0xec, 0x5a, 0x7d, 0x29, 0xc6, 0xf5,
0x0b, 0xab, 0xbd, 0xeb, 0x5a, 0x7d, 0x23, 0x27, 0x0b, 0x64, 0x93, 0xf3, 0x0f, 0x36, 0x71, 0xc1,
0xc1, 0xce, 0x28, 0x29, 0xf9, 0x66, 0x4a, 0x9a, 0x39, 0x73, 0xf5, 0xec, 0x99, 0xff, 0x94, 0x80,
0x4c, 0x8b, 0x5f, 0x50, 0xcb, 0xfd, 0x2f, 0xae, 0xd8, 0x35, 0xc8, 0xfa, 0xc4, 0x35, 0x85, 0x47,
0xe5, 0x9e, 0x8c, 0x4f, 0x5c, 0x63, 0x4e, 0x47, 0xa9, 0xb7, 0x74, 0xff, 0x16, 0xdf, 0x02, 0x6b,
0xe9, 0xb3, 0xac, 0x05, 0xb0, 0x24, 0xa8, 0x90, 0x0d, 0xf3, 0x36, 0xe3, 0x80, 0x77, 0x60, 0x65,
0xbe, 0xc1, 0x8b, 0x6d, 0x0b, 0xa4, 0x21, 0x71, 0x2c, 0x42, 0xf4, 0x17, 0xd9, 0xb3, 0x8b, 0x17,
0xe9, 0xdc, 0x90, 0xb8, 0xca, 0xcf, 0x0a, 0x64, 0x79, 0xa9, 0xfb, 0x98, 0x5a, 0x33, 0x54, 0x29,
0x6f, 0x4e, 0xd5, 0x3a, 0x80, 0x48, 0x13, 0x3a, 0x4f, 0xb1, 0x3c, 0xc0, 0x2c, 0xb7, 0xb4, 0x9d,
0xa7, 0x18, 0x7d, 0x18, 0xd5, 0x95, 0xfc, 0xe7, 0xba, 0xe4, 0x55, 0x9c, 0x54, 0x77, 0x05, 0xd2,
0xde, 0x68, 0x68, 0xb2, 0xe7, 0x5d, 0x15, 0xa2, 0xf0, 0x46, 0xc3, 0xce, 0x51, 0x58, 0xf9, 0x1a,
0xd2, 0x9d, 0x23, 0xfe, 0xa9, 0xc3, 0x94, 0x10, 0x10, 0x22, 0xfb, 0xab, 0xf8, 0xae, 0xc9, 0x30,
0x03, 0x6f, 0x27, 0x08, 0x54, 0xd6, 0x48, 0x27, 0x9d, 0x80, 0x8d, 0x91, 0xfe, 0x9a, 0x1f, 0x51,
0xf2, 0xf3, 0xe9, 0xe6, 0x2f, 0x0a, 0xe4, 0x62, 0xd7, 0x10, 0xbd, 0x0f, 0x97, 0xea, 0x7b, 0x07,
0xdb, 0x0f, 0xcc, 0xc6, 0x8e, 0x79, 0x77, 0xaf, 0x76, 0xcf, 0x7c, 0xd8, 0x7c, 0xd0, 0x3c, 0xf8,
0xa2, 0x59, 0x58, 0x28, 0x5d, 0x3e, 0x19, 0x6b, 0x28, 0x86, 0x7d, 0xe8, 0x3d, 0xf1, 0xc8, 0x37,
0x1e, 0xaa, 0xc2, 0xda, 0x6c, 0x48, 0xad, 0xde, 0xde, 0x6d, 0x76, 0x0a, 0x4a, 0xe9, 0xd2, 0xc9,
0x58, 0x5b, 0x8d, 0x45, 0xd4, 0xba, 0x21, 0xf6, 0xe8, 0x7c, 0xc0, 0xf6, 0xc1, 0xfe, 0x7e, 0xa3,
0x53, 0x48, 0xcc, 0x05, 0xc8, 0x87, 0xf6, 0x06, 0xac, 0xce, 0x06, 0x34, 0x1b, 0x7b, 0x85, 0x64,
0x09, 0x9d, 0x8c, 0xb5, 0xe5, 0x18, 0xba, 0xe9, 0xb8, 0xa5, 0xcc, 0xb7, 0xdf, 0x97, 0x17, 0x7e,
0xfc, 0xa1, 0xac, 0xb0, 0xca, 0xf2, 0x33, 0x57, 0x11, 0xdd, 0x82, 0x2b, 0xed, 0xc6, 0xbd, 0xe6,
0xee, 0x8e, 0xb9, 0xdf, 0xbe, 0x67, 0x76, 0xbe, 0x6c, 0xed, 0xc6, 0xaa, 0x5b, 0x39, 0x19, 0x6b,
0x39, 0x59, 0xd2, 0x45, 0xe8, 0x96, 0xb1, 0xfb, 0xe8, 0xa0, 0xb3, 0x5b, 0x50, 0x04, 0xba, 0x15,
0xe0, 0x43, 0x42, 0x31, 0x47, 0xdf, 0x86, 0xab, 0xe7, 0xa0, 0xa3, 0xc2, 0x56, 0x4f, 0xc6, 0x5a,
0xbe, 0x15, 0x60, 0x21, 0x53, 0x1e, 0xa1, 0x43, 0x71, 0x3e, 0xe2, 0xa0, 0x75, 0xd0, 0xae, 0xed,
0x15, 0xb4, 0x52, 0xe1, 0x64, 0xac, 0x2d, 0x4d, 0xde, 0x1c, 0x86, 0x9f, 0x56, 0x56, 0xff, 0xfc,
0xf9, 0x69, 0x59, 0x79, 0x71, 0x5a, 0x56, 0xfe, 0x38, 0x2d, 0x2b, 0xcf, 0x5e, 0x95, 0x17, 0x5e,
0xbc, 0x2a, 0x2f, 0xfc, 0xfa, 0xaa, 0xbc, 0xf0, 0xd5, 0x47, 0x7d, 0x87, 0x0e, 0x46, 0x5d, 0xbd,
0x47, 0x86, 0xd5, 0xf8, 0x9f, 0x90, 0xe9, 0x50, 0xfc, 0xcd, 0x38, 0xfb, 0x07, 0xa5, 0xbb, 0xc8,
0xed, 0x77, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x5b, 0x78, 0xe7, 0xbb, 0x0c, 0x00, 0x00,
// 1364 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x6e, 0xdb, 0x46,
0x10, 0x36, 0x25, 0xca, 0x92, 0x46, 0x92, 0x2d, 0x13, 0x4e, 0xa2, 0x28, 0xb1, 0x4c, 0xa8, 0x68,
0xeb, 0xa4, 0x01, 0x95, 0x3a, 0x45, 0x7f, 0x50, 0xf4, 0x20, 0xc9, 0x4e, 0x22, 0xc4, 0x96, 0x55,
0x4a, 0x49, 0xd1, 0x5e, 0x08, 0x4a, 0xdc, 0x48, 0x6c, 0x28, 0x92, 0xe0, 0xae, 0x5c, 0x3b, 0x4f,
0x50, 0xf8, 0x94, 0x5e, 0x7a, 0xf3, 0xa9, 0x3d, 0xf4, 0xde, 0x37, 0xe8, 0x29, 0xc7, 0xdc, 0xda,
0x4b, 0xd3, 0xc2, 0x01, 0x8a, 0x3e, 0x46, 0xb1, 0x3f, 0xa2, 0x48, 0xcb, 0x6e, 0x03, 0x23, 0xe8,
0x45, 0xe0, 0xce, 0x7c, 0x33, 0x3b, 0xf3, 0xed, 0xc7, 0x1d, 0x0a, 0xae, 0x13, 0xe4, 0x5a, 0x28,
0x18, 0xdb, 0x2e, 0xa9, 0x91, 0x43, 0x1f, 0x61, 0xfe, 0xab, 0xf9, 0x81, 0x47, 0x3c, 0xa5, 0x38,
0xf3, 0x6a, 0xcc, 0x5e, 0x5e, 0x1d, 0x7a, 0x43, 0x8f, 0x39, 0x6b, 0xf4, 0x89, 0xe3, 0xca, 0xeb,
0x43, 0xcf, 0x1b, 0x3a, 0xa8, 0xc6, 0x56, 0xfd, 0xc9, 0xe3, 0x1a, 0xb1, 0xc7, 0x08, 0x13, 0x73,
0xec, 0x0b, 0x80, 0x1a, 0xd9, 0xc6, 0xb1, 0xfb, 0xb8, 0xd6, 0xb7, 0x49, 0x6c, 0xab, 0xf2, 0x5a,
0x04, 0x31, 0x08, 0x0e, 0x7d, 0xe2, 0xd1, 0x6c, 0xde, 0x63, 0xe1, 0xae, 0x44, 0xdc, 0xfb, 0x28,
0xc0, 0xb6, 0xe7, 0xc6, 0xc2, 0xd5, 0xb9, 0x3e, 0xf6, 0x4d, 0xc7, 0xb6, 0x4c, 0xe2, 0x05, 0x1c,
0x51, 0xfd, 0x04, 0x0a, 0x1d, 0x33, 0x20, 0x5d, 0x44, 0xee, 0x23, 0xd3, 0x42, 0x81, 0xb2, 0x0a,
0x29, 0xe2, 0x11, 0xd3, 0x29, 0x49, 0xaa, 0xb4, 0x51, 0xd0, 0xf9, 0x42, 0x51, 0x40, 0x1e, 0x99,
0x78, 0x54, 0x4a, 0xa8, 0xd2, 0x46, 0x5e, 0x67, 0xcf, 0xd5, 0x11, 0xc8, 0x34, 0x94, 0x46, 0xd8,
0xae, 0x85, 0x0e, 0xa6, 0x11, 0x6c, 0x41, 0xad, 0xfd, 0x43, 0x82, 0xb0, 0x08, 0xe1, 0x0b, 0xe5,
0x03, 0x48, 0xb1, 0xfa, 0x4b, 0x49, 0x55, 0xda, 0xc8, 0x6d, 0x96, 0xb4, 0x08, 0x95, 0xbc, 0x3f,
0xad, 0x43, 0xfd, 0x0d, 0xf9, 0xf9, 0xcb, 0xf5, 0x05, 0x9d, 0x83, 0xab, 0x0e, 0xa4, 0x1b, 0x8e,
0x37, 0x78, 0xd2, 0xda, 0x0a, 0x0b, 0x91, 0x66, 0x85, 0x28, 0xbb, 0xb0, 0xec, 0x9b, 0x01, 0x31,
0x30, 0x22, 0xc6, 0x88, 0x75, 0xc1, 0x36, 0xcd, 0x6d, 0xae, 0x6b, 0xa7, 0x4f, 0x4a, 0x8b, 0x35,
0x2b, 0x76, 0x29, 0xf8, 0x51, 0x63, 0xf5, 0x2f, 0x19, 0x16, 0x05, 0x19, 0x9f, 0x41, 0x5a, 0xd0,
0xca, 0x36, 0xcc, 0x6d, 0xae, 0x45, 0x33, 0x0a, 0x97, 0xd6, 0xf4, 0x5c, 0x8c, 0x5c, 0x3c, 0xc1,
0x22, 0xdf, 0x34, 0x46, 0x79, 0x07, 0x32, 0x83, 0x91, 0x69, 0xbb, 0x86, 0x6d, 0xb1, 0x8a, 0xb2,
0x8d, 0xdc, 0xc9, 0xcb, 0xf5, 0x74, 0x93, 0xda, 0x5a, 0x5b, 0x7a, 0x9a, 0x39, 0x5b, 0x96, 0x72,
0x19, 0x16, 0x47, 0xc8, 0x1e, 0x8e, 0x08, 0xa3, 0x25, 0xa9, 0x8b, 0x95, 0xf2, 0x31, 0xc8, 0x54,
0x32, 0x25, 0x99, 0xed, 0x5d, 0xd6, 0xb8, 0x9e, 0xb4, 0xa9, 0x9e, 0xb4, 0xde, 0x54, 0x4f, 0x8d,
0x0c, 0xdd, 0xf8, 0xd9, 0x1f, 0xeb, 0x92, 0xce, 0x22, 0x94, 0x26, 0x14, 0x1c, 0x13, 0x13, 0xa3,
0x4f, 0x69, 0xa3, 0xdb, 0xa7, 0x58, 0x8a, 0xab, 0xf3, 0x84, 0x08, 0x62, 0x45, 0xe9, 0x39, 0x1a,
0xc5, 0x4d, 0x96, 0xb2, 0x01, 0x45, 0x96, 0x64, 0xe0, 0x8d, 0xc7, 0x36, 0x31, 0x18, 0xef, 0x8b,
0x8c, 0xf7, 0x25, 0x6a, 0x6f, 0x32, 0xf3, 0x7d, 0x7a, 0x02, 0xd7, 0x20, 0x6b, 0x99, 0xc4, 0xe4,
0x90, 0x34, 0x83, 0x64, 0xa8, 0x81, 0x39, 0xdf, 0x85, 0xe5, 0x50, 0x75, 0x98, 0x43, 0x32, 0x3c,
0xcb, 0xcc, 0xcc, 0x80, 0xb7, 0x61, 0xd5, 0x45, 0x07, 0xc4, 0x38, 0x8d, 0xce, 0x32, 0xb4, 0x42,
0x7d, 0x8f, 0xe2, 0x11, 0x6f, 0xc3, 0xd2, 0x60, 0x4a, 0x3e, 0xc7, 0x02, 0xc3, 0x16, 0x42, 0x2b,
0x83, 0x5d, 0x85, 0x8c, 0xe9, 0xfb, 0x1c, 0x90, 0x63, 0x80, 0xb4, 0xe9, 0xfb, 0xcc, 0x75, 0x13,
0x56, 0x58, 0x8f, 0x01, 0xc2, 0x13, 0x87, 0x88, 0x24, 0x79, 0x86, 0x59, 0xa6, 0x0e, 0x9d, 0xdb,
0x19, 0xf6, 0x2d, 0x28, 0xa0, 0x7d, 0xdb, 0x42, 0xee, 0x00, 0x71, 0x5c, 0x81, 0xe1, 0xf2, 0x53,
0x23, 0x03, 0xdd, 0x80, 0xa2, 0x1f, 0x78, 0xbe, 0x87, 0x51, 0x60, 0x98, 0x96, 0x15, 0x20, 0x8c,
0x4b, 0x4b, 0x3c, 0xdf, 0xd4, 0x5e, 0xe7, 0xe6, 0xea, 0x2d, 0x90, 0xb7, 0x4c, 0x62, 0x2a, 0x45,
0x48, 0x92, 0x03, 0x5c, 0x92, 0xd4, 0xe4, 0x46, 0x5e, 0xa7, 0x8f, 0x67, 0xbe, 0x6e, 0x7f, 0x27,
0x40, 0x7e, 0xe4, 0x11, 0xa4, 0xdc, 0x01, 0x99, 0x1e, 0x1d, 0x53, 0xe4, 0xd2, 0x59, 0x1a, 0xef,
0xda, 0x43, 0x17, 0x59, 0xbb, 0x78, 0xd8, 0x3b, 0xf4, 0x91, 0xce, 0xc0, 0x11, 0x89, 0x25, 0x62,
0x12, 0x5b, 0x85, 0x54, 0xe0, 0x4d, 0x5c, 0x8b, 0x29, 0x2f, 0xa5, 0xf3, 0x85, 0xb2, 0x0d, 0x99,
0x50, 0x39, 0xf2, 0x7f, 0x29, 0x67, 0x99, 0x2a, 0x87, 0xea, 0x5a, 0x18, 0xf4, 0x74, 0x5f, 0x08,
0xa8, 0x01, 0xd9, 0xf0, 0xca, 0x13, 0x0a, 0x7c, 0x3d, 0x11, 0xcf, 0xc2, 0x94, 0xf7, 0x60, 0x25,
0xd4, 0x43, 0x48, 0x28, 0x57, 0x61, 0x31, 0x74, 0x08, 0x46, 0x63, 0x52, 0x33, 0xf8, 0xa5, 0x94,
0x66, 0x7d, 0xcd, 0xa4, 0xd6, 0x62, 0xb7, 0xd3, 0x75, 0xc8, 0x62, 0x7b, 0xe8, 0x9a, 0x64, 0x12,
0x20, 0xa1, 0xc6, 0x99, 0xa1, 0xfa, 0x5d, 0x02, 0x16, 0xb9, 0xba, 0x23, 0xbc, 0x49, 0x67, 0xf3,
0x96, 0x38, 0x8f, 0xb7, 0xe4, 0xc5, 0x79, 0xab, 0x03, 0x84, 0xc5, 0xe0, 0x92, 0xac, 0x26, 0x37,
0x72, 0x9b, 0xd7, 0xe6, 0x13, 0xf1, 0x12, 0xbb, 0xf6, 0x50, 0xbc, 0xbc, 0x91, 0xa0, 0x50, 0x41,
0xa9, 0xc8, 0x3d, 0xf9, 0x29, 0x64, 0xfb, 0x36, 0x31, 0xcc, 0x20, 0x30, 0x0f, 0x19, 0x85, 0xb9,
0xcd, 0x4a, 0x34, 0x2b, 0x1d, 0x41, 0x1a, 0x1d, 0x41, 0x5a, 0xc3, 0x26, 0x75, 0x8a, 0xd2, 0x33,
0x7d, 0xf1, 0x54, 0xfd, 0x5d, 0x82, 0x6c, 0xb8, 0xa1, 0x52, 0x87, 0xc2, 0xb4, 0x51, 0xe3, 0xb1,
0x63, 0x0e, 0x85, 0x18, 0xd7, 0xce, 0xed, 0xf6, 0xae, 0x63, 0x0e, 0xf5, 0x9c, 0x68, 0x90, 0x2e,
0xce, 0x3e, 0xd8, 0xc4, 0x39, 0x07, 0x1b, 0x53, 0x52, 0xf2, 0x62, 0x4a, 0x8a, 0x9d, 0xb9, 0x7c,
0xfa, 0xcc, 0x7f, 0x4e, 0x40, 0xa6, 0xc3, 0x5e, 0x50, 0xd3, 0xf9, 0x3f, 0x5e, 0xb1, 0x6b, 0x90,
0xf5, 0x3d, 0xc7, 0xe0, 0x1e, 0x99, 0x79, 0x32, 0xbe, 0xe7, 0xe8, 0x73, 0x3a, 0x4a, 0xbd, 0xa1,
0xf7, 0x6f, 0xf1, 0x0d, 0xb0, 0x96, 0x3e, 0xcd, 0x5a, 0x00, 0x79, 0x4e, 0x85, 0x18, 0x98, 0xb7,
0x29, 0x07, 0x6c, 0x02, 0x4b, 0xf3, 0x03, 0x9e, 0x97, 0xcd, 0x91, 0xba, 0xc0, 0xd1, 0x08, 0x3e,
0x5f, 0xc4, 0xcc, 0x2e, 0x9d, 0xa7, 0x73, 0x5d, 0xe0, 0xaa, 0xdf, 0x4b, 0x00, 0x3b, 0x94, 0x59,
0xd6, 0x2f, 0x1d, 0x75, 0x98, 0x95, 0x60, 0xc4, 0x76, 0xae, 0x9c, 0x77, 0x68, 0x62, 0xff, 0x3c,
0x8e, 0xd6, 0xdd, 0x84, 0xc2, 0x4c, 0x8c, 0x18, 0x4d, 0x8b, 0x39, 0x23, 0x49, 0x38, 0x81, 0xba,
0x88, 0xe8, 0xf9, 0xfd, 0xc8, 0xaa, 0xfa, 0x8b, 0x04, 0x59, 0x56, 0xd3, 0x2e, 0x22, 0x66, 0xec,
0x0c, 0xa5, 0x8b, 0x9f, 0xe1, 0x1a, 0x00, 0x4f, 0x83, 0xed, 0xa7, 0x48, 0x28, 0x2b, 0xcb, 0x2c,
0x5d, 0xfb, 0x29, 0x52, 0x3e, 0x0c, 0x09, 0x4f, 0xfe, 0x3b, 0xe1, 0xe2, 0x8e, 0x98, 0xd2, 0x7e,
0x05, 0xd2, 0xee, 0x64, 0x6c, 0xd0, 0xb9, 0x23, 0x73, 0xb5, 0xba, 0x93, 0x71, 0xef, 0x00, 0x57,
0xbf, 0x86, 0x74, 0xef, 0x80, 0x7d, 0x83, 0x51, 0x89, 0x06, 0x9e, 0x27, 0x06, 0x3f, 0xff, 0xe0,
0xca, 0x50, 0x03, 0x9b, 0x73, 0x0a, 0xc8, 0x74, 0xc2, 0x4f, 0x47, 0x14, 0x7d, 0x56, 0xb4, 0xd7,
0xfc, 0xba, 0x13, 0xdf, 0x75, 0x37, 0x7f, 0x95, 0x20, 0x17, 0xb9, 0x1f, 0x94, 0xf7, 0xe1, 0x52,
0x63, 0x67, 0xaf, 0xf9, 0xc0, 0x68, 0x6d, 0x19, 0x77, 0x77, 0xea, 0xf7, 0x8c, 0x87, 0xed, 0x07,
0xed, 0xbd, 0x2f, 0xda, 0xc5, 0x85, 0xf2, 0xe5, 0xa3, 0x63, 0x55, 0x89, 0x60, 0x1f, 0xba, 0x4f,
0x5c, 0xef, 0x1b, 0x57, 0xa9, 0xc1, 0x6a, 0x3c, 0xa4, 0xde, 0xe8, 0x6e, 0xb7, 0x7b, 0x45, 0xa9,
0x7c, 0xe9, 0xe8, 0x58, 0x5d, 0x89, 0x44, 0xd4, 0xfb, 0x18, 0xb9, 0x64, 0x3e, 0xa0, 0xb9, 0xb7,
0xbb, 0xdb, 0xea, 0x15, 0x13, 0x73, 0x01, 0x62, 0x02, 0xdc, 0x80, 0x95, 0x78, 0x40, 0xbb, 0xb5,
0x53, 0x4c, 0x96, 0x95, 0xa3, 0x63, 0x75, 0x29, 0x82, 0x6e, 0xdb, 0x4e, 0x39, 0xf3, 0xed, 0x0f,
0x95, 0x85, 0x9f, 0x7e, 0xac, 0x48, 0xb4, 0xb3, 0x42, 0xec, 0x8e, 0x50, 0x6e, 0xc1, 0x95, 0x6e,
0xeb, 0x5e, 0x7b, 0x7b, 0xcb, 0xd8, 0xed, 0xde, 0x33, 0x7a, 0x5f, 0x76, 0xb6, 0x23, 0xdd, 0x2d,
0x1f, 0x1d, 0xab, 0x39, 0xd1, 0xd2, 0x79, 0xe8, 0x8e, 0xbe, 0xfd, 0x68, 0xaf, 0xb7, 0x5d, 0x94,
0x38, 0xba, 0x13, 0xa0, 0x7d, 0x8f, 0x20, 0x86, 0xbe, 0x0d, 0x57, 0xcf, 0x40, 0x87, 0x8d, 0xad,
0x1c, 0x1d, 0xab, 0x85, 0x4e, 0x80, 0xf8, 0xfb, 0xc3, 0x22, 0x34, 0x28, 0xcd, 0x47, 0xec, 0x75,
0xf6, 0xba, 0xf5, 0x9d, 0xa2, 0x5a, 0x2e, 0x1e, 0x1d, 0xab, 0xf9, 0xe9, 0x65, 0x48, 0xf1, 0xb3,
0xce, 0x1a, 0x9f, 0x3f, 0x3f, 0xa9, 0x48, 0x2f, 0x4e, 0x2a, 0xd2, 0x9f, 0x27, 0x15, 0xe9, 0xd9,
0xab, 0xca, 0xc2, 0x8b, 0x57, 0x95, 0x85, 0xdf, 0x5e, 0x55, 0x16, 0xbe, 0xfa, 0x68, 0x68, 0x93,
0xd1, 0xa4, 0xaf, 0x0d, 0xbc, 0x71, 0x2d, 0xfa, 0xbf, 0x63, 0xf6, 0xc8, 0xff, 0x21, 0x9d, 0xfe,
0x4f, 0xd2, 0x5f, 0x64, 0xf6, 0x3b, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0xb5, 0xf9, 0x01, 0xed,
0x76, 0x0d, 0x00, 0x00,
}
func (m *PartSetHeader) Marshal() (dAtA []byte, err error) {
@ -1708,6 +1765,53 @@ func (m *SignedHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *LightBlock) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *LightBlock) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *LightBlock) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.ValidatorSet != nil {
{
size, err := m.ValidatorSet.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintTypes(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
}
if m.SignedHeader != nil {
{
size, err := m.SignedHeader.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintTypes(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *BlockMeta) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -2079,6 +2183,23 @@ func (m *SignedHeader) Size() (n int) {
return n
}
func (m *LightBlock) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.SignedHeader != nil {
l = m.SignedHeader.Size()
n += 1 + l + sovTypes(uint64(l))
}
if m.ValidatorSet != nil {
l = m.ValidatorSet.Size()
n += 1 + l + sovTypes(uint64(l))
}
return n
}
func (m *BlockMeta) Size() (n int) {
if m == nil {
return 0
@ -4136,6 +4257,131 @@ func (m *SignedHeader) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *LightBlock) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: LightBlock: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: LightBlock: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SignedHeader", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.SignedHeader == nil {
m.SignedHeader = &SignedHeader{}
}
if err := m.SignedHeader.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ValidatorSet", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.ValidatorSet == nil {
m.ValidatorSet = &ValidatorSet{}
}
if err := m.ValidatorSet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *BlockMeta) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0


+ 6
- 0
proto/tendermint/types/types.proto View File

@ -8,6 +8,7 @@ import "google/protobuf/timestamp.proto";
import "tendermint/libs/bits/types.proto";
import "tendermint/crypto/proof.proto";
import "tendermint/version/types.proto";
import "tendermint/types/validator.proto";
// BlockIdFlag indicates which BlcokID the signature is for
enum BlockIDFlag {
@ -141,6 +142,11 @@ message SignedHeader {
Commit commit = 2;
}
message LightBlock {
SignedHeader signed_header = 1;
tendermint.types.ValidatorSet validator_set = 2;
}
message BlockMeta {
BlockID block_id = 1 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false];
int64 block_size = 2;


+ 15
- 24
statesync/stateprovider.go View File

@ -88,7 +88,7 @@ func (s *lightClientStateProvider) AppHash(height uint64) ([]byte, error) {
defer s.Unlock()
// We have to fetch the next height, which contains the app hash for the previous height.
header, err := s.lc.VerifyHeaderAtHeight(int64(height+1), time.Now())
header, err := s.lc.VerifyLightBlockAtHeight(int64(height+1), time.Now())
if err != nil {
return nil, err
}
@ -99,7 +99,7 @@ func (s *lightClientStateProvider) AppHash(height uint64) ([]byte, error) {
func (s *lightClientStateProvider) Commit(height uint64) (*types.Commit, error) {
s.Lock()
defer s.Unlock()
header, err := s.lc.VerifyHeaderAtHeight(int64(height), time.Now())
header, err := s.lc.VerifyLightBlockAtHeight(int64(height), time.Now())
if err != nil {
return nil, err
}
@ -121,36 +121,27 @@ func (s *lightClientStateProvider) State(height uint64) (sm.State, error) {
}
// We need to verify the previous block to get the validator set.
_, err := s.lc.VerifyHeaderAtHeight(int64(height-1), time.Now())
prevLightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height-1), time.Now())
if err != nil {
return sm.State{}, err
}
header, err := s.lc.VerifyHeaderAtHeight(int64(height), time.Now())
lightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height), time.Now())
if err != nil {
return sm.State{}, err
}
nextHeader, err := s.lc.VerifyHeaderAtHeight(int64(height+1), time.Now())
nextLightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height+1), time.Now())
if err != nil {
return sm.State{}, err
}
state.LastBlockHeight = header.Height
state.LastBlockTime = header.Time
state.LastBlockID = header.Commit.BlockID
state.AppHash = nextHeader.AppHash
state.LastResultsHash = nextHeader.LastResultsHash
state.LastValidators, _, err = s.lc.TrustedValidatorSet(int64(height - 1))
if err != nil {
return sm.State{}, err
}
state.Validators, _, err = s.lc.TrustedValidatorSet(int64(height))
if err != nil {
return sm.State{}, err
}
state.NextValidators, _, err = s.lc.TrustedValidatorSet(int64(height + 1))
if err != nil {
return sm.State{}, err
}
state.LastBlockHeight = lightBlock.Height
state.LastBlockTime = lightBlock.Time
state.LastBlockID = lightBlock.Commit.BlockID
state.AppHash = nextLightBlock.AppHash
state.LastResultsHash = nextLightBlock.LastResultsHash
state.LastValidators = prevLightBlock.ValidatorSet
state.Validators = lightBlock.ValidatorSet
state.NextValidators = nextLightBlock.ValidatorSet
state.LastHeightValidatorsChanged = int64(height)
// We'll also need to fetch consensus params via RPC, using light client verification.
@ -163,10 +154,10 @@ func (s *lightClientStateProvider) State(height uint64) (sm.State, error) {
return sm.State{}, fmt.Errorf("unable to create RPC client: %w", err)
}
rpcclient := lightrpc.NewClient(primaryRPC, s.lc)
result, err := rpcclient.ConsensusParams(&nextHeader.Height)
result, err := rpcclient.ConsensusParams(&nextLightBlock.Height)
if err != nil {
return sm.State{}, fmt.Errorf("unable to fetch consensus parameters for height %v: %w",
nextHeader.Height, err)
nextLightBlock.Height, err)
}
state.ConsensusParams = result.ConsensusParams


+ 0
- 110
types/block.go View File

@ -987,116 +987,6 @@ func CommitFromProto(cp *tmproto.Commit) (*Commit, error) {
//-----------------------------------------------------------------------------
// SignedHeader is a header along with the commits that prove it.
// It is the basis of the light client.
type SignedHeader struct {
*Header `json:"header"`
Commit *Commit `json:"commit"`
}
// ValidateBasic does basic consistency checks and makes sure the header
// and commit are consistent.
//
// NOTE: This does not actually check the cryptographic signatures. Make 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 {
if sh.Header == nil {
return errors.New("missing header")
}
if sh.Commit == nil {
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)
}
if sh.ChainID != chainID {
return fmt.Errorf("header belongs to another chain %q, not %q", sh.ChainID, chainID)
}
// Make sure the header is consistent with the commit.
if sh.Commit.Height != sh.Height {
return fmt.Errorf("header and commit height mismatch: %d vs %d", sh.Height, sh.Commit.Height)
}
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
}
// String returns a string representation of SignedHeader.
func (sh SignedHeader) String() string {
return sh.StringIndented("")
}
// StringIndented returns an indented string representation of SignedHeader.
//
// Header
// Commit
func (sh SignedHeader) StringIndented(indent string) string {
return fmt.Sprintf(`SignedHeader{
%s %v
%s %v
%s}`,
indent, sh.Header.StringIndented(indent+" "),
indent, sh.Commit.StringIndented(indent+" "),
indent)
}
// ToProto converts SignedHeader to protobuf
func (sh *SignedHeader) ToProto() *tmproto.SignedHeader {
if sh == nil {
return nil
}
psh := new(tmproto.SignedHeader)
if sh.Header != nil {
psh.Header = sh.Header.ToProto()
}
if sh.Commit != nil {
psh.Commit = sh.Commit.ToProto()
}
return psh
}
// FromProto sets a protobuf SignedHeader to the given pointer.
// It returns an error if the hader or the commit is invalid.
func SignedHeaderFromProto(shp *tmproto.SignedHeader) (*SignedHeader, error) {
if shp == nil {
return nil, errors.New("nil SignedHeader")
}
sh := new(SignedHeader)
if shp.Header != nil {
h, err := HeaderFromProto(shp.Header)
if err != nil {
return nil, err
}
sh.Header = &h
}
if shp.Commit != nil {
c, err := CommitFromProto(shp.Commit)
if err != nil {
return nil, err
}
sh.Commit = c
}
return sh, nil
}
//-----------------------------------------------------------------------------
// Data contains the set of transactions included in the block
type Data struct {


+ 0
- 53
types/block_test.go View File

@ -543,59 +543,6 @@ func TestCommitToVoteSetWithVotesForNilBlock(t *testing.T) {
}
}
func TestSignedHeaderValidateBasic(t *testing.T) {
commit := randCommit(time.Now())
chainID := "𠜎"
timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
h := Header{
Version: version.Consensus{Block: math.MaxInt64, App: math.MaxInt64},
ChainID: chainID,
Height: commit.Height,
Time: timestamp,
LastBlockID: commit.BlockID,
LastCommitHash: commit.Hash(),
DataHash: commit.Hash(),
ValidatorsHash: commit.Hash(),
NextValidatorsHash: commit.Hash(),
ConsensusHash: commit.Hash(),
AppHash: commit.Hash(),
LastResultsHash: commit.Hash(),
EvidenceHash: commit.Hash(),
ProposerAddress: crypto.AddressHash([]byte("proposer_address")),
}
validSignedHeader := SignedHeader{Header: &h, Commit: commit}
validSignedHeader.Commit.BlockID.Hash = validSignedHeader.Hash()
invalidSignedHeader := SignedHeader{}
testCases := []struct {
testName string
shHeader *Header
shCommit *Commit
expectErr bool
}{
{"Valid Signed Header", validSignedHeader.Header, validSignedHeader.Commit, false},
{"Invalid Signed Header", invalidSignedHeader.Header, validSignedHeader.Commit, true},
{"Invalid Signed Header", validSignedHeader.Header, invalidSignedHeader.Commit, true},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.testName, func(t *testing.T) {
sh := SignedHeader{
Header: tc.shHeader,
Commit: tc.shCommit,
}
assert.Equal(
t,
tc.expectErr,
sh.ValidateBasic(validSignedHeader.Header.ChainID) != nil,
"Validate Basic had an unexpected result",
)
})
}
}
func TestBlockIDValidateBasic(t *testing.T) {
validBlockID := BlockID{
Hash: bytes.HexBytes{},


+ 221
- 0
types/light.go View File

@ -0,0 +1,221 @@
package types
import (
"bytes"
"errors"
"fmt"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
// LightBlock is a SignedHeader and a ValidatorSet.
// It is the basis of the light client
type LightBlock struct {
*SignedHeader `json:"signed_header"`
ValidatorSet *ValidatorSet `json:"validator_set"`
}
// ValidateBasic checks that the data is correct and consistent
//
// This does no verification of the signatures
func (lb LightBlock) ValidateBasic(chainID string) error {
if lb.SignedHeader == nil {
return errors.New("missing signed header")
}
if lb.ValidatorSet == nil {
return errors.New("missing validator set")
}
if err := lb.SignedHeader.ValidateBasic(chainID); err != nil {
return fmt.Errorf("invalid signed header: %w", err)
}
if err := lb.ValidatorSet.ValidateBasic(); err != nil {
return fmt.Errorf("invalid validator set: %w", err)
}
// make sure the validator set is consistent with the header
if valSetHash := lb.ValidatorSet.Hash(); !bytes.Equal(lb.SignedHeader.ValidatorsHash, valSetHash) {
return fmt.Errorf("expected validator hash of header to match validator set hash (%X != %X)",
lb.SignedHeader.ValidatorsHash, valSetHash,
)
}
return nil
}
// String returns a string representation of the LightBlock
func (lb LightBlock) String() string {
return lb.StringIndented("")
}
// StringIndented returns an indented string representation of the LightBlock
//
// SignedHeader
// ValidatorSet
func (lb LightBlock) StringIndented(indent string) string {
return fmt.Sprintf(`LightBlock{
%s %v
%s %v
%s}`,
indent, lb.SignedHeader.StringIndented(indent+" "),
indent, lb.ValidatorSet.StringIndented(indent+" "),
indent)
}
// ToProto converts the LightBlock to protobuf
func (lb *LightBlock) ToProto() (*tmproto.LightBlock, error) {
if lb == nil {
return nil, nil
}
lbp := new(tmproto.LightBlock)
var err error
if lb.SignedHeader != nil {
lbp.SignedHeader = lb.SignedHeader.ToProto()
}
if lb.ValidatorSet != nil {
lbp.ValidatorSet, err = lb.ValidatorSet.ToProto()
if err != nil {
return nil, err
}
}
return lbp, nil
}
// LightBlockFromProto converts from protobuf back into the Lightblock.
// An error is returned if either the validator set or signed header are invalid
func LightBlockFromProto(pb *tmproto.LightBlock) (*LightBlock, error) {
if pb == nil {
return nil, errors.New("nil light block")
}
lb := new(LightBlock)
if pb.SignedHeader != nil {
sh, err := SignedHeaderFromProto(pb.SignedHeader)
if err != nil {
return nil, err
}
lb.SignedHeader = sh
}
if pb.ValidatorSet != nil {
vals, err := ValidatorSetFromProto(pb.ValidatorSet)
if err != nil {
return nil, err
}
lb.ValidatorSet = vals
}
return lb, nil
}
//-----------------------------------------------------------------------------
// SignedHeader is a header along with the commits that prove it.
type SignedHeader struct {
*Header `json:"header"`
Commit *Commit `json:"commit"`
}
// ValidateBasic does basic consistency checks and makes sure the header
// and commit are consistent.
//
// NOTE: This does not actually check the cryptographic signatures. Make 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 {
if sh.Header == nil {
return errors.New("missing header")
}
if sh.Commit == nil {
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)
}
if sh.ChainID != chainID {
return fmt.Errorf("header belongs to another chain %q, not %q", sh.ChainID, chainID)
}
// Make sure the header is consistent with the commit.
if sh.Commit.Height != sh.Height {
return fmt.Errorf("header and commit height mismatch: %d vs %d", sh.Height, sh.Commit.Height)
}
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
}
// String returns a string representation of SignedHeader.
func (sh SignedHeader) String() string {
return sh.StringIndented("")
}
// StringIndented returns an indented string representation of SignedHeader.
//
// Header
// Commit
func (sh SignedHeader) StringIndented(indent string) string {
return fmt.Sprintf(`SignedHeader{
%s %v
%s %v
%s}`,
indent, sh.Header.StringIndented(indent+" "),
indent, sh.Commit.StringIndented(indent+" "),
indent)
}
// ToProto converts SignedHeader to protobuf
func (sh *SignedHeader) ToProto() *tmproto.SignedHeader {
if sh == nil {
return nil
}
psh := new(tmproto.SignedHeader)
if sh.Header != nil {
psh.Header = sh.Header.ToProto()
}
if sh.Commit != nil {
psh.Commit = sh.Commit.ToProto()
}
return psh
}
// FromProto sets a protobuf SignedHeader to the given pointer.
// It returns an error if the header or the commit is invalid.
func SignedHeaderFromProto(shp *tmproto.SignedHeader) (*SignedHeader, error) {
if shp == nil {
return nil, errors.New("nil SignedHeader")
}
sh := new(SignedHeader)
if shp.Header != nil {
h, err := HeaderFromProto(shp.Header)
if err != nil {
return nil, err
}
sh.Header = &h
}
if shp.Commit != nil {
c, err := CommitFromProto(shp.Commit)
if err != nil {
return nil, err
}
sh.Commit = c
}
return sh, nil
}

+ 161
- 0
types/light_test.go View File

@ -0,0 +1,161 @@
package types
import (
"math"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/proto/tendermint/version"
)
func TestLightBlockValidateBasic(t *testing.T) {
header := makeRandHeader()
commit := randCommit(time.Now())
vals, _ := RandValidatorSet(5, 1)
header.Height = commit.Height
header.LastBlockID = commit.BlockID
header.ValidatorsHash = vals.Hash()
vals2, _ := RandValidatorSet(3, 1)
vals3 := vals.Copy()
vals3.Proposer = &Validator{}
commit.BlockID.Hash = header.Hash()
sh := &SignedHeader{
Header: &header,
Commit: commit,
}
testCases := []struct {
name string
sh *SignedHeader
vals *ValidatorSet
expectErr bool
}{
{"valid light block", sh, vals, false},
{"hashes don't match", sh, vals2, true},
{"invalid validator set", sh, vals3, true},
{"invalid signed header", &SignedHeader{Header: &header, Commit: randCommit(time.Now())}, vals, true},
}
for _, tc := range testCases {
lightBlock := LightBlock{
SignedHeader: tc.sh,
ValidatorSet: tc.vals,
}
err := lightBlock.ValidateBasic(header.ChainID)
if tc.expectErr {
assert.Error(t, err, tc.name)
} else {
assert.NoError(t, err, tc.name)
}
}
}
func TestLightBlockProtobuf(t *testing.T) {
header := makeRandHeader()
commit := randCommit(time.Now())
vals, _ := RandValidatorSet(5, 1)
header.Height = commit.Height
header.LastBlockID = commit.BlockID
header.ValidatorsHash = vals.Hash()
vals3 := vals.Copy()
vals3.Proposer = &Validator{}
commit.BlockID.Hash = header.Hash()
sh := &SignedHeader{
Header: &header,
Commit: commit,
}
testCases := []struct {
name string
sh *SignedHeader
vals *ValidatorSet
toProtoErr bool
toBlockErr bool
}{
{"valid light block", sh, vals, false, false},
{"empty signed header", &SignedHeader{}, vals, false, false},
{"empty validator set", sh, &ValidatorSet{}, false, true},
{"empty light block", &SignedHeader{}, &ValidatorSet{}, false, true},
}
for _, tc := range testCases {
lightBlock := &LightBlock{
SignedHeader: tc.sh,
ValidatorSet: tc.vals,
}
lbp, err := lightBlock.ToProto()
if tc.toProtoErr {
assert.Error(t, err, tc.name)
} else {
assert.NoError(t, err, tc.name)
}
lb, err := LightBlockFromProto(lbp)
if tc.toBlockErr {
assert.Error(t, err, tc.name)
} else {
assert.NoError(t, err, tc.name)
assert.Equal(t, lightBlock, lb)
}
}
}
func TestSignedHeaderValidateBasic(t *testing.T) {
commit := randCommit(time.Now())
chainID := "𠜎"
timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
h := Header{
Version: version.Consensus{Block: math.MaxInt64, App: math.MaxInt64},
ChainID: chainID,
Height: commit.Height,
Time: timestamp,
LastBlockID: commit.BlockID,
LastCommitHash: commit.Hash(),
DataHash: commit.Hash(),
ValidatorsHash: commit.Hash(),
NextValidatorsHash: commit.Hash(),
ConsensusHash: commit.Hash(),
AppHash: commit.Hash(),
LastResultsHash: commit.Hash(),
EvidenceHash: commit.Hash(),
ProposerAddress: crypto.AddressHash([]byte("proposer_address")),
}
validSignedHeader := SignedHeader{Header: &h, Commit: commit}
validSignedHeader.Commit.BlockID.Hash = validSignedHeader.Hash()
invalidSignedHeader := SignedHeader{}
testCases := []struct {
testName string
shHeader *Header
shCommit *Commit
expectErr bool
}{
{"Valid Signed Header", validSignedHeader.Header, validSignedHeader.Commit, false},
{"Invalid Signed Header", invalidSignedHeader.Header, validSignedHeader.Commit, true},
{"Invalid Signed Header", validSignedHeader.Header, invalidSignedHeader.Commit, true},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.testName, func(t *testing.T) {
sh := SignedHeader{
Header: tc.shHeader,
Commit: tc.shCommit,
}
assert.Equal(
t,
tc.expectErr,
sh.ValidateBasic(validSignedHeader.Header.ChainID) != nil,
"Validate Basic had an unexpected result",
)
})
}
}

Loading…
Cancel
Save