Browse Source

cmd/lite: switch to new lite2 package (#4300)

* cmd/lite: switch to new lite2 package

* update changelog

* shorten the trusting period explanation
pull/4305/head
Anton Kaliaev 5 years ago
committed by GitHub
parent
commit
faf783331d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 98 additions and 50 deletions
  1. +9
    -0
      CHANGELOG_PENDING.md
  2. +52
    -42
      cmd/tendermint/commands/lite.go
  3. +2
    -0
      lite/doc.go
  4. +26
    -2
      lite2/client.go
  5. +8
    -5
      lite2/proxy/proxy.go
  6. +1
    -1
      lite2/verifier.go

+ 9
- 0
CHANGELOG_PENDING.md View File

@ -17,6 +17,11 @@ information in `Block#LastCommit`. `Commit` now mainly consists of a signature
and a validator address plus a timestamp. Note we may remove the validator
address & timestamp fields in the future (see ADR-25).
`lite2` package has been added to solve `lite` issues and introduce weak
subjectivity interface
https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md).
`lite` package is now deprecated and will be removed in v0.34 release.
Special thanks to external contributors on this release:
@erikgrinaker, @PSalant726, @gchaincl, @gregzaitsev, @princesinha19, @Stumble
@ -60,6 +65,9 @@ program](https://hackerone.com/tendermint).
- You will have to generate a new config for your Tendermint node(s)
- [genesis] \#2565 Add `consensus_params.evidence.max_age_duration`. Rename
`consensus_params.evidence.max_age` to `max_age_num_blocks`.
- [cli] \#1771 `tendermint lite` now uses new light client package (`lite2`)
and has 3 more flags: `--trusting-period`, `--trusted-height` and
`--trusted-hash`
- Apps
@ -124,6 +132,7 @@ program](https://hackerone.com/tendermint).
- `consensus_validator_missed_blocks`: total amount of missed blocks for a validator
as gauges in prometheus for validator specific metrics
- [rpc/lib] [\#4248](https://github.com/tendermint/tendermint/issues/4248) RPC client basic authentication support (@greg-szabo)
- [lite2] \#1771 Light client with weak subjectivity
### IMPROVEMENTS:


+ 52
- 42
cmd/tendermint/commands/lite.go View File

@ -1,15 +1,23 @@
package commands
import (
"fmt"
"net/url"
"net/http"
"time"
"github.com/pkg/errors"
"github.com/spf13/cobra"
amino "github.com/tendermint/go-amino"
dbm "github.com/tendermint/tm-db"
tmos "github.com/tendermint/tendermint/libs/os"
"github.com/tendermint/tendermint/lite/proxy"
lite "github.com/tendermint/tendermint/lite2"
httpp "github.com/tendermint/tendermint/lite2/provider/http"
lproxy "github.com/tendermint/tendermint/lite2/proxy"
lrpc "github.com/tendermint/tendermint/lite2/rpc"
dbs "github.com/tendermint/tendermint/lite2/store/db"
rpcclient "github.com/tendermint/tendermint/rpc/client"
rpcserver "github.com/tendermint/tendermint/rpc/lib/server"
)
// LiteCmd represents the base command when called without any subcommands
@ -32,7 +40,10 @@ var (
chainID string
home string
maxOpenConnections int
cacheSize int
trustingPeriod time.Duration
trustedHeight int64
trustedHash []byte
)
func init() {
@ -45,60 +56,59 @@ func init() {
"max-open-connections",
900,
"Maximum number of simultaneous connections (including WebSocket).")
LiteCmd.Flags().IntVar(&cacheSize, "cache-size", 10, "Specify the memory trust store cache size")
}
func EnsureAddrHasSchemeOrDefaultToTCP(addr string) (string, error) {
u, err := url.Parse(addr)
if err != nil {
return "", err
}
switch u.Scheme {
case "tcp", "unix":
case "":
u.Scheme = "tcp"
default:
return "", fmt.Errorf("unknown scheme %q, use either tcp or unix", u.Scheme)
}
return u.String(), nil
LiteCmd.Flags().DurationVar(&trustingPeriod, "trusting-period", 168*time.Hour, "Trusting period. Should be significantly less than the unbonding period")
LiteCmd.Flags().Int64Var(&trustedHeight, "trusted-height", 1, "Trusted header's height")
LiteCmd.Flags().BytesHexVar(&trustedHash, "trusted-hash", []byte{}, "Trusted header's hash")
}
func runProxy(cmd *cobra.Command, args []string) error {
// Stop upon receiving SIGTERM or CTRL-C.
tmos.TrapSignal(logger, func() {
// TODO: close up shop
})
liteLogger := logger.With("module", "lite")
nodeAddr, err := EnsureAddrHasSchemeOrDefaultToTCP(nodeAddr)
logger.Info("Connecting to Tendermint node...")
// First, connect a client
node, err := rpcclient.NewHTTP(nodeAddr, "/websocket")
if err != nil {
return err
return errors.Wrap(err, "new HTTP client")
}
listenAddr, err := EnsureAddrHasSchemeOrDefaultToTCP(listenAddr)
logger.Info("Creating client...")
db, err := dbm.NewGoLevelDB("lite-client-db", home)
if err != nil {
return err
}
// First, connect a client
logger.Info("Connecting to source HTTP client...")
node, err := rpcclient.NewHTTP(nodeAddr, "/websocket")
c, err := lite.NewClient(
chainID,
lite.TrustOptions{
Period: trustingPeriod,
Height: trustedHeight,
Hash: trustedHash,
},
httpp.NewWithClient(chainID, node),
dbs.New(db, chainID),
)
if err != nil {
return errors.Wrap(err, "new HTTP client")
return err
}
c.SetLogger(liteLogger)
logger.Info("Constructing Verifier...")
cert, err := proxy.NewVerifier(chainID, home, node, logger, cacheSize)
if err != nil {
return errors.Wrap(err, "constructing Verifier")
p := lproxy.Proxy{
Addr: listenAddr,
Config: &rpcserver.Config{MaxOpenConnections: maxOpenConnections},
Codec: amino.NewCodec(),
Client: lrpc.NewClient(node, c),
Logger: liteLogger,
}
cert.SetLogger(logger)
sc := proxy.SecureClient(node, cert)
// Stop upon receiving SIGTERM or CTRL-C.
tmos.TrapSignal(liteLogger, func() {
p.Listener.Close()
})
logger.Info("Starting proxy...")
err = proxy.StartProxy(sc, listenAddr, logger, maxOpenConnections)
if err != nil {
return errors.Wrap(err, "starting proxy")
if err := p.ListenAndServe(); err != http.ErrServerClosed {
// Error starting or closing listener:
logger.Error("proxy ListenAndServe", "err", err)
}
// Run forever
select {}
return nil
}

+ 2
- 0
lite/doc.go View File

@ -1,4 +1,6 @@
/*
Package lite is deprecated and will be removed in v0.34!
Package lite allows you to securely validate headers without a full node.
This library pulls together all the crypto and algorithms, so given a


+ 26
- 2
lite2/client.go View File

@ -214,6 +214,8 @@ func (c *Client) restoreTrustedHeaderAndNextVals() error {
c.trustedHeader = trustedHeader
c.trustedNextVals = trustedNextVals
c.logger.Debug("Restored trusted header and next vals", lastHeight)
}
return nil
@ -249,6 +251,10 @@ func (c *Client) checkTrustedHeaderUsingOptions(options TrustOptions) error {
case options.Height == c.trustedHeader.Height:
primaryHash = options.Hash
case options.Height < c.trustedHeader.Height:
c.logger.Info("Client initialized with old header (trusted is more recent)",
"old", options.Height,
"trusted", c.trustedHeader.Height)
action := fmt.Sprintf(
"Rollback to %d (%X)? Note this will remove newer headers up to %d (%X)",
options.Height, options.Hash,
@ -258,6 +264,9 @@ func (c *Client) checkTrustedHeaderUsingOptions(options TrustOptions) error {
c.cleanup(options.Height + 1)
// set c.trustedHeader to one at options.Height
c.restoreTrustedHeaderAndNextVals()
c.logger.Info("Rolled back to older header (newer headers were removed)",
"old", options.Height)
} else {
return errors.New("rollback aborted")
}
@ -266,8 +275,8 @@ func (c *Client) checkTrustedHeaderUsingOptions(options TrustOptions) error {
}
if !bytes.Equal(primaryHash, c.trustedHeader.Hash()) {
c.logger.Info("Prev. trusted header's hash %X doesn't match hash %X from primary provider",
c.trustedHeader.Hash(), primaryHash)
c.logger.Info("Prev. trusted header's hash (h1) doesn't match hash from primary provider (h2)",
"h1", c.trustedHeader.Hash(), "h1", primaryHash)
action := fmt.Sprintf(
"Prev. trusted header's hash %X doesn't match hash %X from primary provider. Remove all the stored headers?",
@ -398,6 +407,8 @@ func (c *Client) ChainID() string {
//
// If the trusted header is more recent than one here, an error is returned.
func (c *Client) VerifyHeaderAtHeight(height int64, now time.Time) (*types.SignedHeader, error) {
c.logger.Info("VerifyHeaderAtHeight", "height", height)
if c.trustedHeader.Height >= height {
return nil, errors.Errorf("header at more recent height #%d exists", c.trustedHeader.Height)
}
@ -425,6 +436,8 @@ func (c *Client) VerifyHeaderAtHeight(height int64, now time.Time) (*types.Signe
//
// If the trusted header is more recent than one here, an error is returned.
func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.ValidatorSet, now time.Time) error {
c.logger.Info("VerifyHeader", "height", newHeader.Hash(), "newVals", newVals.Hash())
if c.trustedHeader.Height >= newHeader.Height {
return errors.Errorf("header at more recent height #%d exists", c.trustedHeader.Height)
}
@ -458,6 +471,7 @@ func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.Vali
// Cleanup removes all the data (headers and validator sets) stored.
func (c *Client) Cleanup() error {
c.logger.Info("Cleanup everything")
return c.cleanup(0)
}
@ -507,6 +521,11 @@ func (c *Client) sequence(newHeader *types.SignedHeader, newVals *types.Validato
return errors.Wrapf(err, "failed to obtain the header #%d", height)
}
c.logger.Debug("Verify newHeader against lastHeader",
"lastHeight", c.trustedHeader.Height,
"lastHash", c.trustedHeader.Hash(),
"newHeight", interimHeader.Height,
"newHash", interimHeader.Hash())
err = Verify(c.chainID, c.trustedHeader, c.trustedNextVals, interimHeader, c.trustedNextVals,
c.trustingPeriod, now, c.trustLevel)
if err != nil {
@ -540,6 +559,11 @@ func (c *Client) bisection(
newVals *types.ValidatorSet,
now time.Time) error {
c.logger.Debug("Verify newHeader against lastHeader",
"lastHeight", lastHeader.Height,
"lastHash", lastHeader.Hash(),
"newHeight", newHeader.Height,
"newHash", newHeader.Hash())
err := Verify(c.chainID, lastHeader, lastVals, newHeader, newVals, c.trustingPeriod, now, c.trustLevel)
switch err.(type) {
case nil:


+ 8
- 5
lite2/proxy/proxy.go View File

@ -18,11 +18,12 @@ import (
// A Proxy defines parameters for running an HTTP server proxy.
type Proxy struct {
Addr string // TCP address to listen on, ":http" if empty
Config *rpcserver.Config
Codec *amino.Codec
Client *lrpc.Client
Logger log.Logger
Addr string // TCP address to listen on, ":http" if empty
Config *rpcserver.Config
Codec *amino.Codec
Client *lrpc.Client
Logger log.Logger
Listener net.Listener
}
// ListenAndServe configures the rpcserver.WebsocketManager, sets up the RPC
@ -34,6 +35,7 @@ func (p *Proxy) ListenAndServe() error {
if err != nil {
return err
}
p.Listener = listener
return rpcserver.StartHTTPServer(
listener,
@ -51,6 +53,7 @@ func (p *Proxy) ListenAndServeTLS(certFile, keyFile string) error {
if err != nil {
return err
}
p.Listener = listener
return rpcserver.StartHTTPAndTLSServer(
listener,


+ 1
- 1
lite2/verifier.go View File

@ -19,7 +19,7 @@ var (
// Verify verifies the new header (h2) against the old header (h1). It ensures that:
//
// a) h1 can still be trusted (if not, ErrOldHeaderExpired is returned);
// b) h2 is valid (if not, ErrInvalidNewHeader is returned);
// b) h2 is valid;
// c) either h2.ValidatorsHash equals h1NextVals.Hash()
// OR trustLevel ([1/3, 1]) of last trusted validators (h1NextVals) signed
// correctly (if not, ErrNewValSetCantBeTrusted is returned);


Loading…
Cancel
Save