mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-20 06:54:41 +00:00
Merge branch 'develop' into config
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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} {
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user