mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-08 14:21:14 +00:00
light: implement light block (#5298)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
741
light/client.go
741
light/client.go
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
l, err := c.TrustedLightBlock(1)
|
||||
assert.NoError(t, err)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, h.Hash(), header1.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())
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
// Check we still have the 1st light block.
|
||||
l, err := c.TrustedLightBlock(1)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, h)
|
||||
assert.Equal(t, h.Hash(), h1.Hash())
|
||||
assert.NotNil(t, l)
|
||||
assert.Equal(t, l.Hash(), h1.Hash())
|
||||
assert.NoError(t, l.ValidateBasic(chainID))
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
// 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)
|
||||
// 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, h)
|
||||
assert.Equal(t, h.Hash(), header1.Hash())
|
||||
assert.NotNil(t, l)
|
||||
assert.Equal(t, l.Hash(), header1.Hash())
|
||||
assert.NoError(t, l.ValidateBasic(chainID))
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
// 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))
|
||||
l, 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)
|
||||
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)
|
||||
h, err := c.TrustedLightBlock(1)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, h.Height)
|
||||
|
||||
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.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 {
|
||||
|
||||
@@ -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,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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
lbpb, err := lb.ToProto()
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshalling SignedHeader: %w", err)
|
||||
return fmt.Errorf("unable to convert light block to protobuf: %w", err)
|
||||
}
|
||||
|
||||
pbvs, err := valSet.ToProto()
|
||||
lbBz, err := lbpb.Marshal()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to transition validator set to protobuf: %w", err)
|
||||
}
|
||||
|
||||
valSetBz, err := proto.Marshal(pbvs)
|
||||
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) lbKey(height int64) []byte {
|
||||
return []byte(fmt.Sprintf("lb/%s/%020d", s.prefix, height))
|
||||
}
|
||||
|
||||
func (s *dbs) vsKey(height int64) []byte {
|
||||
return []byte(fmt.Sprintf("vs/%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
|
||||
|
||||
@@ -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)
|
||||
size := dbStore.Size()
|
||||
assert.Equal(t, uint16(1), size)
|
||||
t.Log(size)
|
||||
|
||||
h, err = dbStore.LightBlock(1)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, h)
|
||||
|
||||
valSet, err = dbStore.ValidatorSet(1)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, valSet)
|
||||
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
)
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
110
types/block.go
110
types/block.go
@@ -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 {
|
||||
|
||||
|
||||
@@ -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
types/light.go
Normal file
221
types/light.go
Normal 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
types/light_test.go
Normal file
161
types/light_test.go
Normal 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",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user