|
|
@ -62,6 +62,52 @@ var ( |
|
|
|
largeFullNode = mockp.New(GenMockNode(chainID, 10, 3, 0, bTime)) |
|
|
|
) |
|
|
|
|
|
|
|
func TestValidateTrustOptions(t *testing.T) { |
|
|
|
testCases := []struct { |
|
|
|
err bool |
|
|
|
to light.TrustOptions |
|
|
|
}{ |
|
|
|
{ |
|
|
|
false, |
|
|
|
trustOptions, |
|
|
|
}, |
|
|
|
{ |
|
|
|
true, |
|
|
|
light.TrustOptions{ |
|
|
|
Period: -1 * time.Hour, |
|
|
|
Height: 1, |
|
|
|
Hash: h1.Hash(), |
|
|
|
}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
true, |
|
|
|
light.TrustOptions{ |
|
|
|
Period: 1 * time.Hour, |
|
|
|
Height: 0, |
|
|
|
Hash: h1.Hash(), |
|
|
|
}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
true, |
|
|
|
light.TrustOptions{ |
|
|
|
Period: 1 * time.Hour, |
|
|
|
Height: 1, |
|
|
|
Hash: []byte("incorrect hash"), |
|
|
|
}, |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
for _, tc := range testCases { |
|
|
|
err := tc.to.ValidateBasic() |
|
|
|
if tc.err { |
|
|
|
assert.Error(t, err) |
|
|
|
} else { |
|
|
|
assert.NoError(t, err) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
func TestClient_SequentialVerification(t *testing.T) { |
|
|
|
newKeys := genPrivKeys(4) |
|
|
|
newVals := newKeys.ToValidators(10, 1) |
|
|
@ -296,8 +342,11 @@ func TestClient_SkippingVerification(t *testing.T) { |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// start from a large header to make sure that the pivot height doesn't select a height outside
|
|
|
|
// the appropriate range
|
|
|
|
} |
|
|
|
|
|
|
|
// start from a large header 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) |
|
|
|
require.NoError(t, err) |
|
|
@ -321,6 +370,34 @@ func TestClient_SkippingVerification(t *testing.T) { |
|
|
|
assert.Equal(t, h, h2) |
|
|
|
} |
|
|
|
|
|
|
|
func TestClientBisectionBetweenTrustedHeaders(t *testing.T) { |
|
|
|
c, err := light.NewClient( |
|
|
|
chainID, |
|
|
|
light.TrustOptions{ |
|
|
|
Period: 4 * time.Hour, |
|
|
|
Height: 1, |
|
|
|
Hash: h1.Hash(), |
|
|
|
}, |
|
|
|
fullNode, |
|
|
|
[]provider.Provider{fullNode}, |
|
|
|
dbs.New(dbm.NewMemDB(), chainID), |
|
|
|
light.SkippingVerification(light.DefaultTrustLevel), |
|
|
|
) |
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(2*time.Hour)) |
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
// confirm that the client already doesn't have the header
|
|
|
|
_, err = c.TrustedHeader(2) |
|
|
|
require.Error(t, err) |
|
|
|
|
|
|
|
// verify using bisection the header between the two trusted headers
|
|
|
|
_, err = c.VerifyHeaderAtHeight(2, bTime.Add(1*time.Hour)) |
|
|
|
assert.NoError(t, err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
func TestClient_Cleanup(t *testing.T) { |
|
|
|
c, err := light.NewClient( |
|
|
|
chainID, |
|
|
@ -514,12 +591,11 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) { |
|
|
|
func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) { |
|
|
|
// 1. options.Hash == trustedHeader.Hash
|
|
|
|
{ |
|
|
|
// load the first three headers into the trusted store
|
|
|
|
trustedStore := dbs.New(dbm.NewMemDB(), chainID) |
|
|
|
err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals) |
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
//header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
|
|
|
|
// []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
|
|
|
|
err = trustedStore.SaveSignedHeaderAndValidatorSet(h2, vals) |
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
@ -554,6 +630,10 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) { |
|
|
|
valSet, _, err = c.TrustedValidatorSet(2) |
|
|
|
assert.Error(t, err) |
|
|
|
assert.Nil(t, valSet) |
|
|
|
|
|
|
|
h, err = c.TrustedHeader(3) |
|
|
|
assert.Error(t, err) |
|
|
|
assert.Nil(t, h) |
|
|
|
} |
|
|
|
|
|
|
|
// 2. options.Hash != trustedHeader.Hash
|
|
|
@ -907,26 +987,60 @@ func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) { |
|
|
|
// header should still be verified
|
|
|
|
assert.EqualValues(t, 2, h.Height) |
|
|
|
|
|
|
|
// no witnesses left to verify -> error
|
|
|
|
// remaining withness doesn't have header -> error
|
|
|
|
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(2*time.Hour)) |
|
|
|
assert.Error(t, err) |
|
|
|
if assert.Error(t, err) { |
|
|
|
assert.Equal(t, "awaiting response from all witnesses exceeded dropout time", err.Error()) |
|
|
|
} |
|
|
|
assert.EqualValues(t, 0, len(c.Witnesses())) |
|
|
|
|
|
|
|
// no witnesses left, will not be allowed to verify a header
|
|
|
|
_, err = c.VerifyHeaderAtHeight(3, bTime.Add(2*time.Hour)) |
|
|
|
if assert.Error(t, err) { |
|
|
|
assert.Equal(t, "no witnesses connected. please reset light client", err.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func TestClientTrustedValidatorSet(t *testing.T) { |
|
|
|
noValSetNode := mockp.New( |
|
|
|
chainID, |
|
|
|
headerSet, |
|
|
|
map[int64]*types.ValidatorSet{ |
|
|
|
1: nil, |
|
|
|
2: nil, |
|
|
|
3: nil, |
|
|
|
}, |
|
|
|
) |
|
|
|
|
|
|
|
differentVals, _ := types.RandValidatorSet(10, 100) |
|
|
|
|
|
|
|
badValSetNode := mockp.New( |
|
|
|
chainID, |
|
|
|
headerSet, |
|
|
|
map[int64]*types.ValidatorSet{ |
|
|
|
1: vals, |
|
|
|
2: differentVals, |
|
|
|
3: differentVals, |
|
|
|
}, |
|
|
|
) |
|
|
|
|
|
|
|
c, err := light.NewClient( |
|
|
|
chainID, |
|
|
|
trustOptions, |
|
|
|
fullNode, |
|
|
|
[]provider.Provider{fullNode}, |
|
|
|
noValSetNode, |
|
|
|
[]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)) |
|
|
|
require.NoError(t, err) |
|
|
|
assert.Error(t, err) |
|
|
|
assert.Equal(t, 1, len(c.Witnesses())) |
|
|
|
|
|
|
|
_, err = c.VerifyHeaderAtHeight(2, bTime.Add(2*time.Hour).Add(1*time.Second)) |
|
|
|
assert.NoError(t, err) |
|
|
|
|
|
|
|
valSet, height, err := c.TrustedValidatorSet(0) |
|
|
|
assert.NoError(t, err) |
|
|
@ -974,6 +1088,28 @@ func TestClientReportsConflictingHeadersEvidence(t *testing.T) { |
|
|
|
assert.True(t, fullNode.HasEvidence(ev)) |
|
|
|
} |
|
|
|
|
|
|
|
func TestClientPrunesHeadersAndValidatorSets(t *testing.T) { |
|
|
|
c, err := light.NewClient( |
|
|
|
chainID, |
|
|
|
trustOptions, |
|
|
|
fullNode, |
|
|
|
[]provider.Provider{fullNode}, |
|
|
|
dbs.New(dbm.NewMemDB(), chainID), |
|
|
|
light.Logger(log.TestingLogger()), |
|
|
|
light.PruningSize(1), |
|
|
|
) |
|
|
|
require.NoError(t, err) |
|
|
|
_, err = c.TrustedHeader(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) |
|
|
|
assert.Error(t, err) |
|
|
|
} |
|
|
|
|
|
|
|
func TestClientEnsureValidHeadersAndValSets(t *testing.T) { |
|
|
|
emptyValSet := &types.ValidatorSet{ |
|
|
|
Validators: nil, |
|
|
|