Merge branch 'develop' into config

This commit is contained in:
Zach
2018-01-10 14:21:24 +00:00
committed by GitHub
41 changed files with 1110 additions and 404 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ func TestProvider(t *testing.T) {
// let's check this is valid somehow
assert.Nil(seed.ValidateBasic(chainID))
cert := lite.NewStatic(chainID, seed.Validators)
cert := lite.NewStaticCertifier(chainID, seed.Validators)
// historical queries now work :)
lower := sh - 5
+26 -25
View File
@@ -6,9 +6,9 @@ import (
liteErr "github.com/tendermint/tendermint/lite/errors"
)
var _ Certifier = &Dynamic{}
var _ Certifier = (*DynamicCertifier)(nil)
// Dynamic uses a Static for Certify, but adds an
// DynamicCertifier uses a StaticCertifier for Certify, but adds an
// Update method to allow for a change of validators.
//
// You can pass in a FullCommit with another validator set,
@@ -17,46 +17,48 @@ var _ Certifier = &Dynamic{}
// validator set for the next Certify call.
// For security, it will only follow validator set changes
// going forward.
type Dynamic struct {
cert *Static
type DynamicCertifier struct {
cert *StaticCertifier
lastHeight int64
}
// NewDynamic returns a new dynamic certifier.
func NewDynamic(chainID string, vals *types.ValidatorSet, height int64) *Dynamic {
return &Dynamic{
cert: NewStatic(chainID, vals),
func NewDynamicCertifier(chainID string, vals *types.ValidatorSet, height int64) *DynamicCertifier {
return &DynamicCertifier{
cert: NewStaticCertifier(chainID, vals),
lastHeight: height,
}
}
// ChainID returns the chain id of this certifier.
func (c *Dynamic) ChainID() string {
return c.cert.ChainID()
// Implements Certifier.
func (dc *DynamicCertifier) ChainID() string {
return dc.cert.ChainID()
}
// Validators returns the validators of this certifier.
func (c *Dynamic) Validators() *types.ValidatorSet {
return c.cert.vSet
func (dc *DynamicCertifier) Validators() *types.ValidatorSet {
return dc.cert.vSet
}
// Hash returns the hash of this certifier.
func (c *Dynamic) Hash() []byte {
return c.cert.Hash()
func (dc *DynamicCertifier) Hash() []byte {
return dc.cert.Hash()
}
// LastHeight returns the last height of this certifier.
func (c *Dynamic) LastHeight() int64 {
return c.lastHeight
func (dc *DynamicCertifier) LastHeight() int64 {
return dc.lastHeight
}
// 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 {
err := c.cert.Certify(check)
// Implements Certifier.
func (dc *DynamicCertifier) Certify(check Commit) error {
err := dc.cert.Certify(check)
if err == nil {
// update last seen height if input is valid
c.lastHeight = check.Height()
dc.lastHeight = check.Height()
}
return err
}
@@ -65,15 +67,15 @@ func (c *Dynamic) Certify(check Commit) error {
// the certifying validator set if safe to do so.
//
// Returns an error if update is impossible (invalid proof or IsTooMuchChangeErr)
func (c *Dynamic) Update(fc FullCommit) error {
func (dc *DynamicCertifier) Update(fc FullCommit) error {
// ignore all checkpoints in the past -> only to the future
h := fc.Height()
if h <= c.lastHeight {
if h <= dc.lastHeight {
return liteErr.ErrPastTime()
}
// first, verify if the input is self-consistent....
err := fc.ValidateBasic(c.ChainID())
err := fc.ValidateBasic(dc.ChainID())
if err != nil {
return err
}
@@ -82,14 +84,13 @@ func (c *Dynamic) Update(fc FullCommit) error {
// would be approved by the currently known validator set
// as well as the new set
commit := fc.Commit.Commit
err = c.Validators().VerifyCommitAny(fc.Validators, c.ChainID(),
commit.BlockID, h, commit)
err = dc.Validators().VerifyCommitAny(fc.Validators, dc.ChainID(), commit.BlockID, h, commit)
if err != nil {
return liteErr.ErrTooMuchChange()
}
// looks good, we can update
c.cert = NewStatic(c.ChainID(), fc.Validators)
c.lastHeight = h
dc.cert = NewStaticCertifier(dc.ChainID(), fc.Validators)
dc.lastHeight = h
return nil
}
@@ -23,7 +23,7 @@ func TestDynamicCert(t *testing.T) {
vals := keys.ToValidators(20, 10)
// and a certifier based on our known set
chainID := "test-dyno"
cert := lite.NewDynamic(chainID, vals, 0)
cert := lite.NewDynamicCertifier(chainID, vals, 0)
cases := []struct {
keys lite.ValKeys
@@ -67,7 +67,7 @@ func TestDynamicUpdate(t *testing.T) {
chainID := "test-dyno-up"
keys := lite.GenValKeys(5)
vals := keys.ToValidators(20, 0)
cert := lite.NewDynamic(chainID, vals, 40)
cert := lite.NewDynamicCertifier(chainID, vals, 40)
// one valid block to give us a sense of time
h := int64(100)
-155
View File
@@ -1,155 +0,0 @@
package lite
import (
"github.com/tendermint/tendermint/types"
liteErr "github.com/tendermint/tendermint/lite/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 {
cert *Dynamic
// These are only properly validated data, from local system
trusted Provider
// This is a source of new info, like a node rpc, or other import method
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 {
// store the data in trusted
// TODO: StoredCommit() can return an error and we need to handle this.
trusted.StoreCommit(fc)
return &Inquiring{
cert: NewDynamic(chainID, fc.Validators, fc.Height()),
trusted: trusted,
Source: source,
}
}
// ChainID returns the chain id.
func (c *Inquiring) ChainID() string {
return c.cert.ChainID()
}
// Validators returns the validator set.
func (c *Inquiring) Validators() *types.ValidatorSet {
return c.cert.cert.vSet
}
// LastHeight returns the last height.
func (c *Inquiring) LastHeight() int64 {
return c.cert.lastHeight
}
// Certify makes sure this is checkpoint is valid.
//
// If the validators have changed since the last know time, it looks
// for a path to prove the new validators.
//
// On success, it will store the checkpoint in the store for later viewing
func (c *Inquiring) Certify(commit Commit) error {
err := c.useClosestTrust(commit.Height())
if err != nil {
return err
}
err = c.cert.Certify(commit)
if !liteErr.IsValidatorsChangedErr(err) {
return err
}
err = c.updateToHash(commit.Header.ValidatorsHash)
if err != nil {
return err
}
err = c.cert.Certify(commit)
if err != nil {
return err
}
// store the new checkpoint
return c.trusted.StoreCommit(NewFullCommit(commit, c.Validators()))
}
// 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 {
err := c.useClosestTrust(fc.Height())
if err != nil {
return err
}
err = c.cert.Update(fc)
if err == nil {
err = c.trusted.StoreCommit(fc)
}
return err
}
func (c *Inquiring) useClosestTrust(h int64) error {
closest, err := c.trusted.GetByHeight(h)
if err != nil {
return err
}
// if the best seed is not the one we currently use,
// let's just reset the dynamic validator
if closest.Height() != c.LastHeight() {
c.cert = NewDynamic(c.ChainID(), closest.Validators, closest.Height())
}
return nil
}
// updateToHash gets the validator hash we want to update to
// if IsTooMuchChangeErr, we try to find a path by binary search over height
func (c *Inquiring) updateToHash(vhash []byte) error {
// try to get the match, and update
fc, err := c.Source.GetByHash(vhash)
if err != nil {
return err
}
err = c.cert.Update(fc)
// handle IsTooMuchChangeErr by using divide and conquer
if liteErr.IsTooMuchChangeErr(err) {
err = c.updateToHeight(fc.Height())
}
return err
}
// updateToHeight will use divide-and-conquer to find a path to h
func (c *Inquiring) updateToHeight(h int64) error {
// try to update to this height (with checks)
fc, err := c.Source.GetByHeight(h)
if err != nil {
return err
}
start, end := c.LastHeight(), fc.Height()
if end <= start {
return liteErr.ErrNoPathFound()
}
err = c.Update(fc)
// we can handle IsTooMuchChangeErr specially
if !liteErr.IsTooMuchChangeErr(err) {
return err
}
// try to update to mid
mid := (start + end) / 2
err = c.updateToHeight(mid)
if err != nil {
return err
}
// if we made it to mid, we recurse
return c.updateToHeight(h)
}
+163
View File
@@ -0,0 +1,163 @@
package lite
import (
"github.com/tendermint/tendermint/types"
liteErr "github.com/tendermint/tendermint/lite/errors"
)
var _ Certifier = (*InquiringCertifier)(nil)
// InquiringCertifier wraps a dynamic certifier and implements an auto-update strategy. If a call
// to Certify fails due to a change it validator set, InquiringCertifier 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 InquiringCertifier struct {
cert *DynamicCertifier
// These are only properly validated data, from local system
trusted Provider
// This is a source of new info, like a node rpc, or other import method
Source Provider
}
// NewInquiringCertifier 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 NewInquiringCertifier(chainID string, fc FullCommit, trusted Provider,
source Provider) (*InquiringCertifier, error) {
// store the data in trusted
err := trusted.StoreCommit(fc)
if err != nil {
return nil, err
}
return &InquiringCertifier{
cert: NewDynamicCertifier(chainID, fc.Validators, fc.Height()),
trusted: trusted,
Source: source,
}, nil
}
// ChainID returns the chain id.
// Implements Certifier.
func (ic *InquiringCertifier) ChainID() string {
return ic.cert.ChainID()
}
// Validators returns the validator set.
func (ic *InquiringCertifier) Validators() *types.ValidatorSet {
return ic.cert.cert.vSet
}
// LastHeight returns the last height.
func (ic *InquiringCertifier) LastHeight() int64 {
return ic.cert.lastHeight
}
// Certify makes sure this is checkpoint is valid.
//
// If the validators have changed since the last know time, it looks
// for a path to prove the new validators.
//
// On success, it will store the checkpoint in the store for later viewing
// Implements Certifier.
func (ic *InquiringCertifier) Certify(commit Commit) error {
err := ic.useClosestTrust(commit.Height())
if err != nil {
return err
}
err = ic.cert.Certify(commit)
if !liteErr.IsValidatorsChangedErr(err) {
return err
}
err = ic.updateToHash(commit.Header.ValidatorsHash)
if err != nil {
return err
}
err = ic.cert.Certify(commit)
if err != nil {
return err
}
// store the new checkpoint
return ic.trusted.StoreCommit(NewFullCommit(commit, ic.Validators()))
}
// Update will verify if this is a valid change and update
// the certifying validator set if safe to do so.
func (ic *InquiringCertifier) Update(fc FullCommit) error {
err := ic.useClosestTrust(fc.Height())
if err != nil {
return err
}
err = ic.cert.Update(fc)
if err == nil {
err = ic.trusted.StoreCommit(fc)
}
return err
}
func (ic *InquiringCertifier) useClosestTrust(h int64) error {
closest, err := ic.trusted.GetByHeight(h)
if err != nil {
return err
}
// if the best seed is not the one we currently use,
// let's just reset the dynamic validator
if closest.Height() != ic.LastHeight() {
ic.cert = NewDynamicCertifier(ic.ChainID(), closest.Validators, closest.Height())
}
return nil
}
// updateToHash gets the validator hash we want to update to
// if IsTooMuchChangeErr, we try to find a path by binary search over height
func (ic *InquiringCertifier) updateToHash(vhash []byte) error {
// try to get the match, and update
fc, err := ic.Source.GetByHash(vhash)
if err != nil {
return err
}
err = ic.cert.Update(fc)
// handle IsTooMuchChangeErr by using divide and conquer
if liteErr.IsTooMuchChangeErr(err) {
err = ic.updateToHeight(fc.Height())
}
return err
}
// updateToHeight will use divide-and-conquer to find a path to h
func (ic *InquiringCertifier) updateToHeight(h int64) error {
// try to update to this height (with checks)
fc, err := ic.Source.GetByHeight(h)
if err != nil {
return err
}
start, end := ic.LastHeight(), fc.Height()
if end <= start {
return liteErr.ErrNoPathFound()
}
err = ic.Update(fc)
// we can handle IsTooMuchChangeErr specially
if !liteErr.IsTooMuchChangeErr(err) {
return err
}
// try to update to mid
mid := (start + end) / 2
err = ic.updateToHeight(mid)
if err != nil {
return err
}
// if we made it to mid, we recurse
return ic.updateToHeight(h)
}
@@ -32,18 +32,20 @@ func TestInquirerValidPath(t *testing.T) {
vals := keys.ToValidators(vote, 0)
h := int64(20 + 10*i)
appHash := []byte(fmt.Sprintf("h=%d", h))
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0, len(keys))
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0,
len(keys))
}
// initialize a certifier with the initial state
cert := lite.NewInquiring(chainID, commits[0], trust, source)
cert, err := lite.NewInquiringCertifier(chainID, commits[0], trust, source)
require.Nil(err)
// this should fail validation....
commit := commits[count-1].Commit
err := cert.Certify(commit)
err = cert.Certify(commit)
require.NotNil(err)
// add a few seed in the middle should be insufficient
// adding a few commits in the middle should be insufficient
for i := 10; i < 13; i++ {
err := source.StoreCommit(commits[i])
require.Nil(err)
@@ -81,11 +83,12 @@ func TestInquirerMinimalPath(t *testing.T) {
h := int64(5 + 10*i)
appHash := []byte(fmt.Sprintf("h=%d", h))
resHash := []byte(fmt.Sprintf("res=%d", h))
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0, len(keys))
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0,
len(keys))
}
// initialize a certifier with the initial state
cert := lite.NewInquiring(chainID, commits[0], trust, source)
cert, _ := lite.NewInquiringCertifier(chainID, commits[0], trust, source)
// this should fail validation....
commit := commits[count-1].Commit
@@ -130,11 +133,12 @@ func TestInquirerVerifyHistorical(t *testing.T) {
h := int64(20 + 10*i)
appHash := []byte(fmt.Sprintf("h=%d", h))
resHash := []byte(fmt.Sprintf("res=%d", h))
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0, len(keys))
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0,
len(keys))
}
// initialize a certifier with the initial state
cert := lite.NewInquiring(chainID, commits[0], trust, source)
cert, _ := lite.NewInquiringCertifier(chainID, commits[0], trust, source)
// store a few commits as trust
for _, i := range []int{2, 5} {
+1 -1
View File
@@ -105,7 +105,7 @@ func BenchmarkCertifyCommitSec100(b *testing.B) {
func benchmarkCertifyCommit(b *testing.B, keys lite.ValKeys) {
chainID := "bench-certify"
vals := keys.ToValidators(20, 10)
cert := lite.NewStatic(chainID, vals)
cert := lite.NewStaticCertifier(chainID, vals)
check := keys.GenCommit(chainID, 123, nil, vals, []byte("foo"), []byte("params"), []byte("res"), 0, len(keys))
for i := 0; i < b.N; i++ {
err := cert.Certify(check)
+7 -2
View File
@@ -6,7 +6,7 @@ import (
"github.com/tendermint/tendermint/lite/files"
)
func GetCertifier(chainID, rootDir, nodeAddr string) (*lite.Inquiring, error) {
func GetCertifier(chainID, rootDir, nodeAddr string) (*lite.InquiringCertifier, error) {
trust := lite.NewCacheProvider(
lite.NewMemStoreProvider(),
files.NewProvider(rootDir),
@@ -25,6 +25,11 @@ func GetCertifier(chainID, rootDir, nodeAddr string) (*lite.Inquiring, error) {
if err != nil {
return nil, err
}
cert := lite.NewInquiring(chainID, fc, trust, source)
cert, err := lite.NewInquiringCertifier(chainID, fc, trust, source)
if err != nil {
return nil, err
}
return cert, nil
}
+6 -2
View File
@@ -18,7 +18,11 @@ const (
// set up the rpc routes to proxy via the given client,
// and start up an http/rpc server on the location given by bind (eg. :1234)
func StartProxy(c rpcclient.Client, listenAddr string, logger log.Logger) error {
c.Start()
err := c.Start()
if err != nil {
return err
}
r := RPCRoutes(c)
// build the handler...
@@ -30,7 +34,7 @@ func StartProxy(c rpcclient.Client, listenAddr string, logger log.Logger) error
core.SetLogger(logger)
mux.HandleFunc(wsEndpoint, wm.WebsocketHandler)
_, err := rpc.StartHTTPServer(listenAddr, mux, logger)
_, err = rpc.StartHTTPServer(listenAddr, mux, logger)
return err
}
+12 -9
View File
@@ -51,7 +51,7 @@ func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOption
// make sure the proof is the proper height
if resp.IsErr() {
err = errors.Errorf("Query error %d: %d", resp.Code)
err = errors.Errorf("Query error for key %d: %d", key, resp.Code)
return nil, nil, err
}
if len(resp.Key) == 0 || len(resp.Proof) == 0 {
@@ -79,7 +79,7 @@ func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOption
if err != nil {
return nil, nil, errors.Wrap(err, "Couldn't verify proof")
}
return &ctypes.ResultABCIQuery{resp}, eproof, nil
return &ctypes.ResultABCIQuery{Response: resp}, eproof, nil
}
// The key wasn't found, construct a proof of non-existence.
@@ -93,13 +93,12 @@ func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOption
if err != nil {
return nil, nil, errors.Wrap(err, "Couldn't verify proof")
}
return &ctypes.ResultABCIQuery{resp}, aproof, ErrNoData()
return &ctypes.ResultABCIQuery{Response: resp}, aproof, ErrNoData()
}
// GetCertifiedCommit gets the signed header for a given height
// and certifies it. Returns error if unable to get a proven header.
func GetCertifiedCommit(h int64, node rpcclient.Client,
cert lite.Certifier) (empty lite.Commit, err error) {
func GetCertifiedCommit(h int64, node rpcclient.Client, cert lite.Certifier) (lite.Commit, error) {
// FIXME: cannot use cert.GetByHeight for now, as it also requires
// Validators and will fail on querying tendermint for non-current height.
@@ -107,14 +106,18 @@ func GetCertifiedCommit(h int64, node rpcclient.Client,
rpcclient.WaitForHeight(node, h, nil)
cresp, err := node.Commit(&h)
if err != nil {
return
return lite.Commit{}, err
}
commit := client.CommitFromResult(cresp)
commit := client.CommitFromResult(cresp)
// validate downloaded checkpoint with our request and trust store.
if commit.Height() != h {
return empty, certerr.ErrHeightMismatch(h, commit.Height())
return lite.Commit{}, certerr.ErrHeightMismatch(h, commit.Height())
}
err = cert.Certify(commit)
if err = cert.Certify(commit); err != nil {
return lite.Commit{}, err
}
return commit, nil
}
+2 -3
View File
@@ -58,7 +58,7 @@ func _TestAppProofs(t *testing.T) {
source := certclient.NewProvider(cl)
seed, err := source.GetByHeight(brh - 2)
require.NoError(err, "%+v", err)
cert := lite.NewStatic("my-chain", seed.Validators)
cert := lite.NewStaticCertifier("my-chain", seed.Validators)
client.WaitForHeight(cl, 3, nil)
latest, err := source.LatestCommit()
@@ -117,7 +117,7 @@ func _TestTxProofs(t *testing.T) {
source := certclient.NewProvider(cl)
seed, err := source.GetByHeight(brh - 2)
require.NoError(err, "%+v", err)
cert := lite.NewStatic("my-chain", seed.Validators)
cert := lite.NewStaticCertifier("my-chain", seed.Validators)
// First let's make sure a bogus transaction hash returns a valid non-existence proof.
key := types.Tx([]byte("bogus")).Hash()
@@ -136,5 +136,4 @@ func _TestTxProofs(t *testing.T) {
commit, err := GetCertifiedCommit(br.Height, cl, cert)
require.Nil(err, "%+v", err)
require.Equal(res.Proof.RootHash, commit.Header.DataHash)
}
+5 -3
View File
@@ -15,14 +15,14 @@ var _ rpcclient.Client = Wrapper{}
// provable before passing it along. Allows you to make any rpcclient fully secure.
type Wrapper struct {
rpcclient.Client
cert *lite.Inquiring
cert *lite.InquiringCertifier
}
// SecureClient uses a given certifier to wrap an connection to an untrusted
// host and return a cryptographically secure rpc client.
//
// If it is wrapping an HTTP rpcclient, it will also wrap the websocket interface
func SecureClient(c rpcclient.Client, cert *lite.Inquiring) Wrapper {
func SecureClient(c rpcclient.Client, cert *lite.InquiringCertifier) Wrapper {
wrap := Wrapper{c, cert}
// TODO: no longer possible as no more such interface exposed....
// if we wrap http client, then we can swap out the event switch to filter
@@ -34,7 +34,9 @@ func SecureClient(c rpcclient.Client, cert *lite.Inquiring) Wrapper {
}
// ABCIQueryWithOptions exposes all options for the ABCI query and verifies the returned proof
func (w Wrapper) ABCIQueryWithOptions(path string, data data.Bytes, opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
func (w Wrapper) ABCIQueryWithOptions(path string, data data.Bytes,
opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
res, _, err := GetWithProofOptions(path, data, opts, w.Client, w.cert)
return res, err
}
+20 -18
View File
@@ -10,62 +10,64 @@ import (
liteErr "github.com/tendermint/tendermint/lite/errors"
)
var _ Certifier = &Static{}
var _ Certifier = (*StaticCertifier)(nil)
// Static assumes a static set of validators, set on
// StaticCertifier assumes a static set of validators, set on
// initilization and checks against them.
// The signatures on every header is checked for > 2/3 votes
// against the known validator set upon Certify
//
// Good for testing or really simple chains. Building block
// to support real-world functionality.
type Static struct {
type StaticCertifier struct {
chainID string
vSet *types.ValidatorSet
vhash []byte
}
// NewStatic returns a new certifier with a static validator set.
func NewStatic(chainID string, vals *types.ValidatorSet) *Static {
return &Static{
// NewStaticCertifier returns a new certifier with a static validator set.
func NewStaticCertifier(chainID string, vals *types.ValidatorSet) *StaticCertifier {
return &StaticCertifier{
chainID: chainID,
vSet: vals,
}
}
// ChainID returns the chain id.
func (c *Static) ChainID() string {
return c.chainID
// Implements Certifier.
func (sc *StaticCertifier) ChainID() string {
return sc.chainID
}
// Validators returns the validator set.
func (c *Static) Validators() *types.ValidatorSet {
return c.vSet
func (sc *StaticCertifier) Validators() *types.ValidatorSet {
return sc.vSet
}
// Hash returns the hash of the validator set.
func (c *Static) Hash() []byte {
if len(c.vhash) == 0 {
c.vhash = c.vSet.Hash()
func (sc *StaticCertifier) Hash() []byte {
if len(sc.vhash) == 0 {
sc.vhash = sc.vSet.Hash()
}
return c.vhash
return sc.vhash
}
// Certify makes sure that the commit is valid.
func (c *Static) Certify(commit Commit) error {
// Implements Certifier.
func (sc *StaticCertifier) Certify(commit Commit) error {
// do basic sanity checks
err := commit.ValidateBasic(c.chainID)
err := commit.ValidateBasic(sc.chainID)
if err != nil {
return err
}
// make sure it has the same validator set we have (static means static)
if !bytes.Equal(c.Hash(), commit.Header.ValidatorsHash) {
if !bytes.Equal(sc.Hash(), commit.Header.ValidatorsHash) {
return liteErr.ErrValidatorsChanged()
}
// then make sure we have the proper signatures for this
err = c.vSet.VerifyCommit(c.chainID, commit.Commit.BlockID,
err = sc.vSet.VerifyCommit(sc.chainID, commit.Commit.BlockID,
commit.Header.Height, commit.Commit)
return errors.WithStack(err)
}
@@ -21,7 +21,7 @@ func TestStaticCert(t *testing.T) {
vals := keys.ToValidators(20, 10)
// and a certifier based on our known set
chainID := "test-static"
cert := lite.NewStatic(chainID, vals)
cert := lite.NewStaticCertifier(chainID, vals)
cases := []struct {
keys lite.ValKeys