mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
Rename certifier to light (#784) and add godocs
The certifier package is renamed to light. This is more descriptive especially in the wider blockchain context. Moreover we are building light-clients using the light package. This also adds godocs to all exported functions. Furthermore it introduces some extra error handling. I've added one TODO where I would like someone else's opinion on how to handle the error.
This commit is contained in:
parent
38c4de3fc7
commit
1871a7c3d0
@ -12,10 +12,11 @@ import (
|
|||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SignStatusClient combines a SignClient and StatusClient.
|
||||||
type SignStatusClient interface {
|
type SignStatusClient interface {
|
||||||
rpcclient.SignClient
|
rpcclient.SignClient
|
||||||
rpcclient.StatusClient
|
rpcclient.StatusClient
|
||||||
@ -28,13 +29,13 @@ type provider struct {
|
|||||||
|
|
||||||
// NewProvider can wrap any rpcclient to expose it as
|
// NewProvider can wrap any rpcclient to expose it as
|
||||||
// a read-only provider.
|
// a read-only provider.
|
||||||
func NewProvider(node SignStatusClient) certifiers.Provider {
|
func NewProvider(node SignStatusClient) light.Provider {
|
||||||
return &provider{node: node}
|
return &provider{node: node}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProvider can connects to a tendermint json-rpc endpoint
|
// NewHTTPProvider can connects to a tendermint json-rpc endpoint
|
||||||
// at the given url, and uses that as a read-only provider.
|
// at the given url, and uses that as a read-only provider.
|
||||||
func NewHTTPProvider(remote string) certifiers.Provider {
|
func NewHTTPProvider(remote string) light.Provider {
|
||||||
return &provider{
|
return &provider{
|
||||||
node: rpcclient.NewHTTP(remote, "/websocket"),
|
node: rpcclient.NewHTTP(remote, "/websocket"),
|
||||||
}
|
}
|
||||||
@ -46,13 +47,13 @@ func (p *provider) StatusClient() rpcclient.StatusClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StoreCommit is a noop, as clients can only read from the chain...
|
// StoreCommit is a noop, as clients can only read from the chain...
|
||||||
func (p *provider) StoreCommit(_ certifiers.FullCommit) error { return nil }
|
func (p *provider) StoreCommit(_ light.FullCommit) error { return nil }
|
||||||
|
|
||||||
// GetHash gets the most recent validator and sees if it matches
|
// GetHash gets the most recent validator and sees if it matches
|
||||||
//
|
//
|
||||||
// TODO: improve when the rpc interface supports more functionality
|
// TODO: improve when the rpc interface supports more functionality
|
||||||
func (p *provider) GetByHash(hash []byte) (certifiers.FullCommit, error) {
|
func (p *provider) GetByHash(hash []byte) (light.FullCommit, error) {
|
||||||
var fc certifiers.FullCommit
|
var fc light.FullCommit
|
||||||
vals, err := p.node.Validators(nil)
|
vals, err := p.node.Validators(nil)
|
||||||
// if we get no validators, or a different height, return an error
|
// if we get no validators, or a different height, return an error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -61,13 +62,13 @@ func (p *provider) GetByHash(hash []byte) (certifiers.FullCommit, error) {
|
|||||||
p.updateHeight(vals.BlockHeight)
|
p.updateHeight(vals.BlockHeight)
|
||||||
vhash := types.NewValidatorSet(vals.Validators).Hash()
|
vhash := types.NewValidatorSet(vals.Validators).Hash()
|
||||||
if !bytes.Equal(hash, vhash) {
|
if !bytes.Equal(hash, vhash) {
|
||||||
return fc, certerr.ErrCommitNotFound()
|
return fc, lightErr.ErrCommitNotFound()
|
||||||
}
|
}
|
||||||
return p.seedFromVals(vals)
|
return p.seedFromVals(vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByHeight gets the validator set by height
|
// GetByHeight gets the validator set by height
|
||||||
func (p *provider) GetByHeight(h int) (fc certifiers.FullCommit, err error) {
|
func (p *provider) GetByHeight(h int) (fc light.FullCommit, err error) {
|
||||||
commit, err := p.node.Commit(&h)
|
commit, err := p.node.Commit(&h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fc, err
|
return fc, err
|
||||||
@ -75,7 +76,8 @@ func (p *provider) GetByHeight(h int) (fc certifiers.FullCommit, err error) {
|
|||||||
return p.seedFromCommit(commit)
|
return p.seedFromCommit(commit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) LatestCommit() (fc certifiers.FullCommit, err error) {
|
// LatestCommit returns the newest commit stored.
|
||||||
|
func (p *provider) LatestCommit() (fc light.FullCommit, err error) {
|
||||||
commit, err := p.GetLatestCommit()
|
commit, err := p.GetLatestCommit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fc, err
|
return fc, err
|
||||||
@ -94,24 +96,25 @@ func (p *provider) GetLatestCommit() (*ctypes.ResultCommit, error) {
|
|||||||
return p.node.Commit(&status.LatestBlockHeight)
|
return p.node.Commit(&status.LatestBlockHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CommitFromResult(result *ctypes.ResultCommit) certifiers.Commit {
|
// CommitFromResult ...
|
||||||
return (certifiers.Commit)(result.SignedHeader)
|
func CommitFromResult(result *ctypes.ResultCommit) light.Commit {
|
||||||
|
return (light.Commit)(result.SignedHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) seedFromVals(vals *ctypes.ResultValidators) (certifiers.FullCommit, error) {
|
func (p *provider) seedFromVals(vals *ctypes.ResultValidators) (light.FullCommit, error) {
|
||||||
// now get the commits and build a full commit
|
// now get the commits and build a full commit
|
||||||
commit, err := p.node.Commit(&vals.BlockHeight)
|
commit, err := p.node.Commit(&vals.BlockHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return certifiers.FullCommit{}, err
|
return light.FullCommit{}, err
|
||||||
}
|
}
|
||||||
fc := certifiers.NewFullCommit(
|
fc := light.NewFullCommit(
|
||||||
CommitFromResult(commit),
|
CommitFromResult(commit),
|
||||||
types.NewValidatorSet(vals.Validators),
|
types.NewValidatorSet(vals.Validators),
|
||||||
)
|
)
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) seedFromCommit(commit *ctypes.ResultCommit) (fc certifiers.FullCommit, err error) {
|
func (p *provider) seedFromCommit(commit *ctypes.ResultCommit) (fc light.FullCommit, err error) {
|
||||||
fc.Commit = CommitFromResult(commit)
|
fc.Commit = CommitFromResult(commit)
|
||||||
|
|
||||||
// now get the proper validators
|
// now get the proper validators
|
||||||
@ -123,7 +126,7 @@ func (p *provider) seedFromCommit(commit *ctypes.ResultCommit) (fc certifiers.Fu
|
|||||||
// make sure they match the commit (as we cannot enforce height)
|
// make sure they match the commit (as we cannot enforce height)
|
||||||
vset := types.NewValidatorSet(vals.Validators)
|
vset := types.NewValidatorSet(vals.Validators)
|
||||||
if !bytes.Equal(vset.Hash(), commit.Header.ValidatorsHash) {
|
if !bytes.Equal(vset.Hash(), commit.Header.ValidatorsHash) {
|
||||||
return fc, certerr.ErrValidatorsChanged()
|
return fc, lightErr.ErrValidatorsChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
p.updateHeight(commit.Header.Height)
|
p.updateHeight(commit.Header.Height)
|
@ -6,8 +6,8 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||||
rpctest "github.com/tendermint/tendermint/rpc/test"
|
rpctest "github.com/tendermint/tendermint/rpc/test"
|
||||||
)
|
)
|
||||||
@ -35,7 +35,7 @@ func TestProvider(t *testing.T) {
|
|||||||
|
|
||||||
// let's check this is valid somehow
|
// let's check this is valid somehow
|
||||||
assert.Nil(seed.ValidateBasic(chainID))
|
assert.Nil(seed.ValidateBasic(chainID))
|
||||||
cert := certifiers.NewStatic(chainID, seed.Validators)
|
cert := light.NewStatic(chainID, seed.Validators)
|
||||||
|
|
||||||
// historical queries now work :)
|
// historical queries now work :)
|
||||||
lower := sh - 5
|
lower := sh - 5
|
||||||
@ -53,7 +53,7 @@ func TestProvider(t *testing.T) {
|
|||||||
// get by hash fails without match
|
// get by hash fails without match
|
||||||
seed, err = p.GetByHash([]byte("foobar"))
|
seed, err = p.GetByHash([]byte("foobar"))
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
assert.True(certerr.IsCommitNotFoundErr(err))
|
assert.True(lightErr.IsCommitNotFoundErr(err))
|
||||||
|
|
||||||
// storing the seed silently ignored
|
// storing the seed silently ignored
|
||||||
err = p.StoreCommit(seed)
|
err = p.StoreCommit(seed)
|
@ -1,4 +1,4 @@
|
|||||||
package certifiers
|
package light
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Certifier checks the votes to make sure the block really is signed properly.
|
// Certifier checks the votes to make sure the block really is signed properly.
|
||||||
@ -33,6 +33,7 @@ type FullCommit struct {
|
|||||||
Validators *types.ValidatorSet `json:"validator_set"`
|
Validators *types.ValidatorSet `json:"validator_set"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFullCommit returns a new FullCommit.
|
||||||
func NewFullCommit(commit Commit, vals *types.ValidatorSet) FullCommit {
|
func NewFullCommit(commit Commit, vals *types.ValidatorSet) FullCommit {
|
||||||
return FullCommit{
|
return FullCommit{
|
||||||
Commit: commit,
|
Commit: commit,
|
||||||
@ -40,6 +41,7 @@ func NewFullCommit(commit Commit, vals *types.ValidatorSet) FullCommit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Height returns the of the header.
|
||||||
func (c Commit) Height() int {
|
func (c Commit) Height() int {
|
||||||
if c.Header == nil {
|
if c.Header == nil {
|
||||||
return 0
|
return 0
|
||||||
@ -47,6 +49,7 @@ func (c Commit) Height() int {
|
|||||||
return c.Header.Height
|
return c.Header.Height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidatorsHash returns the hash of the validator set.
|
||||||
func (c Commit) ValidatorsHash() []byte {
|
func (c Commit) ValidatorsHash() []byte {
|
||||||
if c.Header == nil {
|
if c.Header == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -75,7 +78,7 @@ func (c Commit) ValidateBasic(chainID string) error {
|
|||||||
|
|
||||||
// make sure the header and commit match (height and hash)
|
// make sure the header and commit match (height and hash)
|
||||||
if c.Commit.Height() != c.Header.Height {
|
if c.Commit.Height() != c.Header.Height {
|
||||||
return certerr.ErrHeightMismatch(c.Commit.Height(), c.Header.Height)
|
return lightErr.ErrHeightMismatch(c.Commit.Height(), c.Header.Height)
|
||||||
}
|
}
|
||||||
hhash := c.Header.Hash()
|
hhash := c.Header.Hash()
|
||||||
chash := c.Commit.BlockID.Hash
|
chash := c.Commit.BlockID.Hash
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Package certifiers allows you to securely validate headers
|
Package light allows you to securely validate headers
|
||||||
without a full node.
|
without a full node.
|
||||||
|
|
||||||
This library pulls together all the crypto and algorithms,
|
This library pulls together all the crypto and algorithms,
|
||||||
@ -130,4 +130,4 @@ to manually verify the new validator set hash using off-chain
|
|||||||
means (the same as getting the initial hash).
|
means (the same as getting the initial hash).
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package certifiers
|
package light
|
@ -1,9 +1,9 @@
|
|||||||
package certifiers
|
package light
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Certifier = &Dynamic{}
|
var _ Certifier = &Dynamic{}
|
||||||
@ -22,6 +22,7 @@ type Dynamic struct {
|
|||||||
lastHeight int
|
lastHeight int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDynamic returns a new dynamic certifier.
|
||||||
func NewDynamic(chainID string, vals *types.ValidatorSet, height int) *Dynamic {
|
func NewDynamic(chainID string, vals *types.ValidatorSet, height int) *Dynamic {
|
||||||
return &Dynamic{
|
return &Dynamic{
|
||||||
cert: NewStatic(chainID, vals),
|
cert: NewStatic(chainID, vals),
|
||||||
@ -29,23 +30,28 @@ func NewDynamic(chainID string, vals *types.ValidatorSet, height int) *Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChainID returns the chain id of this certifier.
|
||||||
func (c *Dynamic) ChainID() string {
|
func (c *Dynamic) ChainID() string {
|
||||||
return c.cert.ChainID()
|
return c.cert.ChainID()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validators returns the validators of this certifier.
|
||||||
func (c *Dynamic) Validators() *types.ValidatorSet {
|
func (c *Dynamic) Validators() *types.ValidatorSet {
|
||||||
return c.cert.vSet
|
return c.cert.vSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hash returns the hash of this certifier.
|
||||||
func (c *Dynamic) Hash() []byte {
|
func (c *Dynamic) Hash() []byte {
|
||||||
return c.cert.Hash()
|
return c.cert.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LastHeight returns the last height of this certifier.
|
||||||
func (c *Dynamic) LastHeight() int {
|
func (c *Dynamic) LastHeight() int {
|
||||||
return c.lastHeight
|
return c.lastHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certify handles this with
|
// Certify will verify whether the commit is valid and will update the height if it is or return an
|
||||||
|
// error if it is not.
|
||||||
func (c *Dynamic) Certify(check Commit) error {
|
func (c *Dynamic) Certify(check Commit) error {
|
||||||
err := c.cert.Certify(check)
|
err := c.cert.Certify(check)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -63,7 +69,7 @@ func (c *Dynamic) Update(fc FullCommit) error {
|
|||||||
// ignore all checkpoints in the past -> only to the future
|
// ignore all checkpoints in the past -> only to the future
|
||||||
h := fc.Height()
|
h := fc.Height()
|
||||||
if h <= c.lastHeight {
|
if h <= c.lastHeight {
|
||||||
return certerr.ErrPastTime()
|
return lightErr.ErrPastTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
// first, verify if the input is self-consistent....
|
// first, verify if the input is self-consistent....
|
||||||
@ -79,7 +85,7 @@ func (c *Dynamic) Update(fc FullCommit) error {
|
|||||||
err = c.Validators().VerifyCommitAny(fc.Validators, c.ChainID(),
|
err = c.Validators().VerifyCommitAny(fc.Validators, c.ChainID(),
|
||||||
commit.BlockID, h, commit)
|
commit.BlockID, h, commit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return certerr.ErrTooMuchChange()
|
return lightErr.ErrTooMuchChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
// looks good, we can update
|
// looks good, we can update
|
@ -1,4 +1,4 @@
|
|||||||
package certifiers_test
|
package light_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -8,8 +8,8 @@ import (
|
|||||||
|
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
"github.com/tendermint/tendermint/certifiers/errors"
|
"github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestDynamicCert just makes sure it still works like StaticCert
|
// TestDynamicCert just makes sure it still works like StaticCert
|
||||||
@ -18,15 +18,15 @@ func TestDynamicCert(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
// require := require.New(t)
|
// require := require.New(t)
|
||||||
|
|
||||||
keys := certifiers.GenValKeys(4)
|
keys := light.GenValKeys(4)
|
||||||
// 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
|
// 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
|
||||||
vals := keys.ToValidators(20, 10)
|
vals := keys.ToValidators(20, 10)
|
||||||
// and a certifier based on our known set
|
// and a certifier based on our known set
|
||||||
chainID := "test-dyno"
|
chainID := "test-dyno"
|
||||||
cert := certifiers.NewDynamic(chainID, vals, 0)
|
cert := light.NewDynamic(chainID, vals, 0)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
keys certifiers.ValKeys
|
keys light.ValKeys
|
||||||
vals *types.ValidatorSet
|
vals *types.ValidatorSet
|
||||||
height int
|
height int
|
||||||
first, last int // who actually signs
|
first, last int // who actually signs
|
||||||
@ -65,9 +65,9 @@ func TestDynamicUpdate(t *testing.T) {
|
|||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
|
|
||||||
chainID := "test-dyno-up"
|
chainID := "test-dyno-up"
|
||||||
keys := certifiers.GenValKeys(5)
|
keys := light.GenValKeys(5)
|
||||||
vals := keys.ToValidators(20, 0)
|
vals := keys.ToValidators(20, 0)
|
||||||
cert := certifiers.NewDynamic(chainID, vals, 40)
|
cert := light.NewDynamic(chainID, vals, 40)
|
||||||
|
|
||||||
// one valid block to give us a sense of time
|
// one valid block to give us a sense of time
|
||||||
h := 100
|
h := 100
|
||||||
@ -81,7 +81,7 @@ func TestDynamicUpdate(t *testing.T) {
|
|||||||
|
|
||||||
// we try to update with some blocks
|
// we try to update with some blocks
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
keys certifiers.ValKeys
|
keys light.ValKeys
|
||||||
vals *types.ValidatorSet
|
vals *types.ValidatorSet
|
||||||
height int
|
height int
|
||||||
first, last int // who actually signs
|
first, last int // who actually signs
|
@ -19,34 +19,39 @@ func IsCommitNotFoundErr(err error) bool {
|
|||||||
return err != nil && (errors.Cause(err) == errCommitNotFound)
|
return err != nil && (errors.Cause(err) == errCommitNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrCommitNotFound indicates that a the requested commit was not found.
|
||||||
func ErrCommitNotFound() error {
|
func ErrCommitNotFound() error {
|
||||||
return errors.WithStack(errCommitNotFound)
|
return errors.WithStack(errCommitNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValidatorsChangedErr checks whether an error is due
|
// IsValidatorsChangedErr checks whether an error is due
|
||||||
// to a differing validator set
|
// to a differing validator set.
|
||||||
func IsValidatorsChangedErr(err error) bool {
|
func IsValidatorsChangedErr(err error) bool {
|
||||||
return err != nil && (errors.Cause(err) == errValidatorsChanged)
|
return err != nil && (errors.Cause(err) == errValidatorsChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrValidatorsChanged indicates that the validator set was changed between two commits.
|
||||||
func ErrValidatorsChanged() error {
|
func ErrValidatorsChanged() error {
|
||||||
return errors.WithStack(errValidatorsChanged)
|
return errors.WithStack(errValidatorsChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTooMuchChangeErr checks whether an error is due to too much change
|
// IsTooMuchChangeErr checks whether an error is due to too much change
|
||||||
// between these validators sets
|
// between these validators sets.
|
||||||
func IsTooMuchChangeErr(err error) bool {
|
func IsTooMuchChangeErr(err error) bool {
|
||||||
return err != nil && (errors.Cause(err) == errTooMuchChange)
|
return err != nil && (errors.Cause(err) == errTooMuchChange)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrTooMuchChange indicates that the underlying validator set was changed by >1/3.
|
||||||
func ErrTooMuchChange() error {
|
func ErrTooMuchChange() error {
|
||||||
return errors.WithStack(errTooMuchChange)
|
return errors.WithStack(errTooMuchChange)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsPastTimeErr ...
|
||||||
func IsPastTimeErr(err error) bool {
|
func IsPastTimeErr(err error) bool {
|
||||||
return err != nil && (errors.Cause(err) == errPastTime)
|
return err != nil && (errors.Cause(err) == errPastTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrPastTime ...
|
||||||
func ErrPastTime() error {
|
func ErrPastTime() error {
|
||||||
return errors.WithStack(errPastTime)
|
return errors.WithStack(errPastTime)
|
||||||
}
|
}
|
||||||
@ -57,6 +62,7 @@ func IsNoPathFoundErr(err error) bool {
|
|||||||
return err != nil && (errors.Cause(err) == errNoPathFound)
|
return err != nil && (errors.Cause(err) == errNoPathFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrNoPathFound ...
|
||||||
func ErrNoPathFound() error {
|
func ErrNoPathFound() error {
|
||||||
return errors.WithStack(errNoPathFound)
|
return errors.WithStack(errNoPathFound)
|
||||||
}
|
}
|
@ -8,8 +8,8 @@ import (
|
|||||||
|
|
||||||
wire "github.com/tendermint/go-wire"
|
wire "github.com/tendermint/go-wire"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -20,7 +20,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// SaveFullCommit exports the seed in binary / go-wire style
|
// SaveFullCommit exports the seed in binary / go-wire style
|
||||||
func SaveFullCommit(fc certifiers.FullCommit, path string) error {
|
func SaveFullCommit(fc light.FullCommit, path string) error {
|
||||||
f, err := os.Create(path)
|
f, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
@ -33,7 +33,7 @@ func SaveFullCommit(fc certifiers.FullCommit, path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveFullCommitJSON exports the seed in a json format
|
// SaveFullCommitJSON exports the seed in a json format
|
||||||
func SaveFullCommitJSON(fc certifiers.FullCommit, path string) error {
|
func SaveFullCommitJSON(fc light.FullCommit, path string) error {
|
||||||
f, err := os.Create(path)
|
f, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
@ -44,12 +44,13 @@ func SaveFullCommitJSON(fc certifiers.FullCommit, path string) error {
|
|||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadFullCommit(path string) (certifiers.FullCommit, error) {
|
// LoadFullCommit loads the full commit from the file system.
|
||||||
var fc certifiers.FullCommit
|
func LoadFullCommit(path string) (light.FullCommit, error) {
|
||||||
|
var fc light.FullCommit
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return fc, certerr.ErrCommitNotFound()
|
return fc, lightErr.ErrCommitNotFound()
|
||||||
}
|
}
|
||||||
return fc, errors.WithStack(err)
|
return fc, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
@ -60,12 +61,13 @@ func LoadFullCommit(path string) (certifiers.FullCommit, error) {
|
|||||||
return fc, errors.WithStack(err)
|
return fc, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadFullCommitJSON(path string) (certifiers.FullCommit, error) {
|
// LoadFullCommitJSON loads the commit from the file system in JSON format.
|
||||||
var fc certifiers.FullCommit
|
func LoadFullCommitJSON(path string) (light.FullCommit, error) {
|
||||||
|
var fc light.FullCommit
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return fc, certerr.ErrCommitNotFound()
|
return fc, lightErr.ErrCommitNotFound()
|
||||||
}
|
}
|
||||||
return fc, errors.WithStack(err)
|
return fc, errors.WithStack(err)
|
||||||
}
|
}
|
@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
)
|
)
|
||||||
|
|
||||||
func tmpFile() string {
|
func tmpFile() string {
|
||||||
@ -27,7 +27,7 @@ func TestSerializeFullCommits(t *testing.T) {
|
|||||||
h := 25
|
h := 25
|
||||||
|
|
||||||
// build a fc
|
// build a fc
|
||||||
keys := certifiers.GenValKeys(5)
|
keys := light.GenValKeys(5)
|
||||||
vals := keys.ToValidators(10, 0)
|
vals := keys.ToValidators(10, 0)
|
||||||
fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, 5)
|
fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, 5)
|
||||||
|
|
@ -24,10 +24,11 @@ import (
|
|||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// nolint
|
||||||
const (
|
const (
|
||||||
Ext = ".tsd"
|
Ext = ".tsd"
|
||||||
ValDir = "validators"
|
ValDir = "validators"
|
||||||
@ -43,7 +44,7 @@ type provider struct {
|
|||||||
|
|
||||||
// NewProvider creates the parent dir and subdirs
|
// NewProvider creates the parent dir and subdirs
|
||||||
// for validators and checkpoints as needed
|
// for validators and checkpoints as needed
|
||||||
func NewProvider(dir string) certifiers.Provider {
|
func NewProvider(dir string) light.Provider {
|
||||||
valDir := filepath.Join(dir, ValDir)
|
valDir := filepath.Join(dir, ValDir)
|
||||||
checkDir := filepath.Join(dir, CheckDir)
|
checkDir := filepath.Join(dir, CheckDir)
|
||||||
for _, d := range []string{valDir, checkDir} {
|
for _, d := range []string{valDir, checkDir} {
|
||||||
@ -64,7 +65,8 @@ func (p *provider) encodeHeight(h int) string {
|
|||||||
return fmt.Sprintf("%012d%s", h, Ext)
|
return fmt.Sprintf("%012d%s", h, Ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) StoreCommit(fc certifiers.FullCommit) error {
|
// StoreCommit saves a full commit after it has been verified.
|
||||||
|
func (p *provider) StoreCommit(fc light.FullCommit) error {
|
||||||
// make sure the fc is self-consistent before saving
|
// make sure the fc is self-consistent before saving
|
||||||
err := fc.ValidateBasic(fc.Commit.Header.ChainID)
|
err := fc.ValidateBasic(fc.Commit.Header.ChainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -85,11 +87,12 @@ func (p *provider) StoreCommit(fc certifiers.FullCommit) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) GetByHeight(h int) (certifiers.FullCommit, error) {
|
// GetByHeight returns the closest commit with height <= h.
|
||||||
|
func (p *provider) GetByHeight(h int) (light.FullCommit, error) {
|
||||||
// first we look for exact match, then search...
|
// first we look for exact match, then search...
|
||||||
path := filepath.Join(p.checkDir, p.encodeHeight(h))
|
path := filepath.Join(p.checkDir, p.encodeHeight(h))
|
||||||
fc, err := LoadFullCommit(path)
|
fc, err := LoadFullCommit(path)
|
||||||
if certerr.IsCommitNotFoundErr(err) {
|
if lightErr.IsCommitNotFoundErr(err) {
|
||||||
path, err = p.searchForHeight(h)
|
path, err = p.searchForHeight(h)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fc, err = LoadFullCommit(path)
|
fc, err = LoadFullCommit(path)
|
||||||
@ -98,7 +101,8 @@ func (p *provider) GetByHeight(h int) (certifiers.FullCommit, error) {
|
|||||||
return fc, err
|
return fc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) LatestCommit() (fc certifiers.FullCommit, err error) {
|
// LatestCommit returns the newest commit stored.
|
||||||
|
func (p *provider) LatestCommit() (fc light.FullCommit, err error) {
|
||||||
// Note to future: please update by 2077 to avoid rollover
|
// Note to future: please update by 2077 to avoid rollover
|
||||||
return p.GetByHeight(math.MaxInt32 - 1)
|
return p.GetByHeight(math.MaxInt32 - 1)
|
||||||
}
|
}
|
||||||
@ -121,14 +125,15 @@ func (p *provider) searchForHeight(h int) (string, error) {
|
|||||||
sort.Strings(files)
|
sort.Strings(files)
|
||||||
i := sort.SearchStrings(files, desired)
|
i := sort.SearchStrings(files, desired)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return "", certerr.ErrCommitNotFound()
|
return "", lightErr.ErrCommitNotFound()
|
||||||
}
|
}
|
||||||
found := files[i-1]
|
found := files[i-1]
|
||||||
path := filepath.Join(p.checkDir, found)
|
path := filepath.Join(p.checkDir, found)
|
||||||
return path, errors.WithStack(err)
|
return path, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) GetByHash(hash []byte) (certifiers.FullCommit, error) {
|
// GetByHash returns a commit exactly matching this validator hash.
|
||||||
|
func (p *provider) GetByHash(hash []byte) (light.FullCommit, error) {
|
||||||
path := filepath.Join(p.valDir, p.encodeHash(hash))
|
path := filepath.Join(p.valDir, p.encodeHash(hash))
|
||||||
return LoadFullCommit(path)
|
return LoadFullCommit(path)
|
||||||
}
|
}
|
@ -10,12 +10,12 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
"github.com/tendermint/tendermint/certifiers/files"
|
"github.com/tendermint/tendermint/light/files"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkEqual(stored, loaded certifiers.FullCommit, chainID string) error {
|
func checkEqual(stored, loaded light.FullCommit, chainID string) error {
|
||||||
err := loaded.ValidateBasic(chainID)
|
err := loaded.ValidateBasic(chainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -36,28 +36,28 @@ func TestFileProvider(t *testing.T) {
|
|||||||
|
|
||||||
chainID := "test-files"
|
chainID := "test-files"
|
||||||
appHash := []byte("some-data")
|
appHash := []byte("some-data")
|
||||||
keys := certifiers.GenValKeys(5)
|
keys := light.GenValKeys(5)
|
||||||
count := 10
|
count := 10
|
||||||
|
|
||||||
// make a bunch of seeds...
|
// make a bunch of seeds...
|
||||||
seeds := make([]certifiers.FullCommit, count)
|
seeds := make([]light.FullCommit, count)
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
// two seeds for each validator, to check how we handle dups
|
// two seeds for each validator, to check how we handle dups
|
||||||
// (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ...
|
// (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ...
|
||||||
vals := keys.ToValidators(10, int64(count/2))
|
vals := keys.ToValidators(10, int64(count/2))
|
||||||
h := 20 + 10*i
|
h := 20 + 10*i
|
||||||
check := keys.GenCommit(chainID, h, nil, vals, appHash, 0, 5)
|
check := keys.GenCommit(chainID, h, nil, vals, appHash, 0, 5)
|
||||||
seeds[i] = certifiers.NewFullCommit(check, vals)
|
seeds[i] = light.NewFullCommit(check, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check provider is empty
|
// check provider is empty
|
||||||
seed, err := p.GetByHeight(20)
|
seed, err := p.GetByHeight(20)
|
||||||
require.NotNil(err)
|
require.NotNil(err)
|
||||||
assert.True(certerr.IsCommitNotFoundErr(err))
|
assert.True(lightErr.IsCommitNotFoundErr(err))
|
||||||
|
|
||||||
seed, err = p.GetByHash(seeds[3].ValidatorsHash())
|
seed, err = p.GetByHash(seeds[3].ValidatorsHash())
|
||||||
require.NotNil(err)
|
require.NotNil(err)
|
||||||
assert.True(certerr.IsCommitNotFoundErr(err))
|
assert.True(lightErr.IsCommitNotFoundErr(err))
|
||||||
|
|
||||||
// now add them all to the provider
|
// now add them all to the provider
|
||||||
for _, s := range seeds {
|
for _, s := range seeds {
|
||||||
@ -92,5 +92,5 @@ func TestFileProvider(t *testing.T) {
|
|||||||
// and proper error for too low
|
// and proper error for too low
|
||||||
_, err = p.GetByHeight(5)
|
_, err = p.GetByHeight(5)
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
assert.True(certerr.IsCommitNotFoundErr(err))
|
assert.True(lightErr.IsCommitNotFoundErr(err))
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package certifiers
|
package light
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
@ -12,14 +12,14 @@ import (
|
|||||||
//
|
//
|
||||||
// It lets us simulate signing with many keys, either ed25519 or secp256k1.
|
// It lets us simulate signing with many keys, either ed25519 or secp256k1.
|
||||||
// The main use case is to create a set, and call GenCommit
|
// The main use case is to create a set, and call GenCommit
|
||||||
// to get propely signed header for testing.
|
// to get properly signed header for testing.
|
||||||
//
|
//
|
||||||
// You can set different weights of validators each time you call
|
// You can set different weights of validators each time you call
|
||||||
// ToValidators, and can optionally extend the validator set later
|
// ToValidators, and can optionally extend the validator set later
|
||||||
// with Extend or ExtendSecp
|
// with Extend or ExtendSecp
|
||||||
type ValKeys []crypto.PrivKey
|
type ValKeys []crypto.PrivKey
|
||||||
|
|
||||||
// GenValKeys produces an array of private keys to generate commits
|
// GenValKeys produces an array of private keys to generate commits.
|
||||||
func GenValKeys(n int) ValKeys {
|
func GenValKeys(n int) ValKeys {
|
||||||
res := make(ValKeys, n)
|
res := make(ValKeys, n)
|
||||||
for i := range res {
|
for i := range res {
|
||||||
@ -28,7 +28,7 @@ func GenValKeys(n int) ValKeys {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change replaces the key at index i
|
// Change replaces the key at index i.
|
||||||
func (v ValKeys) Change(i int) ValKeys {
|
func (v ValKeys) Change(i int) ValKeys {
|
||||||
res := make(ValKeys, len(v))
|
res := make(ValKeys, len(v))
|
||||||
copy(res, v)
|
copy(res, v)
|
||||||
@ -36,13 +36,13 @@ func (v ValKeys) Change(i int) ValKeys {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend adds n more keys (to remove, just take a slice)
|
// Extend adds n more keys (to remove, just take a slice).
|
||||||
func (v ValKeys) Extend(n int) ValKeys {
|
func (v ValKeys) Extend(n int) ValKeys {
|
||||||
extra := GenValKeys(n)
|
extra := GenValKeys(n)
|
||||||
return append(v, extra...)
|
return append(v, extra...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenSecpValKeys produces an array of secp256k1 private keys to generate commits
|
// GenSecpValKeys produces an array of secp256k1 private keys to generate commits.
|
||||||
func GenSecpValKeys(n int) ValKeys {
|
func GenSecpValKeys(n int) ValKeys {
|
||||||
res := make(ValKeys, n)
|
res := make(ValKeys, n)
|
||||||
for i := range res {
|
for i := range res {
|
||||||
@ -51,7 +51,7 @@ func GenSecpValKeys(n int) ValKeys {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtendSecp adds n more secp256k1 keys (to remove, just take a slice)
|
// ExtendSecp adds n more secp256k1 keys (to remove, just take a slice).
|
||||||
func (v ValKeys) ExtendSecp(n int) ValKeys {
|
func (v ValKeys) ExtendSecp(n int) ValKeys {
|
||||||
extra := GenSecpValKeys(n)
|
extra := GenSecpValKeys(n)
|
||||||
return append(v, extra...)
|
return append(v, extra...)
|
||||||
@ -60,7 +60,7 @@ func (v ValKeys) ExtendSecp(n int) ValKeys {
|
|||||||
// ToValidators produces a list of validators from the set of keys
|
// ToValidators produces a list of validators from the set of keys
|
||||||
// The first key has weight `init` and it increases by `inc` every step
|
// The first key has weight `init` and it increases by `inc` every step
|
||||||
// so we can have all the same weight, or a simple linear distribution
|
// so we can have all the same weight, or a simple linear distribution
|
||||||
// (should be enough for testing)
|
// (should be enough for testing).
|
||||||
func (v ValKeys) ToValidators(init, inc int64) *types.ValidatorSet {
|
func (v ValKeys) ToValidators(init, inc int64) *types.ValidatorSet {
|
||||||
res := make([]*types.Validator, len(v))
|
res := make([]*types.Validator, len(v))
|
||||||
for i, k := range v {
|
for i, k := range v {
|
||||||
@ -69,7 +69,7 @@ func (v ValKeys) ToValidators(init, inc int64) *types.ValidatorSet {
|
|||||||
return types.NewValidatorSet(res)
|
return types.NewValidatorSet(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// signHeader properly signs the header with all keys from first to last exclusive
|
// signHeader properly signs the header with all keys from first to last exclusive.
|
||||||
func (v ValKeys) signHeader(header *types.Header, first, last int) *types.Commit {
|
func (v ValKeys) signHeader(header *types.Header, first, last int) *types.Commit {
|
||||||
votes := make([]*types.Vote, len(v))
|
votes := make([]*types.Vote, len(v))
|
||||||
|
|
||||||
@ -106,6 +106,8 @@ func makeVote(header *types.Header, vals *types.ValidatorSet, key crypto.PrivKey
|
|||||||
return vote
|
return vote
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Silences warning that vals can also be merkle.Hashable
|
||||||
|
// nolint: interfacer
|
||||||
func genHeader(chainID string, height int, txs types.Txs,
|
func genHeader(chainID string, height int, txs types.Txs,
|
||||||
vals *types.ValidatorSet, appHash []byte) *types.Header {
|
vals *types.ValidatorSet, appHash []byte) *types.Header {
|
||||||
|
|
||||||
@ -122,7 +124,7 @@ func genHeader(chainID string, height int, txs types.Txs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenCommit calls genHeader and signHeader and combines them into a Commit
|
// GenCommit calls genHeader and signHeader and combines them into a Commit.
|
||||||
func (v ValKeys) GenCommit(chainID string, height int, txs types.Txs,
|
func (v ValKeys) GenCommit(chainID string, height int, txs types.Txs,
|
||||||
vals *types.ValidatorSet, appHash []byte, first, last int) Commit {
|
vals *types.ValidatorSet, appHash []byte, first, last int) Commit {
|
||||||
|
|
||||||
@ -134,7 +136,7 @@ func (v ValKeys) GenCommit(chainID string, height int, txs types.Txs,
|
|||||||
return check
|
return check
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenFullCommit calls genHeader and signHeader and combines them into a Commit
|
// GenFullCommit calls genHeader and signHeader and combines them into a Commit.
|
||||||
func (v ValKeys) GenFullCommit(chainID string, height int, txs types.Txs,
|
func (v ValKeys) GenFullCommit(chainID string, height int, txs types.Txs,
|
||||||
vals *types.ValidatorSet, appHash []byte, first, last int) FullCommit {
|
vals *types.ValidatorSet, appHash []byte, first, last int) FullCommit {
|
||||||
|
|
@ -1,11 +1,15 @@
|
|||||||
package certifiers
|
package light
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Inquiring wraps a dynamic certifier and implements an auto-update strategy. If a call to Certify
|
||||||
|
// fails due to a change it validator set, Inquiring will try and find a previous FullCommit which
|
||||||
|
// it can use to safely update the validator set. It uses a source provider to obtain the needed
|
||||||
|
// FullCommits. It stores properly validated data on the local system.
|
||||||
type Inquiring struct {
|
type Inquiring struct {
|
||||||
cert *Dynamic
|
cert *Dynamic
|
||||||
// These are only properly validated data, from local system
|
// These are only properly validated data, from local system
|
||||||
@ -14,8 +18,14 @@ type Inquiring struct {
|
|||||||
Source Provider
|
Source Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInquiring returns a new Inquiring object. It uses the trusted provider to store validated
|
||||||
|
// data and the source provider to obtain missing FullCommits.
|
||||||
|
//
|
||||||
|
// Example: The trusted provider should a CacheProvider, MemProvider or files.Provider. The source
|
||||||
|
// provider should be a client.HTTPProvider.
|
||||||
func NewInquiring(chainID string, fc FullCommit, trusted Provider, source Provider) *Inquiring {
|
func NewInquiring(chainID string, fc FullCommit, trusted Provider, source Provider) *Inquiring {
|
||||||
// store the data in trusted
|
// store the data in trusted
|
||||||
|
// TODO: StoredCommit() can return an error and we need to handle this.
|
||||||
trusted.StoreCommit(fc)
|
trusted.StoreCommit(fc)
|
||||||
|
|
||||||
return &Inquiring{
|
return &Inquiring{
|
||||||
@ -25,14 +35,17 @@ func NewInquiring(chainID string, fc FullCommit, trusted Provider, source Provid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChainID returns the chain id.
|
||||||
func (c *Inquiring) ChainID() string {
|
func (c *Inquiring) ChainID() string {
|
||||||
return c.cert.ChainID()
|
return c.cert.ChainID()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validators returns the validator set.
|
||||||
func (c *Inquiring) Validators() *types.ValidatorSet {
|
func (c *Inquiring) Validators() *types.ValidatorSet {
|
||||||
return c.cert.cert.vSet
|
return c.cert.cert.vSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LastHeight returns the last height.
|
||||||
func (c *Inquiring) LastHeight() int {
|
func (c *Inquiring) LastHeight() int {
|
||||||
return c.cert.lastHeight
|
return c.cert.lastHeight
|
||||||
}
|
}
|
||||||
@ -50,7 +63,7 @@ func (c *Inquiring) Certify(commit Commit) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = c.cert.Certify(commit)
|
err = c.cert.Certify(commit)
|
||||||
if !certerr.IsValidatorsChangedErr(err) {
|
if !lightErr.IsValidatorsChangedErr(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = c.updateToHash(commit.Header.ValidatorsHash)
|
err = c.updateToHash(commit.Header.ValidatorsHash)
|
||||||
@ -64,11 +77,11 @@ func (c *Inquiring) Certify(commit Commit) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// store the new checkpoint
|
// store the new checkpoint
|
||||||
c.trusted.StoreCommit(
|
return c.trusted.StoreCommit(NewFullCommit(commit, c.Validators()))
|
||||||
NewFullCommit(commit, c.Validators()))
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update will verify if this is a valid change and update
|
||||||
|
// the certifying validator set if safe to do so.
|
||||||
func (c *Inquiring) Update(fc FullCommit) error {
|
func (c *Inquiring) Update(fc FullCommit) error {
|
||||||
err := c.useClosestTrust(fc.Height())
|
err := c.useClosestTrust(fc.Height())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -77,7 +90,7 @@ func (c *Inquiring) Update(fc FullCommit) error {
|
|||||||
|
|
||||||
err = c.cert.Update(fc)
|
err = c.cert.Update(fc)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.trusted.StoreCommit(fc)
|
err = c.trusted.StoreCommit(fc)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -106,7 +119,7 @@ func (c *Inquiring) updateToHash(vhash []byte) error {
|
|||||||
}
|
}
|
||||||
err = c.cert.Update(fc)
|
err = c.cert.Update(fc)
|
||||||
// handle IsTooMuchChangeErr by using divide and conquer
|
// handle IsTooMuchChangeErr by using divide and conquer
|
||||||
if certerr.IsTooMuchChangeErr(err) {
|
if lightErr.IsTooMuchChangeErr(err) {
|
||||||
err = c.updateToHeight(fc.Height())
|
err = c.updateToHeight(fc.Height())
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@ -121,12 +134,12 @@ func (c *Inquiring) updateToHeight(h int) error {
|
|||||||
}
|
}
|
||||||
start, end := c.LastHeight(), fc.Height()
|
start, end := c.LastHeight(), fc.Height()
|
||||||
if end <= start {
|
if end <= start {
|
||||||
return certerr.ErrNoPathFound()
|
return lightErr.ErrNoPathFound()
|
||||||
}
|
}
|
||||||
err = c.Update(fc)
|
err = c.Update(fc)
|
||||||
|
|
||||||
// we can handle IsTooMuchChangeErr specially
|
// we can handle IsTooMuchChangeErr specially
|
||||||
if !certerr.IsTooMuchChangeErr(err) {
|
if !lightErr.IsTooMuchChangeErr(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
package certifiers_test
|
// nolint: vetshadow
|
||||||
|
package light_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -7,34 +8,33 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInquirerValidPath(t *testing.T) {
|
func TestInquirerValidPath(t *testing.T) {
|
||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
trust := certifiers.NewMemStoreProvider()
|
trust := light.NewMemStoreProvider()
|
||||||
source := certifiers.NewMemStoreProvider()
|
source := light.NewMemStoreProvider()
|
||||||
|
|
||||||
// set up the validators to generate test blocks
|
// set up the validators to generate test blocks
|
||||||
var vote int64 = 10
|
var vote int64 = 10
|
||||||
keys := certifiers.GenValKeys(5)
|
keys := light.GenValKeys(5)
|
||||||
vals := keys.ToValidators(vote, 0)
|
|
||||||
|
|
||||||
// construct a bunch of commits, each with one more height than the last
|
// construct a bunch of commits, each with one more height than the last
|
||||||
chainID := "inquiry-test"
|
chainID := "inquiry-test"
|
||||||
count := 50
|
count := 50
|
||||||
commits := make([]certifiers.FullCommit, count)
|
commits := make([]light.FullCommit, count)
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
// extend the keys by 1 each time
|
// extend the keys by 1 each time
|
||||||
keys = keys.Extend(1)
|
keys = keys.Extend(1)
|
||||||
vals = keys.ToValidators(vote, 0)
|
vals := keys.ToValidators(vote, 0)
|
||||||
h := 20 + 10*i
|
h := 20 + 10*i
|
||||||
appHash := []byte(fmt.Sprintf("h=%d", h))
|
appHash := []byte(fmt.Sprintf("h=%d", h))
|
||||||
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys))
|
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys))
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize a certifier with the initial state
|
// initialize a certifier with the initial state
|
||||||
cert := certifiers.NewInquiring(chainID, commits[0], trust, source)
|
cert := light.NewInquiring(chainID, commits[0], trust, source)
|
||||||
|
|
||||||
// this should fail validation....
|
// this should fail validation....
|
||||||
commit := commits[count-1].Commit
|
commit := commits[count-1].Commit
|
||||||
@ -60,29 +60,28 @@ func TestInquirerValidPath(t *testing.T) {
|
|||||||
|
|
||||||
func TestInquirerMinimalPath(t *testing.T) {
|
func TestInquirerMinimalPath(t *testing.T) {
|
||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
trust := certifiers.NewMemStoreProvider()
|
trust := light.NewMemStoreProvider()
|
||||||
source := certifiers.NewMemStoreProvider()
|
source := light.NewMemStoreProvider()
|
||||||
|
|
||||||
// set up the validators to generate test blocks
|
// set up the validators to generate test blocks
|
||||||
var vote int64 = 10
|
var vote int64 = 10
|
||||||
keys := certifiers.GenValKeys(5)
|
keys := light.GenValKeys(5)
|
||||||
vals := keys.ToValidators(vote, 0)
|
|
||||||
|
|
||||||
// construct a bunch of commits, each with one more height than the last
|
// construct a bunch of commits, each with one more height than the last
|
||||||
chainID := "minimal-path"
|
chainID := "minimal-path"
|
||||||
count := 12
|
count := 12
|
||||||
commits := make([]certifiers.FullCommit, count)
|
commits := make([]light.FullCommit, count)
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
// extend the validators, so we are just below 2/3
|
// extend the validators, so we are just below 2/3
|
||||||
keys = keys.Extend(len(keys)/2 - 1)
|
keys = keys.Extend(len(keys)/2 - 1)
|
||||||
vals = keys.ToValidators(vote, 0)
|
vals := keys.ToValidators(vote, 0)
|
||||||
h := 5 + 10*i
|
h := 5 + 10*i
|
||||||
appHash := []byte(fmt.Sprintf("h=%d", h))
|
appHash := []byte(fmt.Sprintf("h=%d", h))
|
||||||
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys))
|
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys))
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize a certifier with the initial state
|
// initialize a certifier with the initial state
|
||||||
cert := certifiers.NewInquiring(chainID, commits[0], trust, source)
|
cert := light.NewInquiring(chainID, commits[0], trust, source)
|
||||||
|
|
||||||
// this should fail validation....
|
// this should fail validation....
|
||||||
commit := commits[count-1].Commit
|
commit := commits[count-1].Commit
|
||||||
@ -108,29 +107,28 @@ func TestInquirerMinimalPath(t *testing.T) {
|
|||||||
|
|
||||||
func TestInquirerVerifyHistorical(t *testing.T) {
|
func TestInquirerVerifyHistorical(t *testing.T) {
|
||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
trust := certifiers.NewMemStoreProvider()
|
trust := light.NewMemStoreProvider()
|
||||||
source := certifiers.NewMemStoreProvider()
|
source := light.NewMemStoreProvider()
|
||||||
|
|
||||||
// set up the validators to generate test blocks
|
// set up the validators to generate test blocks
|
||||||
var vote int64 = 10
|
var vote int64 = 10
|
||||||
keys := certifiers.GenValKeys(5)
|
keys := light.GenValKeys(5)
|
||||||
vals := keys.ToValidators(vote, 0)
|
|
||||||
|
|
||||||
// construct a bunch of commits, each with one more height than the last
|
// construct a bunch of commits, each with one more height than the last
|
||||||
chainID := "inquiry-test"
|
chainID := "inquiry-test"
|
||||||
count := 10
|
count := 10
|
||||||
commits := make([]certifiers.FullCommit, count)
|
commits := make([]light.FullCommit, count)
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
// extend the keys by 1 each time
|
// extend the keys by 1 each time
|
||||||
keys = keys.Extend(1)
|
keys = keys.Extend(1)
|
||||||
vals = keys.ToValidators(vote, 0)
|
vals := keys.ToValidators(vote, 0)
|
||||||
h := 20 + 10*i
|
h := 20 + 10*i
|
||||||
appHash := []byte(fmt.Sprintf("h=%d", h))
|
appHash := []byte(fmt.Sprintf("h=%d", h))
|
||||||
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys))
|
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys))
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize a certifier with the initial state
|
// initialize a certifier with the initial state
|
||||||
cert := certifiers.NewInquiring(chainID, commits[0], trust, source)
|
cert := light.NewInquiring(chainID, commits[0], trust, source)
|
||||||
|
|
||||||
// store a few commits as trust
|
// store a few commits as trust
|
||||||
for _, i := range []int{2, 5} {
|
for _, i := range []int{2, 5} {
|
@ -1,10 +1,10 @@
|
|||||||
package certifiers
|
package light
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type memStoreProvider struct {
|
type memStoreProvider struct {
|
||||||
@ -23,6 +23,7 @@ func (s fullCommits) Less(i, j int) bool {
|
|||||||
return s[i].Height() < s[j].Height()
|
return s[i].Height() < s[j].Height()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewMemStoreProvider returns a new in-memory provider.
|
||||||
func NewMemStoreProvider() Provider {
|
func NewMemStoreProvider() Provider {
|
||||||
return &memStoreProvider{
|
return &memStoreProvider{
|
||||||
byHeight: fullCommits{},
|
byHeight: fullCommits{},
|
||||||
@ -34,6 +35,7 @@ func (m *memStoreProvider) encodeHash(hash []byte) string {
|
|||||||
return hex.EncodeToString(hash)
|
return hex.EncodeToString(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StoreCommit stores a FullCommit after verifying it.
|
||||||
func (m *memStoreProvider) StoreCommit(fc FullCommit) error {
|
func (m *memStoreProvider) StoreCommit(fc FullCommit) error {
|
||||||
// make sure the fc is self-consistent before saving
|
// make sure the fc is self-consistent before saving
|
||||||
err := fc.ValidateBasic(fc.Commit.Header.ChainID)
|
err := fc.ValidateBasic(fc.Commit.Header.ChainID)
|
||||||
@ -49,6 +51,7 @@ func (m *memStoreProvider) StoreCommit(fc FullCommit) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByHeight returns the FullCommit for height h or an error if the commit is not found.
|
||||||
func (m *memStoreProvider) GetByHeight(h int) (FullCommit, error) {
|
func (m *memStoreProvider) GetByHeight(h int) (FullCommit, error) {
|
||||||
// search from highest to lowest
|
// search from highest to lowest
|
||||||
for i := len(m.byHeight) - 1; i >= 0; i-- {
|
for i := len(m.byHeight) - 1; i >= 0; i-- {
|
||||||
@ -57,22 +60,24 @@ func (m *memStoreProvider) GetByHeight(h int) (FullCommit, error) {
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FullCommit{}, certerr.ErrCommitNotFound()
|
return FullCommit{}, lightErr.ErrCommitNotFound()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByHash returns the FullCommit for the hash or an error if the commit is not found.
|
||||||
func (m *memStoreProvider) GetByHash(hash []byte) (FullCommit, error) {
|
func (m *memStoreProvider) GetByHash(hash []byte) (FullCommit, error) {
|
||||||
var err error
|
var err error
|
||||||
fc, ok := m.byHash[m.encodeHash(hash)]
|
fc, ok := m.byHash[m.encodeHash(hash)]
|
||||||
if !ok {
|
if !ok {
|
||||||
err = certerr.ErrCommitNotFound()
|
err = lightErr.ErrCommitNotFound()
|
||||||
}
|
}
|
||||||
return fc, err
|
return fc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LatestCommit returns the latest FullCommit or an error if no commits exist.
|
||||||
func (m *memStoreProvider) LatestCommit() (FullCommit, error) {
|
func (m *memStoreProvider) LatestCommit() (FullCommit, error) {
|
||||||
l := len(m.byHeight)
|
l := len(m.byHeight)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
return FullCommit{}, certerr.ErrCommitNotFound()
|
return FullCommit{}, lightErr.ErrCommitNotFound()
|
||||||
}
|
}
|
||||||
return m.byHeight[l-1], nil
|
return m.byHeight[l-1], nil
|
||||||
}
|
}
|
@ -1,33 +1,33 @@
|
|||||||
package certifiers_test
|
package light_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkGenCommit20(b *testing.B) {
|
func BenchmarkGenCommit20(b *testing.B) {
|
||||||
keys := certifiers.GenValKeys(20)
|
keys := light.GenValKeys(20)
|
||||||
benchmarkGenCommit(b, keys)
|
benchmarkGenCommit(b, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkGenCommit100(b *testing.B) {
|
func BenchmarkGenCommit100(b *testing.B) {
|
||||||
keys := certifiers.GenValKeys(100)
|
keys := light.GenValKeys(100)
|
||||||
benchmarkGenCommit(b, keys)
|
benchmarkGenCommit(b, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkGenCommitSec20(b *testing.B) {
|
func BenchmarkGenCommitSec20(b *testing.B) {
|
||||||
keys := certifiers.GenSecpValKeys(20)
|
keys := light.GenSecpValKeys(20)
|
||||||
benchmarkGenCommit(b, keys)
|
benchmarkGenCommit(b, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkGenCommitSec100(b *testing.B) {
|
func BenchmarkGenCommitSec100(b *testing.B) {
|
||||||
keys := certifiers.GenSecpValKeys(100)
|
keys := light.GenSecpValKeys(100)
|
||||||
benchmarkGenCommit(b, keys)
|
benchmarkGenCommit(b, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmarkGenCommit(b *testing.B, keys certifiers.ValKeys) {
|
func benchmarkGenCommit(b *testing.B, keys light.ValKeys) {
|
||||||
chainID := fmt.Sprintf("bench-%d", len(keys))
|
chainID := fmt.Sprintf("bench-%d", len(keys))
|
||||||
vals := keys.ToValidators(20, 10)
|
vals := keys.ToValidators(20, 10)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
@ -39,7 +39,7 @@ func benchmarkGenCommit(b *testing.B, keys certifiers.ValKeys) {
|
|||||||
|
|
||||||
// this benchmarks generating one key
|
// this benchmarks generating one key
|
||||||
func BenchmarkGenValKeys(b *testing.B) {
|
func BenchmarkGenValKeys(b *testing.B) {
|
||||||
keys := certifiers.GenValKeys(20)
|
keys := light.GenValKeys(20)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
keys = keys.Extend(1)
|
keys = keys.Extend(1)
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ func BenchmarkGenValKeys(b *testing.B) {
|
|||||||
|
|
||||||
// this benchmarks generating one key
|
// this benchmarks generating one key
|
||||||
func BenchmarkGenSecpValKeys(b *testing.B) {
|
func BenchmarkGenSecpValKeys(b *testing.B) {
|
||||||
keys := certifiers.GenSecpValKeys(20)
|
keys := light.GenSecpValKeys(20)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
keys = keys.Extend(1)
|
keys = keys.Extend(1)
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ func BenchmarkToValidators100(b *testing.B) {
|
|||||||
|
|
||||||
// this benchmarks constructing the validator set (.PubKey() * nodes)
|
// this benchmarks constructing the validator set (.PubKey() * nodes)
|
||||||
func benchmarkToValidators(b *testing.B, nodes int) {
|
func benchmarkToValidators(b *testing.B, nodes int) {
|
||||||
keys := certifiers.GenValKeys(nodes)
|
keys := light.GenValKeys(nodes)
|
||||||
for i := 1; i <= b.N; i++ {
|
for i := 1; i <= b.N; i++ {
|
||||||
keys.ToValidators(int64(2*i), int64(i))
|
keys.ToValidators(int64(2*i), int64(i))
|
||||||
}
|
}
|
||||||
@ -75,36 +75,36 @@ func BenchmarkToValidatorsSec100(b *testing.B) {
|
|||||||
|
|
||||||
// this benchmarks constructing the validator set (.PubKey() * nodes)
|
// this benchmarks constructing the validator set (.PubKey() * nodes)
|
||||||
func benchmarkToValidatorsSec(b *testing.B, nodes int) {
|
func benchmarkToValidatorsSec(b *testing.B, nodes int) {
|
||||||
keys := certifiers.GenSecpValKeys(nodes)
|
keys := light.GenSecpValKeys(nodes)
|
||||||
for i := 1; i <= b.N; i++ {
|
for i := 1; i <= b.N; i++ {
|
||||||
keys.ToValidators(int64(2*i), int64(i))
|
keys.ToValidators(int64(2*i), int64(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCertifyCommit20(b *testing.B) {
|
func BenchmarkCertifyCommit20(b *testing.B) {
|
||||||
keys := certifiers.GenValKeys(20)
|
keys := light.GenValKeys(20)
|
||||||
benchmarkCertifyCommit(b, keys)
|
benchmarkCertifyCommit(b, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCertifyCommit100(b *testing.B) {
|
func BenchmarkCertifyCommit100(b *testing.B) {
|
||||||
keys := certifiers.GenValKeys(100)
|
keys := light.GenValKeys(100)
|
||||||
benchmarkCertifyCommit(b, keys)
|
benchmarkCertifyCommit(b, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCertifyCommitSec20(b *testing.B) {
|
func BenchmarkCertifyCommitSec20(b *testing.B) {
|
||||||
keys := certifiers.GenSecpValKeys(20)
|
keys := light.GenSecpValKeys(20)
|
||||||
benchmarkCertifyCommit(b, keys)
|
benchmarkCertifyCommit(b, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCertifyCommitSec100(b *testing.B) {
|
func BenchmarkCertifyCommitSec100(b *testing.B) {
|
||||||
keys := certifiers.GenSecpValKeys(100)
|
keys := light.GenSecpValKeys(100)
|
||||||
benchmarkCertifyCommit(b, keys)
|
benchmarkCertifyCommit(b, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmarkCertifyCommit(b *testing.B, keys certifiers.ValKeys) {
|
func benchmarkCertifyCommit(b *testing.B, keys light.ValKeys) {
|
||||||
chainID := "bench-certify"
|
chainID := "bench-certify"
|
||||||
vals := keys.ToValidators(20, 10)
|
vals := keys.ToValidators(20, 10)
|
||||||
cert := certifiers.NewStatic(chainID, vals)
|
cert := light.NewStatic(chainID, vals)
|
||||||
check := keys.GenCommit(chainID, 123, nil, vals, []byte("foo"), 0, len(keys))
|
check := keys.GenCommit(chainID, 123, nil, vals, []byte("foo"), 0, len(keys))
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
err := cert.Certify(check)
|
err := cert.Certify(check)
|
@ -1,22 +1,18 @@
|
|||||||
package certifiers
|
package light
|
||||||
|
|
||||||
import (
|
// Provider is used to get more validators by other means.
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Provider is used to get more validators by other means
|
|
||||||
//
|
//
|
||||||
// Examples: MemProvider, files.Provider, client.Provider....
|
// Examples: MemProvider, files.Provider, client.Provider, CacheProvider....
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
// StoreCommit saves a FullCommit after we have verified it,
|
// StoreCommit saves a FullCommit after we have verified it,
|
||||||
// so we can query for it later. Important for updating our
|
// so we can query for it later. Important for updating our
|
||||||
// store of trusted commits
|
// store of trusted commits.
|
||||||
StoreCommit(fc FullCommit) error
|
StoreCommit(fc FullCommit) error
|
||||||
// GetByHeight returns the closest commit with height <= h
|
// GetByHeight returns the closest commit with height <= h.
|
||||||
GetByHeight(h int) (FullCommit, error)
|
GetByHeight(h int) (FullCommit, error)
|
||||||
// GetByHash returns a commit exactly matching this validator hash
|
// GetByHash returns a commit exactly matching this validator hash.
|
||||||
GetByHash(hash []byte) (FullCommit, error)
|
GetByHash(hash []byte) (FullCommit, error)
|
||||||
// LatestCommit returns the newest commit stored
|
// LatestCommit returns the newest commit stored.
|
||||||
LatestCommit() (FullCommit, error)
|
LatestCommit() (FullCommit, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,6 +24,7 @@ type cacheProvider struct {
|
|||||||
Providers []Provider
|
Providers []Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCacheProvider returns a new provider which wraps multiple other providers.
|
||||||
func NewCacheProvider(providers ...Provider) Provider {
|
func NewCacheProvider(providers ...Provider) Provider {
|
||||||
return cacheProvider{
|
return cacheProvider{
|
||||||
Providers: providers,
|
Providers: providers,
|
||||||
@ -47,19 +44,17 @@ func (c cacheProvider) StoreCommit(fc FullCommit) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// GetByHeight should return the closest possible match from all providers.
|
||||||
GetByHeight should return the closest possible match from all providers.
|
//
|
||||||
|
// The Cache is usually organized in order from cheapest call (memory)
|
||||||
The Cache is usually organized in order from cheapest call (memory)
|
// to most expensive calls (disk/network). However, since GetByHeight returns
|
||||||
to most expensive calls (disk/network). However, since GetByHeight returns
|
// a FullCommit at h' <= h, if the memory has a seed at h-10, but the network would
|
||||||
a FullCommit at h' <= h, if the memory has a seed at h-10, but the network would
|
// give us the exact match, a naive "stop at first non-error" would hide
|
||||||
give us the exact match, a naive "stop at first non-error" would hide
|
// the actual desired results.
|
||||||
the actual desired results.
|
//
|
||||||
|
// Thus, we query each provider in order until we find an exact match
|
||||||
Thus, we query each provider in order until we find an exact match
|
// or we finished querying them all. If at least one returned a non-error,
|
||||||
or we finished querying them all. If at least one returned a non-error,
|
// then this returns the best match (minimum h-h').
|
||||||
then this returns the best match (minimum h-h').
|
|
||||||
*/
|
|
||||||
func (c cacheProvider) GetByHeight(h int) (fc FullCommit, err error) {
|
func (c cacheProvider) GetByHeight(h int) (fc FullCommit, err error) {
|
||||||
for _, p := range c.Providers {
|
for _, p := range c.Providers {
|
||||||
var tfc FullCommit
|
var tfc FullCommit
|
||||||
@ -80,6 +75,7 @@ func (c cacheProvider) GetByHeight(h int) (fc FullCommit, err error) {
|
|||||||
return fc, err
|
return fc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByHash returns the FullCommit for the hash or an error if the commit is not found.
|
||||||
func (c cacheProvider) GetByHash(hash []byte) (fc FullCommit, err error) {
|
func (c cacheProvider) GetByHash(hash []byte) (fc FullCommit, err error) {
|
||||||
for _, p := range c.Providers {
|
for _, p := range c.Providers {
|
||||||
fc, err = p.GetByHash(hash)
|
fc, err = p.GetByHash(hash)
|
||||||
@ -90,6 +86,7 @@ func (c cacheProvider) GetByHash(hash []byte) (fc FullCommit, err error) {
|
|||||||
return fc, err
|
return fc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LatestCommit returns the latest FullCommit or an error if no commit exists.
|
||||||
func (c cacheProvider) LatestCommit() (fc FullCommit, err error) {
|
func (c cacheProvider) LatestCommit() (fc FullCommit, err error) {
|
||||||
for _, p := range c.Providers {
|
for _, p := range c.Providers {
|
||||||
var tfc FullCommit
|
var tfc FullCommit
|
||||||
@ -104,22 +101,3 @@ func (c cacheProvider) LatestCommit() (fc FullCommit, err error) {
|
|||||||
}
|
}
|
||||||
return fc, err
|
return fc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// missingProvider doens't store anything, always a miss
|
|
||||||
// Designed as a mock for testing
|
|
||||||
type missingProvider struct{}
|
|
||||||
|
|
||||||
func NewMissingProvider() Provider {
|
|
||||||
return missingProvider{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (missingProvider) StoreCommit(_ FullCommit) error { return nil }
|
|
||||||
func (missingProvider) GetByHeight(_ int) (FullCommit, error) {
|
|
||||||
return FullCommit{}, certerr.ErrCommitNotFound()
|
|
||||||
}
|
|
||||||
func (missingProvider) GetByHash(_ []byte) (FullCommit, error) {
|
|
||||||
return FullCommit{}, certerr.ErrCommitNotFound()
|
|
||||||
}
|
|
||||||
func (missingProvider) LatestCommit() (FullCommit, error) {
|
|
||||||
return FullCommit{}, certerr.ErrCommitNotFound()
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
package certifiers_test
|
// nolint: vetshadow
|
||||||
|
package light_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -6,32 +7,52 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
light "github.com/tendermint/tendermint/light"
|
||||||
"github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// missingProvider doens't store anything, always a miss
|
||||||
|
// Designed as a mock for testing
|
||||||
|
type missingProvider struct{}
|
||||||
|
|
||||||
|
// NewMissingProvider returns a provider which does not store anything and always misses.
|
||||||
|
func NewMissingProvider() light.Provider {
|
||||||
|
return missingProvider{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (missingProvider) StoreCommit(_ light.FullCommit) error { return nil }
|
||||||
|
func (missingProvider) GetByHeight(_ int) (light.FullCommit, error) {
|
||||||
|
return light.FullCommit{}, lightErr.ErrCommitNotFound()
|
||||||
|
}
|
||||||
|
func (missingProvider) GetByHash(_ []byte) (light.FullCommit, error) {
|
||||||
|
return light.FullCommit{}, lightErr.ErrCommitNotFound()
|
||||||
|
}
|
||||||
|
func (missingProvider) LatestCommit() (light.FullCommit, error) {
|
||||||
|
return light.FullCommit{}, lightErr.ErrCommitNotFound()
|
||||||
|
}
|
||||||
|
|
||||||
func TestMemProvider(t *testing.T) {
|
func TestMemProvider(t *testing.T) {
|
||||||
p := certifiers.NewMemStoreProvider()
|
p := light.NewMemStoreProvider()
|
||||||
checkProvider(t, p, "test-mem", "empty")
|
checkProvider(t, p, "test-mem", "empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheProvider(t *testing.T) {
|
func TestCacheProvider(t *testing.T) {
|
||||||
p := certifiers.NewCacheProvider(
|
p := light.NewCacheProvider(
|
||||||
certifiers.NewMissingProvider(),
|
NewMissingProvider(),
|
||||||
certifiers.NewMemStoreProvider(),
|
light.NewMemStoreProvider(),
|
||||||
certifiers.NewMissingProvider(),
|
NewMissingProvider(),
|
||||||
)
|
)
|
||||||
checkProvider(t, p, "test-cache", "kjfhekfhkewhgit")
|
checkProvider(t, p, "test-cache", "kjfhekfhkewhgit")
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkProvider(t *testing.T, p certifiers.Provider, chainID, app string) {
|
func checkProvider(t *testing.T, p light.Provider, chainID, app string) {
|
||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
appHash := []byte(app)
|
appHash := []byte(app)
|
||||||
keys := certifiers.GenValKeys(5)
|
keys := light.GenValKeys(5)
|
||||||
count := 10
|
count := 10
|
||||||
|
|
||||||
// make a bunch of commits...
|
// make a bunch of commits...
|
||||||
commits := make([]certifiers.FullCommit, count)
|
commits := make([]light.FullCommit, count)
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
// two commits for each validator, to check how we handle dups
|
// two commits for each validator, to check how we handle dups
|
||||||
// (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ...
|
// (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ...
|
||||||
@ -43,11 +64,11 @@ func checkProvider(t *testing.T, p certifiers.Provider, chainID, app string) {
|
|||||||
// check provider is empty
|
// check provider is empty
|
||||||
fc, err := p.GetByHeight(20)
|
fc, err := p.GetByHeight(20)
|
||||||
require.NotNil(err)
|
require.NotNil(err)
|
||||||
assert.True(errors.IsCommitNotFoundErr(err))
|
assert.True(lightErr.IsCommitNotFoundErr(err))
|
||||||
|
|
||||||
fc, err = p.GetByHash(commits[3].ValidatorsHash())
|
fc, err = p.GetByHash(commits[3].ValidatorsHash())
|
||||||
require.NotNil(err)
|
require.NotNil(err)
|
||||||
assert.True(errors.IsCommitNotFoundErr(err))
|
assert.True(lightErr.IsCommitNotFoundErr(err))
|
||||||
|
|
||||||
// now add them all to the provider
|
// now add them all to the provider
|
||||||
for _, s := range commits {
|
for _, s := range commits {
|
||||||
@ -80,7 +101,7 @@ func checkProvider(t *testing.T, p certifiers.Provider, chainID, app string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this will make a get height, and if it is good, set the data as well
|
// this will make a get height, and if it is good, set the data as well
|
||||||
func checkGetHeight(t *testing.T, p certifiers.Provider, ask, expect int) {
|
func checkGetHeight(t *testing.T, p light.Provider, ask, expect int) {
|
||||||
fc, err := p.GetByHeight(ask)
|
fc, err := p.GetByHeight(ask)
|
||||||
require.Nil(t, err, "%+v", err)
|
require.Nil(t, err, "%+v", err)
|
||||||
if assert.Equal(t, expect, fc.Height()) {
|
if assert.Equal(t, expect, fc.Height()) {
|
||||||
@ -95,13 +116,13 @@ func TestCacheGetsBestHeight(t *testing.T) {
|
|||||||
|
|
||||||
// we will write data to the second level of the cache (p2),
|
// we will write data to the second level of the cache (p2),
|
||||||
// and see what gets cached, stored in
|
// and see what gets cached, stored in
|
||||||
p := certifiers.NewMemStoreProvider()
|
p := light.NewMemStoreProvider()
|
||||||
p2 := certifiers.NewMemStoreProvider()
|
p2 := light.NewMemStoreProvider()
|
||||||
cp := certifiers.NewCacheProvider(p, p2)
|
cp := light.NewCacheProvider(p, p2)
|
||||||
|
|
||||||
chainID := "cache-best-height"
|
chainID := "cache-best-height"
|
||||||
appHash := []byte("01234567")
|
appHash := []byte("01234567")
|
||||||
keys := certifiers.GenValKeys(5)
|
keys := light.GenValKeys(5)
|
||||||
count := 10
|
count := 10
|
||||||
|
|
||||||
// set a bunch of commits
|
// set a bunch of commits
|
@ -1,4 +1,4 @@
|
|||||||
package certifiers
|
package light
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
certerr "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Certifier = &Static{}
|
var _ Certifier = &Static{}
|
||||||
@ -25,6 +25,7 @@ type Static struct {
|
|||||||
vhash []byte
|
vhash []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStatic returns a new certifier with a static validator set.
|
||||||
func NewStatic(chainID string, vals *types.ValidatorSet) *Static {
|
func NewStatic(chainID string, vals *types.ValidatorSet) *Static {
|
||||||
return &Static{
|
return &Static{
|
||||||
chainID: chainID,
|
chainID: chainID,
|
||||||
@ -32,14 +33,17 @@ func NewStatic(chainID string, vals *types.ValidatorSet) *Static {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChainID returns the chain id.
|
||||||
func (c *Static) ChainID() string {
|
func (c *Static) ChainID() string {
|
||||||
return c.chainID
|
return c.chainID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validators returns the validator set.
|
||||||
func (c *Static) Validators() *types.ValidatorSet {
|
func (c *Static) Validators() *types.ValidatorSet {
|
||||||
return c.vSet
|
return c.vSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hash returns the hash of the validator set.
|
||||||
func (c *Static) Hash() []byte {
|
func (c *Static) Hash() []byte {
|
||||||
if len(c.vhash) == 0 {
|
if len(c.vhash) == 0 {
|
||||||
c.vhash = c.vSet.Hash()
|
c.vhash = c.vSet.Hash()
|
||||||
@ -47,6 +51,7 @@ func (c *Static) Hash() []byte {
|
|||||||
return c.vhash
|
return c.vhash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Certify makes sure that the commit is valid.
|
||||||
func (c *Static) Certify(commit Commit) error {
|
func (c *Static) Certify(commit Commit) error {
|
||||||
// do basic sanity checks
|
// do basic sanity checks
|
||||||
err := commit.ValidateBasic(c.chainID)
|
err := commit.ValidateBasic(c.chainID)
|
||||||
@ -56,7 +61,7 @@ func (c *Static) Certify(commit Commit) error {
|
|||||||
|
|
||||||
// make sure it has the same validator set we have (static means static)
|
// make sure it has the same validator set we have (static means static)
|
||||||
if !bytes.Equal(c.Hash(), commit.Header.ValidatorsHash) {
|
if !bytes.Equal(c.Hash(), commit.Header.ValidatorsHash) {
|
||||||
return certerr.ErrValidatorsChanged()
|
return lightErr.ErrValidatorsChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
// then make sure we have the proper signatures for this
|
// then make sure we have the proper signatures for this
|
@ -1,4 +1,4 @@
|
|||||||
package certifiers_test
|
package light_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -7,8 +7,8 @@ import (
|
|||||||
|
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/certifiers"
|
"github.com/tendermint/tendermint/light"
|
||||||
errors "github.com/tendermint/tendermint/certifiers/errors"
|
lightErr "github.com/tendermint/tendermint/light/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStaticCert(t *testing.T) {
|
func TestStaticCert(t *testing.T) {
|
||||||
@ -16,15 +16,15 @@ func TestStaticCert(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
// require := require.New(t)
|
// require := require.New(t)
|
||||||
|
|
||||||
keys := certifiers.GenValKeys(4)
|
keys := light.GenValKeys(4)
|
||||||
// 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
|
// 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
|
||||||
vals := keys.ToValidators(20, 10)
|
vals := keys.ToValidators(20, 10)
|
||||||
// and a certifier based on our known set
|
// and a certifier based on our known set
|
||||||
chainID := "test-static"
|
chainID := "test-static"
|
||||||
cert := certifiers.NewStatic(chainID, vals)
|
cert := light.NewStatic(chainID, vals)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
keys certifiers.ValKeys
|
keys light.ValKeys
|
||||||
vals *types.ValidatorSet
|
vals *types.ValidatorSet
|
||||||
height int
|
height int
|
||||||
first, last int // who actually signs
|
first, last int // who actually signs
|
||||||
@ -51,7 +51,7 @@ func TestStaticCert(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
if tc.changed {
|
if tc.changed {
|
||||||
assert.True(errors.IsValidatorsChangedErr(err), "%+v", err)
|
assert.True(lightErr.IsValidatorsChangedErr(err), "%+v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user