Files
tendermint/lite2/proxy/proxy.go
Anton Kaliaev fb8b00f1d8 lite2: light client with weak subjectivity (#3989)
Refs #1771

ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md

## Commits:

* add Verifier and VerifyCommitTrusting

* add two more checks

make trustLevel an option

* float32 for trustLevel

* check newHeader time

* started writing lite Client

* unify Verify methods

* ensure h2.Header.bfttime < h1.Header.bfttime + tp

* move trust checks into Verify function

* add more comments

* more docs

* started writing tests

* unbonding period failures

* tests are green

* export ErrNewHeaderTooFarIntoFuture

* make golangci happy

* test for non-adjusted headers

* more precision

* providers and stores

* VerifyHeader and VerifyHeaderAtHeight funcs

* fix compile errors

* remove lastVerifiedHeight, persist new trusted header

* sequential verification

* remove TrustedStore option

* started writing tests for light client

* cover basic cases for linear verification

* bisection tests PASS

* rename BisectingVerification to SkippingVerification

* refactor the code

* add TrustedHeader method

* consolidate sequential verification tests

* consolidate skipping verification tests

* rename trustedVals to trustedNextVals

* start writing docs

* ValidateTrustLevel func and ErrOldHeaderExpired error

* AutoClient and example tests

* fix errors

* update doc

* remove ErrNewHeaderTooFarIntoFuture

This check is unnecessary given existing a) ErrOldHeaderExpired b)
h2.Time > now checks.

* return an error if we're at more recent height

* add comments

* add LastSignedHeaderHeight method to Store

I think it's fine if Store tracks last height

* copy over proxy from old lite package

* make TrustedHeader return latest if height=0

* modify LastSignedHeaderHeight to return an error if no headers exist

* copy over proxy impl

* refactor proxy and start http lite client

* Tx and BlockchainInfo methods

* Block method

* commit method

* code compiles again

* lite client compiles

* extract updateLiteClientIfNeededTo func

* move final parts

* add placeholder for tests

* force usage of lite http client in proxy

* comment out query tests for now

* explicitly mention tp: trusting period

* verify nextVals in VerifyHeader

* refactor bisection

* move the NextValidatorsHash check into updateTrustedHeaderAndVals

+ update the comment

* add ConsensusParams method to RPC client

* add ConsensusParams to rpc/mock/client

* change trustLevel type to a new cmn.Fraction type

+ update SkippingVerification comment

* stress out trustLevel is only used for non-adjusted headers

* fixes after Fede's review

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* compare newHeader with a header from an alternative provider

* save pivot header

Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824

* check header can still be trusted in TrustedHeader

Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424

* lite: update Validators and Block endpoints

- Block no longer contains BlockMeta
- Validators now accept two additional params: page and perPage

* make linter happy
2019-11-25 19:07:40 +04:00

103 lines
2.5 KiB
Go

package proxy
import (
"context"
"net"
"net/http"
"github.com/pkg/errors"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/libs/log"
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
lrpc "github.com/tendermint/tendermint/lite2/rpc"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
rpcserver "github.com/tendermint/tendermint/rpc/lib/server"
)
// 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
}
// ListenAndServe configures the rpcserver.WebsocketManager, sets up the RPC
// routes to proxy via Client, and starts up an HTTP server on the TCP network
// address p.Addr.
// See http#Server#ListenAndServe.
func (p *Proxy) ListenAndServe() error {
listener, mux, err := p.listen()
if err != nil {
return err
}
return rpcserver.StartHTTPServer(
listener,
mux,
p.Logger,
p.Config,
)
}
// ListenAndServeTLS acts identically to ListenAndServe, except that it expects
// HTTPS connections.
// See http#Server#ListenAndServeTLS.
func (p *Proxy) ListenAndServeTLS(certFile, keyFile string) error {
listener, mux, err := p.listen()
if err != nil {
return err
}
return rpcserver.StartHTTPAndTLSServer(
listener,
mux,
certFile,
keyFile,
p.Logger,
p.Config,
)
}
func (p *Proxy) listen() (net.Listener, *http.ServeMux, error) {
ctypes.RegisterAmino(p.Codec)
mux := http.NewServeMux()
// 1) Register regular routes.
r := RPCRoutes(p.Client)
rpcserver.RegisterRPCFuncs(mux, r, p.Codec, p.Logger)
// 2) Allow websocket connections.
wmLogger := p.Logger.With("protocol", "websocket")
wm := rpcserver.NewWebsocketManager(r, p.Codec,
rpcserver.OnDisconnect(func(remoteAddr string) {
err := p.Client.UnsubscribeAll(context.Background(), remoteAddr)
if err != nil && err != tmpubsub.ErrSubscriptionNotFound {
wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err)
}
}),
rpcserver.ReadLimit(p.Config.MaxBodyBytes),
)
wm.SetLogger(wmLogger)
mux.HandleFunc("/websocket", wm.WebsocketHandler)
// 3) Start a client.
if !p.Client.IsRunning() {
if err := p.Client.Start(); err != nil {
return nil, mux, errors.Wrap(err, "Client#Start")
}
}
// 4) Start listening for new connections.
listener, err := rpcserver.Listen(p.Addr, p.Config)
if err != nil {
return nil, mux, err
}
return listener, mux, nil
}