mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
Addressed review for #1815 except those marked as 'TODO make issue'
This commit is contained in:
parent
eb9b37e196
commit
e719a93d1d
@ -556,7 +556,7 @@ BREAKING CHANGES:
|
|||||||
- use scripts/wal2json to convert to json for debugging
|
- use scripts/wal2json to convert to json for debugging
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
- new `certifiers` pkg contains the tendermint light-client library (name subject to change)!
|
- new `Verifiers` pkg contains the tendermint light-client library (name subject to change)!
|
||||||
- rpc: `/genesis` includes the `app_options` .
|
- rpc: `/genesis` includes the `app_options` .
|
||||||
- rpc: `/abci_query` takes an additional `height` parameter to support historical queries.
|
- rpc: `/abci_query` takes an additional `height` parameter to support historical queries.
|
||||||
- rpc/client: new ABCIQueryWithOptions supports options like `trusted` (set false to get a proof) and `height` to query a historical height.
|
- rpc/client: new ABCIQueryWithOptions supports options like `trusted` (set false to get a proof) and `height` to query a historical height.
|
||||||
|
4
Gopkg.lock
generated
4
Gopkg.lock
generated
@ -11,7 +11,7 @@
|
|||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/btcsuite/btcd"
|
name = "github.com/btcsuite/btcd"
|
||||||
packages = ["btcec"]
|
packages = ["btcec"]
|
||||||
revision = "9a2f9524024889e129a5422aca2cff73cb3eabf6"
|
revision = "f5e261fc9ec3437697fb31d8b38453c293204b29"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/btcsuite/btcutil"
|
name = "github.com/btcsuite/btcutil"
|
||||||
@ -342,7 +342,7 @@
|
|||||||
"cpu",
|
"cpu",
|
||||||
"unix"
|
"unix"
|
||||||
]
|
]
|
||||||
revision = "bd9dbc187b6e1dacfdd2722a87e83093c2d7bd6e"
|
revision = "3dc4335d56c789b04b0ba99b7a37249d9b614314"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
|
@ -68,10 +68,10 @@ func runProxy(cmd *cobra.Command, args []string) error {
|
|||||||
logger.Info("Connecting to source HTTP client...")
|
logger.Info("Connecting to source HTTP client...")
|
||||||
node := rpcclient.NewHTTP(nodeAddr, "/websocket")
|
node := rpcclient.NewHTTP(nodeAddr, "/websocket")
|
||||||
|
|
||||||
logger.Info("Constructing certifier...")
|
logger.Info("Constructing Verifier...")
|
||||||
cert, err := proxy.NewCertifier(chainID, home, node, logger)
|
cert, err := proxy.NewVerifier(chainID, home, node, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmn.ErrorWrap(err, "constructing certifier")
|
return cmn.ErrorWrap(err, "constructing Verifier")
|
||||||
}
|
}
|
||||||
cert.SetLogger(logger)
|
cert.SetLogger(logger)
|
||||||
sc := proxy.SecureClient(node, cert)
|
sc := proxy.SecureClient(node, cert)
|
||||||
|
@ -3,48 +3,48 @@ package lite
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
lerr "github.com/tendermint/tendermint/lite/errors"
|
lerr "github.com/tendermint/tendermint/lite/errors"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Certifier = (*BaseCertifier)(nil)
|
var _ Verifier = (*BaseVerifier)(nil)
|
||||||
|
|
||||||
// BaseCertifier lets us check the validity of SignedHeaders at height or
|
// BaseVerifier lets us check the validity of SignedHeaders at height or
|
||||||
// later, requiring sufficient votes (> 2/3) from the given valset.
|
// later, requiring sufficient votes (> 2/3) from the given valset.
|
||||||
// To certify blocks produced by a blockchain with mutable validator sets,
|
// To certify blocks produced by a blockchain with mutable validator sets,
|
||||||
// use the InquiringCertifier.
|
// use the DynamicVerifier.
|
||||||
// TODO: Handle unbonding time.
|
// TODO: Handle unbonding time.
|
||||||
type BaseCertifier struct {
|
type BaseVerifier struct {
|
||||||
chainID string
|
chainID string
|
||||||
height int64
|
height int64
|
||||||
valset *types.ValidatorSet
|
valset *types.ValidatorSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBaseCertifier returns a new certifier initialized with a validator set at
|
// NewBaseVerifier returns a new Verifier initialized with a validator set at
|
||||||
// some height.
|
// some height.
|
||||||
func NewBaseCertifier(chainID string, height int64, valset *types.ValidatorSet) *BaseCertifier {
|
func NewBaseVerifier(chainID string, height int64, valset *types.ValidatorSet) *BaseVerifier {
|
||||||
if valset == nil || len(valset.Hash()) == 0 {
|
if valset.IsNilOrEmpty() {
|
||||||
panic("NewBaseCertifier requires a valid valset")
|
panic("NewBaseVerifier requires a valid valset")
|
||||||
}
|
}
|
||||||
return &BaseCertifier{
|
return &BaseVerifier{
|
||||||
chainID: chainID,
|
chainID: chainID,
|
||||||
height: height,
|
height: height,
|
||||||
valset: valset,
|
valset: valset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Certifier.
|
// Implements Verifier.
|
||||||
func (bc *BaseCertifier) ChainID() string {
|
func (bc *BaseVerifier) ChainID() string {
|
||||||
return bc.chainID
|
return bc.chainID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Certifier.
|
// Implements Verifier.
|
||||||
func (bc *BaseCertifier) Certify(signedHeader types.SignedHeader) error {
|
func (bc *BaseVerifier) Certify(signedHeader types.SignedHeader) error {
|
||||||
|
|
||||||
// We can't certify commits older than bc.height.
|
// We can't certify commits older than bc.height.
|
||||||
if signedHeader.Height < bc.height {
|
if signedHeader.Height < bc.height {
|
||||||
return cmn.NewError("BaseCertifier height is %v, cannot certify height %v",
|
return cmn.NewError("BaseVerifier height is %v, cannot certify height %v",
|
||||||
bc.height, signedHeader.Height)
|
bc.height, signedHeader.Height)
|
||||||
}
|
}
|
||||||
|
|
@ -10,16 +10,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestBaseCert(t *testing.T) {
|
func TestBaseCert(t *testing.T) {
|
||||||
// assert, require := assert.New(t), require.New(t)
|
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
// require := require.New(t)
|
|
||||||
|
|
||||||
keys := genPrivKeys(4)
|
keys := genPrivKeys(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 Verifier based on our known set
|
||||||
chainID := "test-static"
|
chainID := "test-static"
|
||||||
cert := NewBaseCertifier(chainID, 2, vals)
|
cert := NewBaseVerifier(chainID, 2, vals)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
keys privKeys
|
keys privKeys
|
@ -8,12 +8,12 @@ package client
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
log "github.com/tendermint/tendermint/libs/log"
|
||||||
"github.com/tendermint/tendermint/lite"
|
"github.com/tendermint/tendermint/lite"
|
||||||
lerr "github.com/tendermint/tendermint/lite/errors"
|
lerr "github.com/tendermint/tendermint/lite/errors"
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||||
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"
|
||||||
log "github.com/tendermint/tendermint/libs/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignStatusClient combines a SignClient and StatusClient.
|
// SignStatusClient combines a SignClient and StatusClient.
|
||||||
@ -106,12 +106,10 @@ func (p *provider) getValidatorSet(chainID string, height int64) (valset *types.
|
|||||||
err = fmt.Errorf("expected height >= 1, got height %v", height)
|
err = fmt.Errorf("expected height >= 1, got height %v", height)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
heightPtr := new(int64)
|
res, err := p.client.Validators(&height)
|
||||||
*heightPtr = height
|
|
||||||
res, err := p.client.Validators(heightPtr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO pass through other types of errors.
|
// TODO pass through other types of errors.
|
||||||
return nil, lerr.ErrMissingValidators(chainID, height)
|
return nil, lerr.ErrUnknownValidators(chainID, height)
|
||||||
}
|
}
|
||||||
valset = types.NewValidatorSet(res.Validators)
|
valset = types.NewValidatorSet(res.Validators)
|
||||||
return
|
return
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO fix tests!!
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
app := kvstore.NewKVStoreApplication()
|
app := kvstore.NewKVStoreApplication()
|
||||||
node := rpctest.StartTendermint(app)
|
node := rpctest.StartTendermint(app)
|
||||||
@ -59,15 +58,4 @@ func TestProvider(t *testing.T) {
|
|||||||
assert.Nil(err, "%+v", err)
|
assert.Nil(err, "%+v", err)
|
||||||
assert.Equal(lower, fc.Height())
|
assert.Equal(lower, fc.Height())
|
||||||
|
|
||||||
/*
|
|
||||||
// also get by hash (given the match)
|
|
||||||
fc, err = p.GetByHash(vhash)
|
|
||||||
require.Nil(err, "%+v", err)
|
|
||||||
require.Equal(vhash, fc.Header.ValidatorsHash)
|
|
||||||
|
|
||||||
// get by hash fails without match
|
|
||||||
fc, err = p.GetByHash([]byte("foobar"))
|
|
||||||
assert.NotNil(err)
|
|
||||||
assert.True(liteErr.IsCommitNotFoundErr(err))
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
// FullCommit is a signed header (the block header and a commit that signs it),
|
// FullCommit is a signed header (the block header and a commit that signs it),
|
||||||
// the validator set which signed the commit, and the next validator set. The
|
// the validator set which signed the commit, and the next validator set. The
|
||||||
// next validator set (which is proven from the block header) allows us to
|
// next validator set (which is proven from the block header) allows us to
|
||||||
// revert to block-by-block updating of lite certifier's latest validator set,
|
// revert to block-by-block updating of lite Verifier's latest validator set,
|
||||||
// even in the face of arbitrarily large power changes.
|
// even in the face of arbitrarily large power changes.
|
||||||
type FullCommit struct {
|
type FullCommit struct {
|
||||||
SignedHeader types.SignedHeader `json:"signed_header"`
|
SignedHeader types.SignedHeader `json:"signed_header"`
|
||||||
|
@ -22,7 +22,10 @@ type DBProvider struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewDBProvider(label string, db dbm.DB) *DBProvider {
|
func NewDBProvider(label string, db dbm.DB) *DBProvider {
|
||||||
|
|
||||||
|
// NOTE: when debugging, this type of construction might be useful.
|
||||||
//db = dbm.NewDebugDB("db provider "+cmn.RandStr(4), db)
|
//db = dbm.NewDebugDB("db provider "+cmn.RandStr(4), db)
|
||||||
|
|
||||||
cdc := amino.NewCodec()
|
cdc := amino.NewCodec()
|
||||||
cryptoAmino.RegisterAmino(cdc)
|
cryptoAmino.RegisterAmino(cdc)
|
||||||
dbp := &DBProvider{
|
dbp := &DBProvider{
|
||||||
@ -127,8 +130,8 @@ func (dbp *DBProvider) LatestFullCommit(chainID string, minHeight, maxHeight int
|
|||||||
dbp.logger.Info("DBProvider.LatestFullCommit() found latest.", "height", lfc.Height())
|
dbp.logger.Info("DBProvider.LatestFullCommit() found latest.", "height", lfc.Height())
|
||||||
return lfc, nil
|
return lfc, nil
|
||||||
} else {
|
} else {
|
||||||
dbp.logger.Info("DBProvider.LatestFullCommit() got error", "lfc", lfc)
|
dbp.logger.Error("DBProvider.LatestFullCommit() got error", "lfc", lfc)
|
||||||
dbp.logger.Info(fmt.Sprintf("%+v", err))
|
dbp.logger.Error(fmt.Sprintf("%+v", err))
|
||||||
return lfc, err
|
return lfc, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,14 +147,19 @@ func (dbp *DBProvider) ValidatorSet(chainID string, height int64) (valset *types
|
|||||||
func (dbp *DBProvider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
|
func (dbp *DBProvider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
|
||||||
vsBz := dbp.db.Get(validatorSetKey(chainID, height))
|
vsBz := dbp.db.Get(validatorSetKey(chainID, height))
|
||||||
if vsBz == nil {
|
if vsBz == nil {
|
||||||
err = lerr.ErrMissingValidators(chainID, height)
|
err = lerr.ErrUnknownValidators(chainID, height)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = dbp.cdc.UnmarshalBinary(vsBz, &valset)
|
err = dbp.cdc.UnmarshalBinary(vsBz, &valset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
valset.TotalVotingPower() // to test deep equality.
|
|
||||||
|
// To test deep equality. This makes it easier to test for e.g. valset
|
||||||
|
// equivalence using assert.Equal (tests for deep equality) in our tests,
|
||||||
|
// which also tests for unexported/private field equivalence.
|
||||||
|
valset.TotalVotingPower()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,52 +217,52 @@ func (dbp *DBProvider) deleteAfterN(chainID string, after int) error {
|
|||||||
itr.Next()
|
itr.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
dbp.logger.Info(fmt.Sprintf("DBProvider.deleteAfterN() deleted %v items\n", numDeleted))
|
dbp.logger.Info(fmt.Sprintf("DBProvider.deleteAfterN() deleted %v items", numDeleted))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
// key encoding
|
||||||
|
|
||||||
func signedHeaderKey(chainID string, height int64) []byte {
|
func signedHeaderKey(chainID string, height int64) []byte {
|
||||||
return []byte(fmt.Sprintf("%s/%010d/sh", chainID, height))
|
return []byte(fmt.Sprintf("%s/%010d/sh", chainID, height))
|
||||||
}
|
}
|
||||||
|
|
||||||
var signedHeaderKeyPattern = regexp.MustCompile(`([^/]+)/([0-9]*)/sh`)
|
|
||||||
|
|
||||||
func parseSignedHeaderKey(key []byte) (chainID string, height int64, ok bool) {
|
|
||||||
submatch := signedHeaderKeyPattern.FindSubmatch(key)
|
|
||||||
if submatch == nil {
|
|
||||||
return "", 0, false
|
|
||||||
}
|
|
||||||
chainID = string(submatch[1])
|
|
||||||
heightStr := string(submatch[2])
|
|
||||||
heightInt, err := strconv.Atoi(heightStr)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, false
|
|
||||||
}
|
|
||||||
height = int64(heightInt)
|
|
||||||
ok = true // good!
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func validatorSetKey(chainID string, height int64) []byte {
|
func validatorSetKey(chainID string, height int64) []byte {
|
||||||
return []byte(fmt.Sprintf("%s/%010d/vs", chainID, height))
|
return []byte(fmt.Sprintf("%s/%010d/vs", chainID, height))
|
||||||
}
|
}
|
||||||
|
|
||||||
var chainKeyPrefixPattern = regexp.MustCompile(`([^/]+)/([0-9]*)/`)
|
//----------------------------------------
|
||||||
|
// key parsing
|
||||||
|
|
||||||
func parseChainKeyPrefix(key []byte) (chainID string, height int64, ok bool) {
|
var keyPattern = regexp.MustCompile(`^([^/]+)/([0-9]*)/(.*)$`)
|
||||||
submatch := chainKeyPrefixPattern.FindSubmatch(key)
|
|
||||||
|
func parseKey(key []byte) (chainID string, height int64, part string, ok bool) {
|
||||||
|
submatch := keyPattern.FindSubmatch(key)
|
||||||
if submatch == nil {
|
if submatch == nil {
|
||||||
return "", 0, false
|
return "", 0, "", false
|
||||||
}
|
}
|
||||||
chainID = string(submatch[1])
|
chainID = string(submatch[1])
|
||||||
heightStr := string(submatch[2])
|
heightStr := string(submatch[2])
|
||||||
heightInt, err := strconv.Atoi(heightStr)
|
heightInt, err := strconv.Atoi(heightStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, false
|
return "", 0, "", false
|
||||||
}
|
}
|
||||||
height = int64(heightInt)
|
height = int64(heightInt)
|
||||||
|
part = string(submatch[3])
|
||||||
ok = true // good!
|
ok = true // good!
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseSignedHeaderKey(key []byte) (chainID string, height int64, ok bool) {
|
||||||
|
chainID, height, part, ok := parseKey(key)
|
||||||
|
if part != "sh" {
|
||||||
|
return "", 0, false
|
||||||
|
}
|
||||||
|
return chainID, height, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseChainKeyPrefix(key []byte) (chainID string, height int64, ok bool) {
|
||||||
|
chainID, height, _, ok = parseKey(key)
|
||||||
|
return chainID, height, true
|
||||||
|
}
|
||||||
|
18
lite/doc.go
18
lite/doc.go
@ -35,29 +35,29 @@ change on the chain. In practice, most applications will not have frequent
|
|||||||
drastic updates to the validator set, so the logic defined in this package for
|
drastic updates to the validator set, so the logic defined in this package for
|
||||||
lite client syncing is optimized to use intelligent bisection and
|
lite client syncing is optimized to use intelligent bisection and
|
||||||
block-skipping for efficient sourcing and verification of these data structures
|
block-skipping for efficient sourcing and verification of these data structures
|
||||||
and updates to the validator set (see the InquiringCertifier for more
|
and updates to the validator set (see the DynamicVerifier for more
|
||||||
information).
|
information).
|
||||||
|
|
||||||
The FullCommit is also declared in this package as a convenience structure,
|
The FullCommit is also declared in this package as a convenience structure,
|
||||||
which includes the SignedHeader along with the full current and next
|
which includes the SignedHeader along with the full current and next
|
||||||
ValidatorSets.
|
ValidatorSets.
|
||||||
|
|
||||||
## Certifier
|
## Verifier
|
||||||
|
|
||||||
A Certifier validates a new SignedHeader given the currently known state. There
|
A Verifier validates a new SignedHeader given the currently known state. There
|
||||||
are two different types of Certifiers provided.
|
are two different types of Verifiers provided.
|
||||||
|
|
||||||
BaseCertifier - given a validator set and a height, this Certifier verifies
|
BaseVerifier - given a validator set and a height, this Verifier verifies
|
||||||
that > 2/3 of the voting power of the given validator set had signed the
|
that > 2/3 of the voting power of the given validator set had signed the
|
||||||
SignedHeader, and that the SignedHeader was to be signed by the exact given
|
SignedHeader, and that the SignedHeader was to be signed by the exact given
|
||||||
validator set, and that the height of the commit is at least height (or
|
validator set, and that the height of the commit is at least height (or
|
||||||
greater).
|
greater).
|
||||||
|
|
||||||
SignedHeader.Commit may be signed by a different validator set, it can get
|
SignedHeader.Commit may be signed by a different validator set, it can get
|
||||||
certified with a BaseCertifier as long as sufficient signatures from the
|
certified with a BaseVerifier as long as sufficient signatures from the
|
||||||
previous validator set are present in the commit.
|
previous validator set are present in the commit.
|
||||||
|
|
||||||
InquiringCertifier - this certifier implements an auto-update and persistence
|
DynamicVerifier - this Verifier implements an auto-update and persistence
|
||||||
strategy to certify any SignedHeader of the blockchain.
|
strategy to certify any SignedHeader of the blockchain.
|
||||||
|
|
||||||
## Provider and PersistentProvider
|
## Provider and PersistentProvider
|
||||||
@ -77,7 +77,7 @@ type Provider interface {
|
|||||||
* client.NewHTTPProvider - query Tendermint rpc.
|
* client.NewHTTPProvider - query Tendermint rpc.
|
||||||
|
|
||||||
A PersistentProvider is a Provider that also allows for saving state. This is
|
A PersistentProvider is a Provider that also allows for saving state. This is
|
||||||
used by the InquiringCertifier for persistence.
|
used by the DynamicVerifier for persistence.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type PersistentProvider interface {
|
type PersistentProvider interface {
|
||||||
@ -131,7 +131,7 @@ important to verify that you have the proper validator set when initializing
|
|||||||
the client, as that is the root of all trust.
|
the client, as that is the root of all trust.
|
||||||
|
|
||||||
The software currently assumes that the unbonding period is infinite in
|
The software currently assumes that the unbonding period is infinite in
|
||||||
duration. If the InquiringCertifier hasn't been updated in a while, you should
|
duration. If the DynamicVerifier hasn't been updated in a while, you should
|
||||||
manually verify the block headers using other sources.
|
manually verify the block headers using other sources.
|
||||||
|
|
||||||
TODO: Update the software to handle cases around the unbonding period.
|
TODO: Update the software to handle cases around the unbonding period.
|
||||||
|
@ -3,18 +3,18 @@ package lite
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
|
log "github.com/tendermint/tendermint/libs/log"
|
||||||
lerr "github.com/tendermint/tendermint/lite/errors"
|
lerr "github.com/tendermint/tendermint/lite/errors"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
log "github.com/tendermint/tendermint/libs/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Certifier = (*InquiringCertifier)(nil)
|
var _ Verifier = (*DynamicVerifier)(nil)
|
||||||
|
|
||||||
// InquiringCertifier implements an auto-updating certifier. It uses a
|
// DynamicVerifier implements an auto-updating Verifier. It uses a
|
||||||
// "source" provider to obtain the needed FullCommits to securely sync with
|
// "source" provider to obtain the needed FullCommits to securely sync with
|
||||||
// validator set changes. It stores properly validated data on the
|
// validator set changes. It stores properly validated data on the
|
||||||
// "trusted" local system.
|
// "trusted" local system.
|
||||||
type InquiringCertifier struct {
|
type DynamicVerifier struct {
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
chainID string
|
chainID string
|
||||||
// These are only properly validated data, from local system.
|
// These are only properly validated data, from local system.
|
||||||
@ -23,14 +23,14 @@ type InquiringCertifier struct {
|
|||||||
source Provider
|
source Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInquiringCertifier returns a new InquiringCertifier. It uses the
|
// NewDynamicVerifier returns a new DynamicVerifier. It uses the
|
||||||
// trusted provider to store validated data and the source provider to
|
// trusted provider to store validated data and the source provider to
|
||||||
// obtain missing data (e.g. FullCommits).
|
// obtain missing data (e.g. FullCommits).
|
||||||
//
|
//
|
||||||
// The trusted provider should a CacheProvider, MemProvider or
|
// The trusted provider should a CacheProvider, MemProvider or
|
||||||
// files.Provider. The source provider should be a client.HTTPProvider.
|
// files.Provider. The source provider should be a client.HTTPProvider.
|
||||||
func NewInquiringCertifier(chainID string, trusted PersistentProvider, source Provider) *InquiringCertifier {
|
func NewDynamicVerifier(chainID string, trusted PersistentProvider, source Provider) *DynamicVerifier {
|
||||||
return &InquiringCertifier{
|
return &DynamicVerifier{
|
||||||
logger: log.NewNopLogger(),
|
logger: log.NewNopLogger(),
|
||||||
chainID: chainID,
|
chainID: chainID,
|
||||||
trusted: trusted,
|
trusted: trusted,
|
||||||
@ -38,64 +38,64 @@ func NewInquiringCertifier(chainID string, trusted PersistentProvider, source Pr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *InquiringCertifier) SetLogger(logger log.Logger) {
|
func (ic *DynamicVerifier) SetLogger(logger log.Logger) {
|
||||||
logger = logger.With("module", "lite")
|
logger = logger.With("module", "lite")
|
||||||
ic.logger = logger
|
ic.logger = logger
|
||||||
ic.trusted.SetLogger(logger)
|
ic.trusted.SetLogger(logger)
|
||||||
ic.source.SetLogger(logger)
|
ic.source.SetLogger(logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Certifier.
|
// Implements Verifier.
|
||||||
func (ic *InquiringCertifier) ChainID() string {
|
func (ic *DynamicVerifier) ChainID() string {
|
||||||
return ic.chainID
|
return ic.chainID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Certifier.
|
// Implements Verifier.
|
||||||
//
|
//
|
||||||
// If the validators have changed since the last know time, it looks to
|
// If the validators have changed since the last known time, it looks to
|
||||||
// ic.trusted and ic.source to prove the new validators. On success, it will
|
// ic.trusted and ic.source to prove the new validators. On success, it will
|
||||||
// try to store the SignedHeader in ic.trusted if the next
|
// try to store the SignedHeader in ic.trusted if the next
|
||||||
// validator can be sourced.
|
// validator can be sourced.
|
||||||
func (ic *InquiringCertifier) Certify(shdr types.SignedHeader) error {
|
func (ic *DynamicVerifier) Certify(shdr types.SignedHeader) error {
|
||||||
|
|
||||||
// Get the latest known full commit <= h-1 from our trusted providers.
|
// Get the latest known full commit <= h-1 from our trusted providers.
|
||||||
// The full commit at h-1 contains the valset to sign for h.
|
// The full commit at h-1 contains the valset to sign for h.
|
||||||
h := shdr.Height - 1
|
h := shdr.Height - 1
|
||||||
tfc, err := ic.trusted.LatestFullCommit(ic.chainID, 1, h)
|
trustedFC, err := ic.trusted.LatestFullCommit(ic.chainID, 1, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if tfc.Height() == h {
|
if trustedFC.Height() == h {
|
||||||
// Return error if valset doesn't match.
|
// Return error if valset doesn't match.
|
||||||
if !bytes.Equal(
|
if !bytes.Equal(
|
||||||
tfc.NextValidators.Hash(),
|
trustedFC.NextValidators.Hash(),
|
||||||
shdr.Header.ValidatorsHash) {
|
shdr.Header.ValidatorsHash) {
|
||||||
return lerr.ErrUnexpectedValidators(
|
return lerr.ErrUnexpectedValidators(
|
||||||
tfc.NextValidators.Hash(),
|
trustedFC.NextValidators.Hash(),
|
||||||
shdr.Header.ValidatorsHash)
|
shdr.Header.ValidatorsHash)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If valset doesn't match...
|
// If valset doesn't match...
|
||||||
if !bytes.Equal(tfc.NextValidators.Hash(),
|
if !bytes.Equal(trustedFC.NextValidators.Hash(),
|
||||||
shdr.Header.ValidatorsHash) {
|
shdr.Header.ValidatorsHash) {
|
||||||
// ... update.
|
// ... update.
|
||||||
tfc, err = ic.updateToHeight(h)
|
trustedFC, err = ic.updateToHeight(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Return error if valset _still_ doesn't match.
|
// Return error if valset _still_ doesn't match.
|
||||||
if !bytes.Equal(tfc.NextValidators.Hash(),
|
if !bytes.Equal(trustedFC.NextValidators.Hash(),
|
||||||
shdr.Header.ValidatorsHash) {
|
shdr.Header.ValidatorsHash) {
|
||||||
return lerr.ErrUnexpectedValidators(
|
return lerr.ErrUnexpectedValidators(
|
||||||
tfc.NextValidators.Hash(),
|
trustedFC.NextValidators.Hash(),
|
||||||
shdr.Header.ValidatorsHash)
|
shdr.Header.ValidatorsHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certify the signed header using the matching valset.
|
// Certify the signed header using the matching valset.
|
||||||
cert := NewBaseCertifier(ic.chainID, tfc.Height()+1, tfc.NextValidators)
|
cert := NewBaseVerifier(ic.chainID, trustedFC.Height()+1, trustedFC.NextValidators)
|
||||||
err = cert.Certify(shdr)
|
err = cert.Certify(shdr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -103,7 +103,7 @@ func (ic *InquiringCertifier) Certify(shdr types.SignedHeader) error {
|
|||||||
|
|
||||||
// Get the next validator set.
|
// Get the next validator set.
|
||||||
nextValset, err := ic.source.ValidatorSet(ic.chainID, shdr.Height+1)
|
nextValset, err := ic.source.ValidatorSet(ic.chainID, shdr.Height+1)
|
||||||
if lerr.IsErrMissingValidators(err) {
|
if lerr.IsErrUnknownValidators(err) {
|
||||||
// Ignore this error.
|
// Ignore this error.
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -113,7 +113,7 @@ func (ic *InquiringCertifier) Certify(shdr types.SignedHeader) error {
|
|||||||
// Create filled FullCommit.
|
// Create filled FullCommit.
|
||||||
nfc := FullCommit{
|
nfc := FullCommit{
|
||||||
SignedHeader: shdr,
|
SignedHeader: shdr,
|
||||||
Validators: tfc.NextValidators,
|
Validators: trustedFC.NextValidators,
|
||||||
NextValidators: nextValset,
|
NextValidators: nextValset,
|
||||||
}
|
}
|
||||||
// Validate the full commit. This checks the cryptographic
|
// Validate the full commit. This checks the cryptographic
|
||||||
@ -127,22 +127,22 @@ func (ic *InquiringCertifier) Certify(shdr types.SignedHeader) error {
|
|||||||
|
|
||||||
// verifyAndSave will verify if this is a valid source full commit given the
|
// verifyAndSave will verify if this is a valid source full commit given the
|
||||||
// best match trusted full commit, and if good, persist to ic.trusted.
|
// best match trusted full commit, and if good, persist to ic.trusted.
|
||||||
// Returns ErrTooMuchChange when >2/3 of tfc did not sign sfc.
|
// Returns ErrTooMuchChange when >2/3 of trustedFC did not sign sourceFC.
|
||||||
// Panics if tfc.Height() >= sfc.Height().
|
// Panics if trustedFC.Height() >= sourceFC.Height().
|
||||||
func (ic *InquiringCertifier) verifyAndSave(tfc, sfc FullCommit) error {
|
func (ic *DynamicVerifier) verifyAndSave(trustedFC, sourceFC FullCommit) error {
|
||||||
if tfc.Height() >= sfc.Height() {
|
if trustedFC.Height() >= sourceFC.Height() {
|
||||||
panic("should not happen")
|
panic("should not happen")
|
||||||
}
|
}
|
||||||
err := tfc.NextValidators.VerifyFutureCommit(
|
err := trustedFC.NextValidators.VerifyFutureCommit(
|
||||||
sfc.Validators,
|
sourceFC.Validators,
|
||||||
ic.chainID, sfc.SignedHeader.Commit.BlockID,
|
ic.chainID, sourceFC.SignedHeader.Commit.BlockID,
|
||||||
sfc.SignedHeader.Height, sfc.SignedHeader.Commit,
|
sourceFC.SignedHeader.Height, sourceFC.SignedHeader.Commit,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ic.trusted.SaveFullCommit(sfc)
|
return ic.trusted.SaveFullCommit(sourceFC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateToHeight will use divide-and-conquer to find a path to h.
|
// updateToHeight will use divide-and-conquer to find a path to h.
|
||||||
@ -150,48 +150,48 @@ func (ic *InquiringCertifier) verifyAndSave(tfc, sfc FullCommit) error {
|
|||||||
// for height h, using repeated applications of bisection if necessary.
|
// for height h, using repeated applications of bisection if necessary.
|
||||||
//
|
//
|
||||||
// Returns ErrCommitNotFound if source provider doesn't have the commit for h.
|
// Returns ErrCommitNotFound if source provider doesn't have the commit for h.
|
||||||
func (ic *InquiringCertifier) updateToHeight(h int64) (FullCommit, error) {
|
func (ic *DynamicVerifier) updateToHeight(h int64) (FullCommit, error) {
|
||||||
|
|
||||||
// Fetch latest full commit from source.
|
// Fetch latest full commit from source.
|
||||||
sfc, err := ic.source.LatestFullCommit(ic.chainID, h, h)
|
sourceFC, err := ic.source.LatestFullCommit(ic.chainID, h, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FullCommit{}, err
|
return FullCommit{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the full commit. This checks the cryptographic
|
// Validate the full commit. This checks the cryptographic
|
||||||
// signatures of Commit against Validators.
|
// signatures of Commit against Validators.
|
||||||
if err := sfc.ValidateFull(ic.chainID); err != nil {
|
if err := sourceFC.ValidateFull(ic.chainID); err != nil {
|
||||||
return FullCommit{}, err
|
return FullCommit{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If sfc.Height() != h, we can't do it.
|
// If sourceFC.Height() != h, we can't do it.
|
||||||
if sfc.Height() != h {
|
if sourceFC.Height() != h {
|
||||||
return FullCommit{}, lerr.ErrCommitNotFound()
|
return FullCommit{}, lerr.ErrCommitNotFound()
|
||||||
}
|
}
|
||||||
|
|
||||||
FOR_LOOP:
|
FOR_LOOP:
|
||||||
for {
|
for {
|
||||||
// Fetch latest full commit from trusted.
|
// Fetch latest full commit from trusted.
|
||||||
tfc, err := ic.trusted.LatestFullCommit(ic.chainID, 1, h)
|
trustedFC, err := ic.trusted.LatestFullCommit(ic.chainID, 1, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FullCommit{}, err
|
return FullCommit{}, err
|
||||||
}
|
}
|
||||||
// We have nothing to do.
|
// We have nothing to do.
|
||||||
if tfc.Height() == h {
|
if trustedFC.Height() == h {
|
||||||
return tfc, nil
|
return trustedFC, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to update to full commit with checks.
|
// Try to update to full commit with checks.
|
||||||
err = ic.verifyAndSave(tfc, sfc)
|
err = ic.verifyAndSave(trustedFC, sourceFC)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// All good!
|
// All good!
|
||||||
return sfc, nil
|
return sourceFC, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle special case when err is ErrTooMuchChange.
|
// Handle special case when err is ErrTooMuchChange.
|
||||||
if lerr.IsErrTooMuchChange(err) {
|
if lerr.IsErrTooMuchChange(err) {
|
||||||
// Divide and conquer.
|
// Divide and conquer.
|
||||||
start, end := tfc.Height(), sfc.Height()
|
start, end := trustedFC.Height(), sourceFC.Height()
|
||||||
if !(start < end) {
|
if !(start < end) {
|
||||||
panic("should not happen")
|
panic("should not happen")
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ FOR_LOOP:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *InquiringCertifier) LastTrustedHeight() int64 {
|
func (ic *DynamicVerifier) LastTrustedHeight() int64 {
|
||||||
fc, err := ic.trusted.LatestFullCommit(ic.chainID, 1, 1<<63-1)
|
fc, err := ic.trusted.LatestFullCommit(ic.chainID, 1, 1<<63-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("should not happen")
|
panic("should not happen")
|
@ -41,10 +41,10 @@ func TestInquirerValidPath(t *testing.T) {
|
|||||||
nkeys = nkeys.Extend(1)
|
nkeys = nkeys.Extend(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a certifier with the initial state.
|
// Initialize a Verifier with the initial state.
|
||||||
err := trust.SaveFullCommit(fcz[0])
|
err := trust.SaveFullCommit(fcz[0])
|
||||||
require.Nil(err)
|
require.Nil(err)
|
||||||
cert := NewInquiringCertifier(chainID, trust, source)
|
cert := NewDynamicVerifier(chainID, trust, source)
|
||||||
cert.SetLogger(log.TestingLogger())
|
cert.SetLogger(log.TestingLogger())
|
||||||
|
|
||||||
// This should fail validation:
|
// This should fail validation:
|
||||||
@ -99,10 +99,10 @@ func TestInquirerVerifyHistorical(t *testing.T) {
|
|||||||
nkeys = nkeys.Extend(1)
|
nkeys = nkeys.Extend(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a certifier with the initial state.
|
// Initialize a Verifier with the initial state.
|
||||||
err := trust.SaveFullCommit(fcz[0])
|
err := trust.SaveFullCommit(fcz[0])
|
||||||
require.Nil(err)
|
require.Nil(err)
|
||||||
cert := NewInquiringCertifier(chainID, trust, source)
|
cert := NewDynamicVerifier(chainID, trust, source)
|
||||||
cert.SetLogger(log.TestingLogger())
|
cert.SetLogger(log.TestingLogger())
|
||||||
|
|
||||||
// Store a few full commits as trust.
|
// Store a few full commits as trust.
|
@ -31,12 +31,12 @@ func (e errTooMuchChange) Error() string {
|
|||||||
return "Insufficient signatures to validate due to valset changes"
|
return "Insufficient signatures to validate due to valset changes"
|
||||||
}
|
}
|
||||||
|
|
||||||
type errMissingValidators struct {
|
type errUnknownValidators struct {
|
||||||
chainID string
|
chainID string
|
||||||
height int64
|
height int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e errMissingValidators) Error() string {
|
func (e errUnknownValidators) Error() string {
|
||||||
return fmt.Sprintf("Validators are unknown or missing for chain %s and height %d",
|
return fmt.Sprintf("Validators are unknown or missing for chain %s and height %d",
|
||||||
e.chainID, e.height)
|
e.chainID, e.height)
|
||||||
}
|
}
|
||||||
@ -96,16 +96,16 @@ func IsErrTooMuchChange(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-----------------
|
//-----------------
|
||||||
// ErrMissingValidators
|
// ErrUnknownValidators
|
||||||
|
|
||||||
// ErrMissingValidators indicates that some validator set was missing or unknown.
|
// ErrUnknownValidators indicates that some validator set was missing or unknown.
|
||||||
func ErrMissingValidators(chainID string, height int64) error {
|
func ErrUnknownValidators(chainID string, height int64) error {
|
||||||
return cmn.ErrorWrap(errMissingValidators{chainID, height}, "")
|
return cmn.ErrorWrap(errUnknownValidators{chainID, height}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsErrMissingValidators(err error) bool {
|
func IsErrUnknownValidators(err error) bool {
|
||||||
if err_, ok := err.(cmn.Error); ok {
|
if err_, ok := err.(cmn.Error); ok {
|
||||||
_, ok := err_.Data().(errMissingValidators)
|
_, ok := err_.Data().(errUnknownValidators)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package lite
|
package lite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
log "github.com/tendermint/tendermint/libs/log"
|
||||||
lerr "github.com/tendermint/tendermint/lite/errors"
|
lerr "github.com/tendermint/tendermint/lite/errors"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
log "github.com/tendermint/tendermint/libs/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// multiProvider allows you to place one or more caches in front of a source
|
// multiProvider allows you to place one or more caches in front of a source
|
||||||
@ -79,5 +79,5 @@ func (mc *multiProvider) ValidatorSet(chainID string, height int64) (valset *typ
|
|||||||
return valset, nil
|
return valset, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, lerr.ErrMissingValidators(chainID, height)
|
return nil, lerr.ErrUnknownValidators(chainID, height)
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,13 @@ type KeyProof interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetWithProof will query the key on the given node, and verify it has
|
// GetWithProof will query the key on the given node, and verify it has
|
||||||
// a valid proof, as defined by the certifier.
|
// a valid proof, as defined by the Verifier.
|
||||||
//
|
//
|
||||||
// If there is any error in checking, returns an error.
|
// If there is any error in checking, returns an error.
|
||||||
// If val is non-empty, proof should be KeyExistsProof
|
// If val is non-empty, proof should be KeyExistsProof
|
||||||
// If val is empty, proof should be KeyMissingProof
|
// If val is empty, proof should be KeyMissingProof
|
||||||
func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client,
|
func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client,
|
||||||
cert lite.Certifier) (
|
cert lite.Verifier) (
|
||||||
val cmn.HexBytes, height int64, proof KeyProof, err error) {
|
val cmn.HexBytes, height int64, proof KeyProof, err error) {
|
||||||
|
|
||||||
if reqHeight < 0 {
|
if reqHeight < 0 {
|
||||||
@ -54,7 +54,7 @@ func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client,
|
|||||||
|
|
||||||
// GetWithProofOptions is useful if you want full access to the ABCIQueryOptions
|
// GetWithProofOptions is useful if you want full access to the ABCIQueryOptions
|
||||||
func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOptions,
|
func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOptions,
|
||||||
node rpcclient.Client, cert lite.Certifier) (
|
node rpcclient.Client, cert lite.Verifier) (
|
||||||
*ctypes.ResultABCIQuery, KeyProof, error) {
|
*ctypes.ResultABCIQuery, KeyProof, error) {
|
||||||
|
|
||||||
_resp, err := node.ABCIQueryWithOptions(path, key, opts)
|
_resp, err := node.ABCIQueryWithOptions(path, key, opts)
|
||||||
@ -128,7 +128,7 @@ func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOption
|
|||||||
|
|
||||||
// GetCertifiedCommit gets the signed header for a given height and certifies
|
// GetCertifiedCommit gets the signed header for a given height and certifies
|
||||||
// it. Returns error if unable to get a proven header.
|
// it. Returns error if unable to get a proven header.
|
||||||
func GetCertifiedCommit(h int64, client rpcclient.Client, cert lite.Certifier) (types.SignedHeader, error) {
|
func GetCertifiedCommit(h int64, client rpcclient.Client, cert lite.Verifier) (types.SignedHeader, error) {
|
||||||
|
|
||||||
// FIXME: cannot use cert.GetByHeight for now, as it also requires
|
// FIXME: cannot use cert.GetByHeight for now, as it also requires
|
||||||
// Validators and will fail on querying tendermint for non-current height.
|
// Validators and will fail on querying tendermint for non-current height.
|
||||||
|
@ -58,7 +58,7 @@ func _TestAppProofs(t *testing.T) {
|
|||||||
source := certclient.NewProvider(chainID, cl)
|
source := certclient.NewProvider(chainID, cl)
|
||||||
seed, err := source.LatestFullCommit(chainID, brh-2, brh-2)
|
seed, err := source.LatestFullCommit(chainID, brh-2, brh-2)
|
||||||
require.NoError(err, "%+v", err)
|
require.NoError(err, "%+v", err)
|
||||||
cert := lite.NewBaseCertifier("my-chain", seed.Height(), seed.Validators)
|
cert := lite.NewBaseVerifier("my-chain", seed.Height(), seed.Validators)
|
||||||
|
|
||||||
client.WaitForHeight(cl, 3, nil)
|
client.WaitForHeight(cl, 3, nil)
|
||||||
latest, err := source.LatestFullCommit(chainID, 1, 1<<63-1)
|
latest, err := source.LatestFullCommit(chainID, 1, 1<<63-1)
|
||||||
@ -117,7 +117,7 @@ func _TestTxProofs(t *testing.T) {
|
|||||||
source := certclient.NewProvider(chainID, cl)
|
source := certclient.NewProvider(chainID, cl)
|
||||||
seed, err := source.LatestFullCommit(chainID, brh-2, brh-2)
|
seed, err := source.LatestFullCommit(chainID, brh-2, brh-2)
|
||||||
require.NoError(err, "%+v", err)
|
require.NoError(err, "%+v", err)
|
||||||
cert := lite.NewBaseCertifier("my-chain", seed.Height(), seed.Validators)
|
cert := lite.NewBaseVerifier("my-chain", seed.Height(), seed.Validators)
|
||||||
|
|
||||||
// First let's make sure a bogus transaction hash returns a valid non-existence proof.
|
// First let's make sure a bogus transaction hash returns a valid non-existence proof.
|
||||||
key := types.Tx([]byte("bogus")).Hash()
|
key := types.Tx([]byte("bogus")).Hash()
|
||||||
|
@ -8,10 +8,10 @@ import (
|
|||||||
log "github.com/tendermint/tendermint/libs/log"
|
log "github.com/tendermint/tendermint/libs/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCertifier(chainID, rootDir string, client lclient.SignStatusClient, logger log.Logger) (*lite.InquiringCertifier, error) {
|
func NewVerifier(chainID, rootDir string, client lclient.SignStatusClient, logger log.Logger) (*lite.DynamicVerifier, error) {
|
||||||
|
|
||||||
logger = logger.With("module", "lite/proxy")
|
logger = logger.With("module", "lite/proxy")
|
||||||
logger.Info("lite/proxy/NewCertifier()...", "chainID", chainID, "rootDir", rootDir, "client", client)
|
logger.Info("lite/proxy/NewVerifier()...", "chainID", chainID, "rootDir", rootDir, "client", client)
|
||||||
|
|
||||||
memProvider := lite.NewDBProvider("trusted.mem", dbm.NewMemDB()).SetLimit(10)
|
memProvider := lite.NewDBProvider("trusted.mem", dbm.NewMemDB()).SetLimit(10)
|
||||||
lvlProvider := lite.NewDBProvider("trusted.lvl", dbm.NewDB("trust-base", dbm.LevelDBBackend, rootDir))
|
lvlProvider := lite.NewDBProvider("trusted.lvl", dbm.NewDB("trust-base", dbm.LevelDBBackend, rootDir))
|
||||||
@ -20,13 +20,13 @@ func NewCertifier(chainID, rootDir string, client lclient.SignStatusClient, logg
|
|||||||
lvlProvider,
|
lvlProvider,
|
||||||
)
|
)
|
||||||
source := lclient.NewProvider(chainID, client)
|
source := lclient.NewProvider(chainID, client)
|
||||||
cert := lite.NewInquiringCertifier(chainID, trust, source)
|
cert := lite.NewDynamicVerifier(chainID, trust, source)
|
||||||
cert.SetLogger(logger) // Sets logger recursively.
|
cert.SetLogger(logger) // Sets logger recursively.
|
||||||
|
|
||||||
// TODO: Make this more secure, e.g. make it interactive in the console?
|
// TODO: Make this more secure, e.g. make it interactive in the console?
|
||||||
_, err := trust.LatestFullCommit(chainID, 1, 1<<63-1)
|
_, err := trust.LatestFullCommit(chainID, 1, 1<<63-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Info("lite/proxy/NewCertifier found no trusted full commit, initializing from source from height 1...")
|
logger.Info("lite/proxy/NewVerifier found no trusted full commit, initializing from source from height 1...")
|
||||||
fc, err := source.LatestFullCommit(chainID, 1, 1)
|
fc, err := source.LatestFullCommit(chainID, 1, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cmn.ErrorWrap(err, "fetching source full commit @ height 1")
|
return nil, cmn.ErrorWrap(err, "fetching source full commit @ height 1")
|
@ -10,18 +10,18 @@ import (
|
|||||||
|
|
||||||
var _ rpcclient.Client = Wrapper{}
|
var _ rpcclient.Client = Wrapper{}
|
||||||
|
|
||||||
// Wrapper wraps a rpcclient with a Certifier and double-checks any input that is
|
// Wrapper wraps a rpcclient with a Verifier and double-checks any input that is
|
||||||
// provable before passing it along. Allows you to make any rpcclient fully secure.
|
// provable before passing it along. Allows you to make any rpcclient fully secure.
|
||||||
type Wrapper struct {
|
type Wrapper struct {
|
||||||
rpcclient.Client
|
rpcclient.Client
|
||||||
cert *lite.InquiringCertifier
|
cert *lite.DynamicVerifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecureClient uses a given certifier to wrap an connection to an untrusted
|
// SecureClient uses a given Verifier to wrap an connection to an untrusted
|
||||||
// host and return a cryptographically secure rpc client.
|
// host and return a cryptographically secure rpc client.
|
||||||
//
|
//
|
||||||
// If it is wrapping an HTTP rpcclient, it will also wrap the websocket interface
|
// If it is wrapping an HTTP rpcclient, it will also wrap the websocket interface
|
||||||
func SecureClient(c rpcclient.Client, cert *lite.InquiringCertifier) Wrapper {
|
func SecureClient(c rpcclient.Client, cert *lite.DynamicVerifier) Wrapper {
|
||||||
wrap := Wrapper{c, cert}
|
wrap := Wrapper{c, cert}
|
||||||
// TODO: no longer possible as no more such interface exposed....
|
// 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
|
// if we wrap http client, then we can swap out the event switch to filter
|
||||||
|
@ -4,10 +4,10 @@ import (
|
|||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Certifier checks the votes to make sure the block really is signed properly.
|
// Verifier checks the votes to make sure the block really is signed properly.
|
||||||
// Certifier must know the current or recent set of validitors by some other
|
// Verifier must know the current or recent set of validitors by some other
|
||||||
// means.
|
// means.
|
||||||
type Certifier interface {
|
type Verifier interface {
|
||||||
Certify(sheader types.SignedHeader) error
|
Certify(sheader types.SignedHeader) error
|
||||||
ChainID() string
|
ChainID() string
|
||||||
}
|
}
|
||||||
|
@ -446,7 +446,7 @@ type SignedHeader struct {
|
|||||||
// and commit are consistent.
|
// and commit are consistent.
|
||||||
//
|
//
|
||||||
// NOTE: This does not actually check the cryptographic signatures. Make
|
// NOTE: This does not actually check the cryptographic signatures. Make
|
||||||
// sure to use a Certifier to validate the signatures actually provide a
|
// sure to use a Verifier to validate the signatures actually provide a
|
||||||
// significantly strong proof for this header's validity.
|
// significantly strong proof for this header's validity.
|
||||||
func (sh SignedHeader) ValidateBasic(chainID string) error {
|
func (sh SignedHeader) ValidateBasic(chainID string) error {
|
||||||
|
|
||||||
|
@ -48,6 +48,11 @@ func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
|||||||
return vals
|
return vals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nil or empty validator sets are invalid.
|
||||||
|
func (vals *ValidatorSet) IsNilOrEmpty() bool {
|
||||||
|
return vals == nil || len(vals.Validators) == 0
|
||||||
|
}
|
||||||
|
|
||||||
// Increment Accum and update the proposer on a copy, and return it.
|
// Increment Accum and update the proposer on a copy, and return it.
|
||||||
func (vals *ValidatorSet) CopyIncrementAccum(times int) *ValidatorSet {
|
func (vals *ValidatorSet) CopyIncrementAccum(times int) *ValidatorSet {
|
||||||
copy := vals.Copy()
|
copy := vals.Copy()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user