diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index c40eb65ba..a8af8a7e8 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -20,6 +20,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi - sr25519: type `PrivKeySr25519` is now `PrivKey` - sr25519: type `PubKeySr25519` is now `PubKey` - multisig: type `PubKeyMultisigThreshold` is now `PubKey` + - [light] \#4946 Rename `lite2` pkg to `light`, the lite cmd has also been renamed to `light`. Remove `lite` implementation. - Apps diff --git a/cmd/tendermint/commands/lite.go b/cmd/tendermint/commands/lite.go index c1b146d29..15fe6f286 100644 --- a/cmd/tendermint/commands/lite.go +++ b/cmd/tendermint/commands/lite.go @@ -14,17 +14,17 @@ import ( "github.com/tendermint/tendermint/libs/log" tmos "github.com/tendermint/tendermint/libs/os" - lite "github.com/tendermint/tendermint/lite2" - lproxy "github.com/tendermint/tendermint/lite2/proxy" - lrpc "github.com/tendermint/tendermint/lite2/rpc" - dbs "github.com/tendermint/tendermint/lite2/store/db" + "github.com/tendermint/tendermint/light" + lproxy "github.com/tendermint/tendermint/light/proxy" + lrpc "github.com/tendermint/tendermint/light/rpc" + dbs "github.com/tendermint/tendermint/light/store/db" rpchttp "github.com/tendermint/tendermint/rpc/client/http" rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" ) -// LiteCmd represents the base command when called without any subcommands -var LiteCmd = &cobra.Command{ - Use: "lite [chainID]", +// LightCmd represents the base command when called without any subcommands +var LightCmd = &cobra.Command{ + Use: "light [chainID]", Short: "Run a light client proxy server, verifying Tendermint rpc", Long: `Run a light client proxy server, verifying Tendermint rpc. @@ -36,16 +36,16 @@ Example: start a fresh instance: -lite cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657 +light cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657 --height 962118 --hash 28B97BE9F6DE51AC69F70E0B7BFD7E5C9CD1A595B7DC31AFF27C50D4948020CD continue from latest state: -lite cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657 +light cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657 `, RunE: runProxy, Args: cobra.ExactArgs(1), - Example: `lite cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657 + Example: `light cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657 --height 962118 --hash 28B97BE9F6DE51AC69F70E0B7BFD7E5C9CD1A595B7DC31AFF27C50D4948020CD`, } @@ -65,23 +65,23 @@ var ( ) func init() { - LiteCmd.Flags().StringVar(&listenAddr, "laddr", "tcp://localhost:8888", + LightCmd.Flags().StringVar(&listenAddr, "laddr", "tcp://localhost:8888", "Serve the proxy on the given address") - LiteCmd.Flags().StringVarP(&primaryAddr, "primary", "p", "", + LightCmd.Flags().StringVarP(&primaryAddr, "primary", "p", "", "Connect to a Tendermint node at this address") - LiteCmd.Flags().StringVarP(&witnessAddrsJoined, "witnesses", "w", "", + LightCmd.Flags().StringVarP(&witnessAddrsJoined, "witnesses", "w", "", "Tendermint nodes to cross-check the primary node, comma-separated") - LiteCmd.Flags().StringVar(&home, "home-dir", ".tendermint-lite", "Specify the home directory") - LiteCmd.Flags().IntVar( + LightCmd.Flags().StringVar(&home, "home-dir", ".tendermint-light", "Specify the home directory") + LightCmd.Flags().IntVar( &maxOpenConnections, "max-open-connections", 900, "Maximum number of simultaneous connections (including WebSocket).") - LiteCmd.Flags().DurationVar(&trustingPeriod, "trusting-period", 168*time.Hour, + LightCmd.Flags().DurationVar(&trustingPeriod, "trusting-period", 168*time.Hour, "Trusting period. Should be significantly less than the unbonding period") - LiteCmd.Flags().Int64Var(&trustedHeight, "height", 1, "Trusted header's height") - LiteCmd.Flags().BytesHexVar(&trustedHash, "hash", []byte{}, "Trusted header's hash") - LiteCmd.Flags().BoolVar(&verbose, "verbose", false, "Verbose output") + LightCmd.Flags().Int64Var(&trustedHeight, "height", 1, "Trusted header's height") + LightCmd.Flags().BytesHexVar(&trustedHash, "hash", []byte{}, "Trusted header's hash") + LightCmd.Flags().BoolVar(&verbose, "verbose", false, "Verbose output") } func runProxy(cmd *cobra.Command, args []string) error { @@ -100,16 +100,16 @@ func runProxy(cmd *cobra.Command, args []string) error { witnessesAddrs := strings.Split(witnessAddrsJoined, ",") - db, err := dbm.NewGoLevelDB("lite-client-db", home) + db, err := dbm.NewGoLevelDB("light-client-db", home) if err != nil { return fmt.Errorf("can't create a db: %w", err) } - var c *lite.Client + var c *light.Client if trustedHeight > 0 && len(trustedHash) > 0 { // fresh installation - c, err = lite.NewHTTPClient( + c, err = light.NewHTTPClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: trustingPeriod, Height: trustedHeight, Hash: trustedHash, @@ -117,16 +117,16 @@ func runProxy(cmd *cobra.Command, args []string) error { primaryAddr, witnessesAddrs, dbs.New(db, chainID), - lite.Logger(logger), + light.Logger(logger), ) } else { // continue from latest state - c, err = lite.NewHTTPClientFromTrustedStore( + c, err = light.NewHTTPClientFromTrustedStore( chainID, trustingPeriod, primaryAddr, witnessesAddrs, dbs.New(db, chainID), - lite.Logger(logger), + light.Logger(logger), ) } if err != nil { diff --git a/cmd/tendermint/main.go b/cmd/tendermint/main.go index 615b7e065..311a59a65 100644 --- a/cmd/tendermint/main.go +++ b/cmd/tendermint/main.go @@ -17,7 +17,7 @@ func main() { cmd.GenValidatorCmd, cmd.InitFilesCmd, cmd.ProbeUpnpCmd, - cmd.LiteCmd, + cmd.LightCmd, cmd.ReplayCmd, cmd.ReplayConsoleCmd, cmd.ResetAllCmd, diff --git a/docs/app-dev/app-development.md b/docs/app-dev/app-development.md index 9c1acc289..b2a4d6c43 100644 --- a/docs/app-dev/app-development.md +++ b/docs/app-dev/app-development.md @@ -316,7 +316,7 @@ field can be left empty. Tendermint core will take care of updating the validator set. Note the change in voting power must be strictly less than 1/3 per block if you want a light client to be able to prove the transition externally. See the [light client -docs](https://godoc.org/github.com/tendermint/tendermint/lite#hdr-How_We_Track_Validators) +docs](https://godoc.org/github.com/tendermint/tendermint/light#hdr-How_We_Track_Validators) for details on how it tracks validators. In go: diff --git a/docs/guides/go-built-in.md b/docs/guides/go-built-in.md index 23c3d16d9..5822136a6 100644 --- a/docs/guides/go-built-in.md +++ b/docs/guides/go-built-in.md @@ -288,7 +288,7 @@ the application's `Query` method. Applications are free to provide their own APIs. But by using Tendermint Core as a proxy, clients (including [light client -package](https://godoc.org/github.com/tendermint/tendermint/lite2)) can leverage +package](https://godoc.org/github.com/tendermint/tendermint/light)) can leverage the unified API across different applications. Plus they won't have to call the otherwise separate Tendermint Core API for additional proofs. diff --git a/docs/guides/java.md b/docs/guides/java.md index 12bbc4565..2987766f3 100644 --- a/docs/guides/java.md +++ b/docs/guides/java.md @@ -430,7 +430,7 @@ the application's `Query` method. Applications are free to provide their own APIs. But by using Tendermint Core as a proxy, clients (including [light client -package](https://godoc.org/github.com/tendermint/tendermint/lite)) can leverage +package](https://godoc.org/github.com/tendermint/tendermint/light)) can leverage the unified API across different applications. Plus they won't have to call the otherwise separate Tendermint Core API for additional proofs. diff --git a/docs/guides/kotlin.md b/docs/guides/kotlin.md index 0c15098a4..c3cc2f64d 100644 --- a/docs/guides/kotlin.md +++ b/docs/guides/kotlin.md @@ -410,7 +410,7 @@ the application's `Query` method. Applications are free to provide their own APIs. But by using Tendermint Core as a proxy, clients (including [light client -package](https://godoc.org/github.com/tendermint/tendermint/lite)) can leverage +package](https://godoc.org/github.com/tendermint/tendermint/light)) can leverage the unified API across different applications. Plus they won't have to call the otherwise separate Tendermint Core API for additional proofs. diff --git a/docs/tendermint-core/configuration.md b/docs/tendermint-core/configuration.md index 141645f26..4bebd11dd 100644 --- a/docs/tendermint-core/configuration.md +++ b/docs/tendermint-core/configuration.md @@ -361,7 +361,7 @@ Note after the block H, Tendermint creates something we call a "proof block" (only if the application hash changed) H+1. The reason for this is to support proofs. If you have a transaction in block H that changes the state to X, the new application hash will only be included in block H+1. If after your -transaction is committed, you want to get a lite-client proof for the new state +transaction is committed, you want to get a light-client proof for the new state (X), you need the new block to be committed in order to do that because the new block has the new application hash for the state X. That's why we make a new (empty) block if the application hash changes. Otherwise, you won't be able to diff --git a/docs/tendermint-core/light-client-protocol.md b/docs/tendermint-core/light-client-protocol.md index 41b7a0e07..8165ed4ff 100644 --- a/docs/tendermint-core/light-client-protocol.md +++ b/docs/tendermint-core/light-client-protocol.md @@ -8,8 +8,8 @@ Light clients are an important part of the complete blockchain system for most applications. Tendermint provides unique speed and security properties for light client applications. -See our [lite -package](https://pkg.go.dev/github.com/tendermint/tendermint/lite2?tab=doc). +See our [light +package](https://pkg.go.dev/github.com/tendermint/tendermint/light?tab=doc). ## Overview @@ -33,7 +33,7 @@ proofs](https://github.com/tendermint/spec/blob/953523c3cb99fdb8c8f7a2d21e3a9909 ## Where to obtain trusted height & hash? -https://pkg.go.dev/github.com/tendermint/tendermint/lite2?tab=doc#TrustOptions +https://pkg.go.dev/github.com/tendermint/tendermint/light?tab=doc#TrustOptions One way to obtain semi-trusted hash & height is to query multiple full nodes and compare their hashes: @@ -48,16 +48,16 @@ $ curl -s https://233.123.0.140:26657:26657/commit | jq "{height: .result.signed ## HTTP proxy -Tendermint comes with a built-in `tendermint lite` command, which can be used +Tendermint comes with a built-in `tendermint light` command, which can be used to run a light client proxy server, verifying Tendermint rpc. All calls that can be tracked back to a block header by a proof will be verified before passing them back to the caller. Other than that, it will present the same interface as a full Tendermint node. ```sh -$ tendermint lite supernova -p tcp://233.123.0.140:26657 \ +$ tendermint light supernova -p tcp://233.123.0.140:26657 \ -w tcp://179.63.29.15:26657,tcp://144.165.223.135:26657 \ --height=10 --hash=37E9A6DD3FA25E83B22C18835401E8E56088D0D7ABC6FD99FCDC920DD76C1C57 ``` -For additional options, run `tendermint lite --help`. +For additional options, run `tendermint light --help`. diff --git a/lite2/client.go b/light/client.go similarity index 99% rename from lite2/client.go rename to light/client.go index 1b8913bb9..8dd624425 100644 --- a/lite2/client.go +++ b/light/client.go @@ -1,4 +1,4 @@ -package lite +package light import ( "bytes" @@ -10,8 +10,8 @@ import ( "github.com/tendermint/tendermint/libs/log" tmmath "github.com/tendermint/tendermint/libs/math" - "github.com/tendermint/tendermint/lite2/provider" - "github.com/tendermint/tendermint/lite2/store" + "github.com/tendermint/tendermint/light/provider" + "github.com/tendermint/tendermint/light/store" "github.com/tendermint/tendermint/types" ) @@ -68,7 +68,7 @@ func SkippingVerification(trustLevel tmmath.Fraction) Option { // that the light client stores. When Prune() is run, all headers (along with // the associated validator sets) that are earlier than the h amount of headers // will be removed from the store. Default: 1000. A pruning size of 0 will not -// prune the lite client at all. +// prune the light client at all. func PruningSize(h uint16) Option { return func(c *Client) { c.pruningSize = h @@ -120,7 +120,7 @@ type Client struct { maxRetryAttempts uint16 // see MaxRetryAttempts option maxClockDrift time.Duration - // Mutex for locking during changes of the lite clients providers + // Mutex for locking during changes of the light clients providers providerMutex sync.Mutex // Primary provider of new headers. primary provider.Provider diff --git a/lite2/client_benchmark_test.go b/light/client_benchmark_test.go similarity index 79% rename from lite2/client_benchmark_test.go rename to light/client_benchmark_test.go index 5877dbc3c..ef0494c99 100644 --- a/lite2/client_benchmark_test.go +++ b/light/client_benchmark_test.go @@ -1,4 +1,4 @@ -package lite_test +package light_test import ( "testing" @@ -7,10 +7,10 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/tendermint/tendermint/libs/log" - lite "github.com/tendermint/tendermint/lite2" - "github.com/tendermint/tendermint/lite2/provider" - mockp "github.com/tendermint/tendermint/lite2/provider/mock" - dbs "github.com/tendermint/tendermint/lite2/store/db" + "github.com/tendermint/tendermint/light" + "github.com/tendermint/tendermint/light/provider" + mockp "github.com/tendermint/tendermint/light/provider/mock" + dbs "github.com/tendermint/tendermint/light/store/db" ) // NOTE: block is produced every minute. Make sure the verification time @@ -26,9 +26,9 @@ var ( ) func BenchmarkSequence(b *testing.B) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 24 * time.Hour, Height: 1, Hash: genesisHeader.Hash(), @@ -36,8 +36,8 @@ func BenchmarkSequence(b *testing.B) { benchmarkFullNode, []provider.Provider{benchmarkFullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), - lite.SequentialVerification(), + light.Logger(log.TestingLogger()), + light.SequentialVerification(), ) if err != nil { b.Fatal(err) @@ -53,9 +53,9 @@ func BenchmarkSequence(b *testing.B) { } func BenchmarkBisection(b *testing.B) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 24 * time.Hour, Height: 1, Hash: genesisHeader.Hash(), @@ -63,7 +63,7 @@ func BenchmarkBisection(b *testing.B) { benchmarkFullNode, []provider.Provider{benchmarkFullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) if err != nil { b.Fatal(err) @@ -80,9 +80,9 @@ func BenchmarkBisection(b *testing.B) { func BenchmarkBackwards(b *testing.B) { trustedHeader, _ := benchmarkFullNode.SignedHeader(0) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 24 * time.Hour, Height: trustedHeader.Height, Hash: trustedHeader.Hash(), @@ -90,7 +90,7 @@ func BenchmarkBackwards(b *testing.B) { benchmarkFullNode, []provider.Provider{benchmarkFullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) if err != nil { b.Fatal(err) diff --git a/lite2/client_test.go b/light/client_test.go similarity index 92% rename from lite2/client_test.go rename to light/client_test.go index b2b9881a8..d51581558 100644 --- a/lite2/client_test.go +++ b/light/client_test.go @@ -1,4 +1,4 @@ -package lite_test +package light_test import ( "sync" @@ -11,10 +11,10 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/tendermint/tendermint/libs/log" - lite "github.com/tendermint/tendermint/lite2" - "github.com/tendermint/tendermint/lite2/provider" - mockp "github.com/tendermint/tendermint/lite2/provider/mock" - dbs "github.com/tendermint/tendermint/lite2/store/db" + "github.com/tendermint/tendermint/light" + "github.com/tendermint/tendermint/light/provider" + mockp "github.com/tendermint/tendermint/light/provider/mock" + dbs "github.com/tendermint/tendermint/light/store/db" "github.com/tendermint/tendermint/types" ) @@ -35,7 +35,7 @@ var ( h3 = keys.GenSignedHeaderLastBlockID(chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals, hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys), types.BlockID{Hash: h2.Hash()}) trustPeriod = 4 * time.Hour - trustOptions = lite.TrustOptions{ + trustOptions = light.TrustOptions{ Period: 4 * time.Hour, Height: 1, Hash: h1.Hash(), @@ -141,7 +141,7 @@ func TestClient_SequentialVerification(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, mockp.New( @@ -155,7 +155,7 @@ func TestClient_SequentialVerification(t *testing.T) { tc.vals, )}, dbs.New(dbm.NewMemDB(), chainID), - lite.SequentialVerification(), + light.SequentialVerification(), ) if tc.initErr { @@ -264,7 +264,7 @@ func TestClient_SkippingVerification(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, mockp.New( @@ -278,7 +278,7 @@ func TestClient_SkippingVerification(t *testing.T) { tc.vals, )}, dbs.New(dbm.NewMemDB(), chainID), - lite.SkippingVerification(lite.DefaultTrustLevel), + light.SkippingVerification(light.DefaultTrustLevel), ) if tc.initErr { require.Error(t, err) @@ -301,9 +301,9 @@ func TestClient_SkippingVerification(t *testing.T) { veryLargeFullNode := mockp.New(GenMockNode(chainID, 100, 3, 1, bTime)) h1, err := veryLargeFullNode.SignedHeader(90) require.NoError(t, err) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 4 * time.Hour, Height: 90, Hash: h1.Hash(), @@ -311,7 +311,7 @@ func TestClient_SkippingVerification(t *testing.T) { veryLargeFullNode, []provider.Provider{veryLargeFullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.SkippingVerification(lite.DefaultTrustLevel), + light.SkippingVerification(light.DefaultTrustLevel), ) require.NoError(t, err) h, err := c.Update(bTime.Add(100 * time.Minute)) @@ -322,13 +322,13 @@ func TestClient_SkippingVerification(t *testing.T) { } func TestClient_Cleanup(t *testing.T) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{fullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) _, err = c.TrustedHeader(1) @@ -355,13 +355,13 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) { err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals) require.NoError(t, err) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{fullNode}, trustedStore, - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -397,9 +397,9 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) { valSet, ) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 4 * time.Hour, Height: 1, Hash: header1.Hash(), @@ -407,7 +407,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) { primary, []provider.Provider{primary}, trustedStore, - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -434,9 +434,9 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) { err := trustedStore.SaveSignedHeaderAndValidatorSet(h1, vals) require.NoError(t, err) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 4 * time.Hour, Height: 2, Hash: h2.Hash(), @@ -444,7 +444,7 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) { fullNode, []provider.Provider{fullNode}, trustedStore, - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -485,9 +485,9 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) { valSet, ) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 4 * time.Hour, Height: 2, Hash: diffHeader2.Hash(), @@ -495,7 +495,7 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) { primary, []provider.Provider{primary}, trustedStore, - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -523,13 +523,13 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) { err = trustedStore.SaveSignedHeaderAndValidatorSet(h2, vals) require.NoError(t, err) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{fullNode}, trustedStore, - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -580,9 +580,9 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) { valSet, ) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 4 * time.Hour, Height: 1, Hash: header1.Hash(), @@ -590,7 +590,7 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) { primary, []provider.Provider{primary}, trustedStore, - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -619,13 +619,13 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) { } func TestClient_Update(t *testing.T) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{fullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -644,13 +644,13 @@ func TestClient_Update(t *testing.T) { } func TestClient_Concurrency(t *testing.T) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{fullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -688,14 +688,14 @@ func TestClient_Concurrency(t *testing.T) { } func TestClientReplacesPrimaryWithWitnessIfPrimaryIsUnavailable(t *testing.T) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, deadNode, []provider.Provider{fullNode, fullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), - lite.MaxRetryAttempts(1), + light.Logger(log.TestingLogger()), + light.MaxRetryAttempts(1), ) require.NoError(t, err) @@ -709,9 +709,9 @@ func TestClientReplacesPrimaryWithWitnessIfPrimaryIsUnavailable(t *testing.T) { func TestClient_BackwardsVerification(t *testing.T) { { trustHeader, _ := largeFullNode.SignedHeader(6) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 4 * time.Minute, Height: trustHeader.Height, Hash: trustHeader.Hash(), @@ -719,7 +719,7 @@ func TestClient_BackwardsVerification(t *testing.T) { largeFullNode, []provider.Provider{largeFullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -794,9 +794,9 @@ func TestClient_BackwardsVerification(t *testing.T) { } for _, tc := range testCases { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 1 * time.Hour, Height: 3, Hash: h3.Hash(), @@ -804,7 +804,7 @@ func TestClient_BackwardsVerification(t *testing.T) { tc.provider, []provider.Provider{tc.provider}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -820,7 +820,7 @@ func TestClient_NewClientFromTrustedStore(t *testing.T) { err := db.SaveSignedHeaderAndValidatorSet(h1, vals) require.NoError(t, err) - c, err := lite.NewClientFromTrustedStore( + c, err := light.NewClientFromTrustedStore( chainID, trustPeriod, deadNode, @@ -844,14 +844,14 @@ func TestClient_NewClientFromTrustedStore(t *testing.T) { } func TestNewClientErrorsIfAllWitnessesUnavailable(t *testing.T) { - _, err := lite.NewClient( + _, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{deadNode, deadNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), - lite.MaxRetryAttempts(1), + light.Logger(log.TestingLogger()), + light.MaxRetryAttempts(1), ) if assert.Error(t, err) { assert.Contains(t, err.Error(), "awaiting response from all witnesses exceeded dropout time") @@ -887,14 +887,14 @@ func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) { }, ) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{badProvider1, badProvider2}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), - lite.MaxRetryAttempts(1), + light.Logger(log.TestingLogger()), + light.MaxRetryAttempts(1), ) // witness should have behaved properly -> no error require.NoError(t, err) @@ -914,13 +914,13 @@ func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) { } func TestClientTrustedValidatorSet(t *testing.T) { - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{fullNode}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), + light.Logger(log.TestingLogger()), ) require.NoError(t, err) @@ -951,14 +951,14 @@ func TestClientReportsConflictingHeadersEvidence(t *testing.T) { }, ) - c, err := lite.NewClient( + c, err := light.NewClient( chainID, trustOptions, fullNode, []provider.Provider{fullNode2}, dbs.New(dbm.NewMemDB(), chainID), - lite.Logger(log.TestingLogger()), - lite.MaxRetryAttempts(1), + light.Logger(log.TestingLogger()), + light.MaxRetryAttempts(1), ) require.NoError(t, err) diff --git a/lite2/doc.go b/light/doc.go similarity index 92% rename from lite2/doc.go rename to light/doc.go index f42aa64f1..700bbeb6c 100644 --- a/lite2/doc.go +++ b/light/doc.go @@ -1,5 +1,5 @@ /* -Package lite provides a light client implementation. +package light provides a light client implementation. The concept of light clients was introduced in the Bitcoin white paper. It describes a watcher of distributed consensus process that only validates the @@ -14,7 +14,7 @@ chain's state machine). In a network that is expected to reliably punish validators for misbehavior by slashing bonded stake and where the validator set changes infrequently, clients -can take advantage of this assumption to safely synchronize a lite client +can take advantage of this assumption to safely synchronize a light client without downloading the intervening headers. Light clients (and full nodes) operating in the Proof Of Stake context need a @@ -41,15 +41,15 @@ precommit-vote signatures to prove its validity (> 2/3 of the voting power) given the validator set responsible for signing that header. The hash of the next validator set is included and signed in the SignedHeader. -This lets the lite client keep track of arbitrary changes to the validator set, +This lets the light client keep track of arbitrary changes to the validator set, as every change to the validator set must be approved by inclusion in the header and signed in the commit. In the worst case, with every block changing the validators around completely, -a lite client can sync up with every block header to verify each validator set +a light client can sync up with every block header to verify each validator set 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 -lite client syncing is optimized to use intelligent bisection. +light client syncing is optimized to use intelligent bisection. # What this package provides @@ -63,7 +63,7 @@ This package provides three major things: Example usage: - db, err := dbm.NewGoLevelDB("lite-client-db", dbDir) + db, err := dbm.NewGoLevelDB("light-client-db", dbDir) if err != nil { // handle error } @@ -124,4 +124,4 @@ Or see https://github.com/tendermint/spec/tree/master/spec/consensus/light-client for the full spec */ -package lite +package light diff --git a/lite2/errors.go b/light/errors.go similarity index 97% rename from lite2/errors.go rename to light/errors.go index e6bb39359..d40200110 100644 --- a/lite2/errors.go +++ b/light/errors.go @@ -1,10 +1,10 @@ -package lite +package light import ( "fmt" "time" - "github.com/tendermint/tendermint/lite2/provider" + "github.com/tendermint/tendermint/light/provider" "github.com/tendermint/tendermint/types" ) diff --git a/lite2/example_test.go b/light/example_test.go similarity index 84% rename from lite2/example_test.go rename to light/example_test.go index 0de5f1349..bd8aec92f 100644 --- a/lite2/example_test.go +++ b/light/example_test.go @@ -1,4 +1,4 @@ -package lite_test +package light_test import ( "fmt" @@ -11,10 +11,10 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/tendermint/tendermint/abci/example/kvstore" - lite "github.com/tendermint/tendermint/lite2" - "github.com/tendermint/tendermint/lite2/provider" - httpp "github.com/tendermint/tendermint/lite2/provider/http" - dbs "github.com/tendermint/tendermint/lite2/store/db" + "github.com/tendermint/tendermint/light" + "github.com/tendermint/tendermint/light/provider" + httpp "github.com/tendermint/tendermint/light/provider/http" + dbs "github.com/tendermint/tendermint/light/store/db" rpctest "github.com/tendermint/tendermint/rpc/test" ) @@ -23,7 +23,7 @@ func ExampleClient_Update() { // give Tendermint time to generate some blocks time.Sleep(5 * time.Second) - dbDir, err := ioutil.TempDir("", "lite-client-example") + dbDir, err := ioutil.TempDir("", "light-client-example") if err != nil { stdlog.Fatal(err) } @@ -44,14 +44,14 @@ func ExampleClient_Update() { stdlog.Fatal(err) } - db, err := dbm.NewGoLevelDB("lite-client-db", dbDir) + db, err := dbm.NewGoLevelDB("light-client-db", dbDir) if err != nil { stdlog.Fatal(err) } - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 504 * time.Hour, // 21 days Height: 2, Hash: header.Hash(), @@ -92,7 +92,7 @@ func ExampleClient_VerifyHeaderAtHeight() { // give Tendermint time to generate some blocks time.Sleep(5 * time.Second) - dbDir, err := ioutil.TempDir("", "lite-client-example") + dbDir, err := ioutil.TempDir("", "light-client-example") if err != nil { stdlog.Fatal(err) } @@ -113,14 +113,14 @@ func ExampleClient_VerifyHeaderAtHeight() { stdlog.Fatal(err) } - db, err := dbm.NewGoLevelDB("lite-client-db", dbDir) + db, err := dbm.NewGoLevelDB("light-client-db", dbDir) if err != nil { stdlog.Fatal(err) } - c, err := lite.NewClient( + c, err := light.NewClient( chainID, - lite.TrustOptions{ + light.TrustOptions{ Period: 504 * time.Hour, // 21 days Height: 2, Hash: header.Hash(), diff --git a/lite2/helpers_test.go b/light/helpers_test.go similarity index 99% rename from lite2/helpers_test.go rename to light/helpers_test.go index 4a072cb3e..7cdbac189 100644 --- a/lite2/helpers_test.go +++ b/light/helpers_test.go @@ -1,4 +1,4 @@ -package lite_test +package light_test import ( "time" diff --git a/lite2/provider/errors.go b/light/provider/errors.go similarity index 100% rename from lite2/provider/errors.go rename to light/provider/errors.go diff --git a/lite2/provider/http/http.go b/light/provider/http/http.go similarity index 98% rename from lite2/provider/http/http.go rename to light/provider/http/http.go index 360338f75..5ca3e06b1 100644 --- a/lite2/provider/http/http.go +++ b/light/provider/http/http.go @@ -6,7 +6,7 @@ import ( "regexp" "strings" - "github.com/tendermint/tendermint/lite2/provider" + "github.com/tendermint/tendermint/light/provider" rpcclient "github.com/tendermint/tendermint/rpc/client" rpchttp "github.com/tendermint/tendermint/rpc/client/http" "github.com/tendermint/tendermint/types" diff --git a/lite2/provider/http/http_test.go b/light/provider/http/http_test.go similarity index 87% rename from lite2/provider/http/http_test.go rename to light/provider/http/http_test.go index 94e14ed9b..a79103176 100644 --- a/lite2/provider/http/http_test.go +++ b/light/provider/http/http_test.go @@ -9,8 +9,8 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/example/kvstore" - "github.com/tendermint/tendermint/lite2/provider" - litehttp "github.com/tendermint/tendermint/lite2/provider/http" + "github.com/tendermint/tendermint/light/provider" + lighthttp "github.com/tendermint/tendermint/light/provider/http" rpcclient "github.com/tendermint/tendermint/rpc/client" rpchttp "github.com/tendermint/tendermint/rpc/client/http" rpctest "github.com/tendermint/tendermint/rpc/test" @@ -18,15 +18,15 @@ import ( ) func TestNewProvider(t *testing.T) { - c, err := litehttp.New("chain-test", "192.168.0.1:26657") + c, err := lighthttp.New("chain-test", "192.168.0.1:26657") require.NoError(t, err) require.Equal(t, fmt.Sprintf("%s", c), "http{http://192.168.0.1:26657}") - c, err = litehttp.New("chain-test", "http://153.200.0.1:26657") + c, err = lighthttp.New("chain-test", "http://153.200.0.1:26657") require.NoError(t, err) require.Equal(t, fmt.Sprintf("%s", c), "http{http://153.200.0.1:26657}") - c, err = litehttp.New("chain-test", "153.200.0.1") + c, err = lighthttp.New("chain-test", "153.200.0.1") require.NoError(t, err) require.Equal(t, fmt.Sprintf("%s", c), "http{http://153.200.0.1}") } @@ -56,7 +56,7 @@ func TestProvider(t *testing.T) { c, err := rpchttp.New(rpcAddr, "/websocket") require.Nil(t, err) - p := litehttp.NewWithClient(chainID, c) + p := lighthttp.NewWithClient(chainID, c) require.NoError(t, err) require.NotNil(t, p) diff --git a/lite2/provider/mock/deadmock.go b/light/provider/mock/deadmock.go similarity index 93% rename from lite2/provider/mock/deadmock.go rename to light/provider/mock/deadmock.go index 03e22570e..3dcd16c2a 100644 --- a/lite2/provider/mock/deadmock.go +++ b/light/provider/mock/deadmock.go @@ -3,7 +3,7 @@ package mock import ( "errors" - "github.com/tendermint/tendermint/lite2/provider" + "github.com/tendermint/tendermint/light/provider" "github.com/tendermint/tendermint/types" ) diff --git a/lite2/provider/mock/mock.go b/light/provider/mock/mock.go similarity index 97% rename from lite2/provider/mock/mock.go rename to light/provider/mock/mock.go index f4be90454..a948a2b63 100644 --- a/lite2/provider/mock/mock.go +++ b/light/provider/mock/mock.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/tendermint/tendermint/lite2/provider" + "github.com/tendermint/tendermint/light/provider" "github.com/tendermint/tendermint/types" ) diff --git a/lite2/provider/provider.go b/light/provider/provider.go similarity index 93% rename from lite2/provider/provider.go rename to light/provider/provider.go index 02a56f29d..8af6e8650 100644 --- a/lite2/provider/provider.go +++ b/light/provider/provider.go @@ -4,7 +4,7 @@ import ( "github.com/tendermint/tendermint/types" ) -// Provider provides information for the lite client to sync (verification +// Provider provides information for the light client to sync (verification // happens in the client). type Provider interface { // ChainID returns the blockchain ID. diff --git a/lite2/proxy/proxy.go b/light/proxy/proxy.go similarity index 98% rename from lite2/proxy/proxy.go rename to light/proxy/proxy.go index eb7257f0a..0ab1600da 100644 --- a/lite2/proxy/proxy.go +++ b/light/proxy/proxy.go @@ -10,7 +10,7 @@ import ( "github.com/tendermint/tendermint/libs/log" tmpubsub "github.com/tendermint/tendermint/libs/pubsub" - lrpc "github.com/tendermint/tendermint/lite2/rpc" + lrpc "github.com/tendermint/tendermint/light/rpc" ctypes "github.com/tendermint/tendermint/rpc/core/types" rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" ) diff --git a/lite2/proxy/routes.go b/light/proxy/routes.go similarity index 99% rename from lite2/proxy/routes.go rename to light/proxy/routes.go index ac85bfe15..cb2bc363c 100644 --- a/lite2/proxy/routes.go +++ b/light/proxy/routes.go @@ -2,7 +2,7 @@ package proxy import ( "github.com/tendermint/tendermint/libs/bytes" - lrpc "github.com/tendermint/tendermint/lite2/rpc" + lrpc "github.com/tendermint/tendermint/light/rpc" ctypes "github.com/tendermint/tendermint/rpc/core/types" rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" diff --git a/lite2/rpc/client.go b/light/rpc/client.go similarity index 94% rename from lite2/rpc/client.go rename to light/rpc/client.go index 283083958..9bf6590e8 100644 --- a/lite2/rpc/client.go +++ b/light/rpc/client.go @@ -11,7 +11,7 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" tmbytes "github.com/tendermint/tendermint/libs/bytes" service "github.com/tendermint/tendermint/libs/service" - lite "github.com/tendermint/tendermint/lite2" + light "github.com/tendermint/tendermint/light" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" @@ -20,20 +20,20 @@ import ( var errNegOrZeroHeight = errors.New("negative or zero height") -// Client is an RPC client, which uses lite#Client to verify data (if it can be +// Client is an RPC client, which uses light#Client to verify data (if it can be // proved!). type Client struct { service.BaseService next rpcclient.Client - lc *lite.Client + lc *light.Client prt *merkle.ProofRuntime } var _ rpcclient.Client = (*Client)(nil) // NewClient returns a new client. -func NewClient(next rpcclient.Client, lc *lite.Client) *Client { +func NewClient(next rpcclient.Client, lc *light.Client) *Client { c := &Client{ next: next, lc: lc, @@ -92,7 +92,7 @@ func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes, // Update the light client if we're behind. // NOTE: AppHash for height H is in header H+1. - h, err := c.updateLiteClientIfNeededTo(resp.Height + 1) + h, err := c.updateLightClientIfNeededTo(resp.Height + 1) if err != nil { return nil, err } @@ -171,7 +171,7 @@ func (c *Client) ConsensusParams(height *int64) (*ctypes.ResultConsensusParams, } // Update the light client if we're behind. - h, err := c.updateLiteClientIfNeededTo(res.BlockHeight) + h, err := c.updateLightClientIfNeededTo(res.BlockHeight) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func (c *Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlock // Update the light client if we're behind. if len(res.BlockMetas) > 0 { lastHeight := res.BlockMetas[len(res.BlockMetas)-1].Header.Height - if _, err := c.updateLiteClientIfNeededTo(lastHeight); err != nil { + if _, err := c.updateLightClientIfNeededTo(lastHeight); err != nil { return nil, err } } @@ -254,7 +254,7 @@ func (c *Client) Block(height *int64) (*ctypes.ResultBlock, error) { } // Update the light client if we're behind. - h, err := c.updateLiteClientIfNeededTo(res.Block.Height) + h, err := c.updateLightClientIfNeededTo(res.Block.Height) if err != nil { return nil, err } @@ -288,7 +288,7 @@ func (c *Client) BlockByHash(hash []byte) (*ctypes.ResultBlock, error) { } // Update the light client if we're behind. - h, err := c.updateLiteClientIfNeededTo(res.Block.Height) + h, err := c.updateLightClientIfNeededTo(res.Block.Height) if err != nil { return nil, err } @@ -329,7 +329,7 @@ func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error) } // Update the light client if we're behind. - trustedHeader, err := c.updateLiteClientIfNeededTo(h + 1) + trustedHeader, err := c.updateLightClientIfNeededTo(h + 1) if err != nil { return nil, err } @@ -359,7 +359,7 @@ func (c *Client) Commit(height *int64) (*ctypes.ResultCommit, error) { } // Update the light client if we're behind. - h, err := c.updateLiteClientIfNeededTo(res.Height) + h, err := c.updateLightClientIfNeededTo(res.Height) if err != nil { return nil, err } @@ -387,7 +387,7 @@ func (c *Client) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) { } // Update the light client if we're behind. - h, err := c.updateLiteClientIfNeededTo(res.Height) + h, err := c.updateLightClientIfNeededTo(res.Height) if err != nil { return nil, err } @@ -417,7 +417,7 @@ func (c *Client) Validators(height *int64, page, perPage int) (*ctypes.ResultVal } // Update the light client if we're behind. - h, err := c.updateLiteClientIfNeededTo(res.BlockHeight) + h, err := c.updateLightClientIfNeededTo(res.BlockHeight) if err != nil { return nil, err } @@ -450,7 +450,7 @@ func (c *Client) UnsubscribeAll(ctx context.Context, subscriber string) error { return c.next.UnsubscribeAll(ctx, subscriber) } -func (c *Client) updateLiteClientIfNeededTo(height int64) (*types.SignedHeader, error) { +func (c *Client) updateLightClientIfNeededTo(height int64) (*types.SignedHeader, error) { h, err := c.lc.VerifyHeaderAtHeight(height, time.Now()) if err != nil { return nil, fmt.Errorf("failed to update light client to %d: %w", height, err) diff --git a/lite2/rpc/proof.go b/light/rpc/proof.go similarity index 100% rename from lite2/rpc/proof.go rename to light/rpc/proof.go diff --git a/lite2/rpc/query_test.go b/light/rpc/query_test.go similarity index 98% rename from lite2/rpc/query_test.go rename to light/rpc/query_test.go index 93f70c728..ae4daced6 100644 --- a/lite2/rpc/query_test.go +++ b/light/rpc/query_test.go @@ -11,8 +11,6 @@ package rpc // "github.com/tendermint/tendermint/abci/example/kvstore" // "github.com/tendermint/tendermint/crypto/merkle" -// "github.com/tendermint/tendermint/lite" -// certclient "github.com/tendermint/tendermint/lite/client" // nm "github.com/tendermint/tendermint/node" // "github.com/tendermint/tendermint/rpc/client" // rpctest "github.com/tendermint/tendermint/rpc/test" diff --git a/lite2/setup.go b/light/setup.go similarity index 80% rename from lite2/setup.go rename to light/setup.go index 50a4a9d21..a4ad89741 100644 --- a/lite2/setup.go +++ b/light/setup.go @@ -1,15 +1,15 @@ -package lite +package light import ( "time" - "github.com/tendermint/tendermint/lite2/provider" - "github.com/tendermint/tendermint/lite2/provider/http" - "github.com/tendermint/tendermint/lite2/store" + "github.com/tendermint/tendermint/light/provider" + "github.com/tendermint/tendermint/light/provider/http" + "github.com/tendermint/tendermint/light/store" ) -// NewHTTPClient initiates an instance of a lite client using HTTP addresses -// for both the primary provider and witnesses of the lite client. A trusted +// NewHTTPClient initiates an instance of a light client using HTTP addresses +// for both the primary provider and witnesses of the light client. A trusted // header and hash must be passed to initialize the client. // // See all Option(s) for the additional configuration. @@ -36,7 +36,7 @@ func NewHTTPClient( options...) } -// NewHTTPClientFromTrustedStore initiates an instance of a lite client using +// NewHTTPClientFromTrustedStore initiates an instance of a light client using // HTTP addresses for both the primary provider and witnesses and uses a // trusted store as the root of trust. // diff --git a/lite2/store/db/db.go b/light/store/db/db.go similarity index 99% rename from lite2/store/db/db.go rename to light/store/db/db.go index dffb02ca6..92d083885 100644 --- a/lite2/store/db/db.go +++ b/light/store/db/db.go @@ -11,7 +11,7 @@ import ( dbm "github.com/tendermint/tm-db" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" - "github.com/tendermint/tendermint/lite2/store" + "github.com/tendermint/tendermint/light/store" "github.com/tendermint/tendermint/types" ) diff --git a/lite2/store/db/db_test.go b/light/store/db/db_test.go similarity index 100% rename from lite2/store/db/db_test.go rename to light/store/db/db_test.go diff --git a/lite2/store/errors.go b/light/store/errors.go similarity index 100% rename from lite2/store/errors.go rename to light/store/errors.go diff --git a/lite2/store/store.go b/light/store/store.go similarity index 100% rename from lite2/store/store.go rename to light/store/store.go diff --git a/lite2/trust_options.go b/light/trust_options.go similarity index 99% rename from lite2/trust_options.go rename to light/trust_options.go index fef1d083a..cbf3b1cd8 100644 --- a/lite2/trust_options.go +++ b/light/trust_options.go @@ -1,4 +1,4 @@ -package lite +package light import ( "errors" diff --git a/lite2/verifier.go b/light/verifier.go similarity index 99% rename from lite2/verifier.go rename to light/verifier.go index 2f6340ce3..54f0168df 100644 --- a/lite2/verifier.go +++ b/light/verifier.go @@ -1,4 +1,4 @@ -package lite +package light import ( "bytes" diff --git a/lite2/verifier_test.go b/light/verifier_test.go similarity index 92% rename from lite2/verifier_test.go rename to light/verifier_test.go index a6344b766..7acbd78d7 100644 --- a/lite2/verifier_test.go +++ b/light/verifier_test.go @@ -1,4 +1,4 @@ -package lite_test +package light_test import ( "fmt" @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" tmmath "github.com/tendermint/tendermint/libs/math" - lite "github.com/tendermint/tendermint/lite2" + "github.com/tendermint/tendermint/light" "github.com/tendermint/tendermint/types" ) @@ -117,7 +117,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) { vals, 3 * time.Hour, bTime.Add(2 * time.Hour), - lite.ErrInvalidHeader{Reason: types.ErrNotEnoughVotingPowerSigned{Got: 50, Needed: 93}}, + light.ErrInvalidHeader{Reason: types.ErrNotEnoughVotingPowerSigned{Got: 50, Needed: 93}}, "", }, // vals does not match with what we have -> error @@ -155,7 +155,7 @@ func TestVerifyAdjacentHeaders(t *testing.T) { for i, tc := range testCases { tc := tc t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { - err := lite.VerifyAdjacent(chainID, header, tc.newHeader, tc.newVals, tc.trustingPeriod, tc.now, maxClockDrift) + err := light.VerifyAdjacent(chainID, header, tc.newHeader, tc.newVals, tc.trustingPeriod, tc.now, maxClockDrift) switch { case tc.expErr != nil && assert.Error(t, err): assert.Equal(t, tc.expErr, err) @@ -231,7 +231,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) { vals, 3 * time.Hour, bTime.Add(2 * time.Hour), - lite.ErrInvalidHeader{types.ErrNotEnoughVotingPowerSigned{Got: 50, Needed: 93}}, + light.ErrInvalidHeader{types.ErrNotEnoughVotingPowerSigned{Got: 50, Needed: 93}}, "", }, // 3/3 new vals signed, 2/3 old vals present -> no error @@ -261,7 +261,7 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) { lessThanOneThirdVals, 3 * time.Hour, bTime.Add(2 * time.Hour), - lite.ErrNewValSetCantBeTrusted{types.ErrNotEnoughVotingPowerSigned{Got: 20, Needed: 46}}, + light.ErrNewValSetCantBeTrusted{types.ErrNotEnoughVotingPowerSigned{Got: 20, Needed: 46}}, "", }, } @@ -269,9 +269,9 @@ func TestVerifyNonAdjacentHeaders(t *testing.T) { for i, tc := range testCases { tc := tc t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { - err := lite.VerifyNonAdjacent(chainID, header, vals, tc.newHeader, tc.newVals, tc.trustingPeriod, + err := light.VerifyNonAdjacent(chainID, header, vals, tc.newHeader, tc.newVals, tc.trustingPeriod, tc.now, maxClockDrift, - lite.DefaultTrustLevel) + light.DefaultTrustLevel) switch { case tc.expErr != nil && assert.Error(t, err): @@ -300,7 +300,7 @@ func TestVerifyReturnsErrorIfTrustLevelIsInvalid(t *testing.T) { hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)) ) - err := lite.Verify(chainID, header, vals, header, vals, 2*time.Hour, time.Now(), maxClockDrift, + err := light.Verify(chainID, header, vals, header, vals, 2*time.Hour, time.Now(), maxClockDrift, tmmath.Fraction{Numerator: 2, Denominator: 1}) assert.Error(t, err) } @@ -327,7 +327,7 @@ func TestValidateTrustLevel(t *testing.T) { } for _, tc := range testCases { - err := lite.ValidateTrustLevel(tc.lvl) + err := light.ValidateTrustLevel(tc.lvl) if !tc.valid { assert.Error(t, err) } else { diff --git a/lite/base_verifier.go b/lite/base_verifier.go deleted file mode 100644 index 6a2a50ab5..000000000 --- a/lite/base_verifier.go +++ /dev/null @@ -1,79 +0,0 @@ -package lite - -import ( - "bytes" - - "github.com/pkg/errors" - - lerr "github.com/tendermint/tendermint/lite/errors" - "github.com/tendermint/tendermint/types" -) - -var _ Verifier = (*BaseVerifier)(nil) - -// BaseVerifier lets us check the validity of SignedHeaders at height or -// later, requiring sufficient votes (> 2/3) from the given valset. -// To verify blocks produced by a blockchain with mutable validator sets, -// use the DynamicVerifier. -// TODO: Handle unbonding time. -type BaseVerifier struct { - chainID string - height int64 - valset *types.ValidatorSet -} - -// NewBaseVerifier returns a new Verifier initialized with a validator set at -// some height. -func NewBaseVerifier(chainID string, height int64, valset *types.ValidatorSet) *BaseVerifier { - if valset.IsNilOrEmpty() { - panic("NewBaseVerifier requires a valid valset") - } - return &BaseVerifier{ - chainID: chainID, - height: height, - valset: valset, - } -} - -// Implements Verifier. -func (bv *BaseVerifier) ChainID() string { - return bv.chainID -} - -// Implements Verifier. -func (bv *BaseVerifier) Verify(signedHeader types.SignedHeader) error { - - // We can't verify commits for a different chain. - if signedHeader.ChainID != bv.chainID { - return errors.Errorf("BaseVerifier chainID is %v, cannot verify chainID %v", - bv.chainID, signedHeader.ChainID) - } - - // We can't verify commits older than bv.height. - if signedHeader.Height < bv.height { - return errors.Errorf("BaseVerifier height is %v, cannot verify height %v", - bv.height, signedHeader.Height) - } - - // We can't verify with the wrong validator set. - if !bytes.Equal(signedHeader.ValidatorsHash, - bv.valset.Hash()) { - return lerr.ErrUnexpectedValidators(signedHeader.ValidatorsHash, bv.valset.Hash()) - } - - // Do basic sanity checks. - err := signedHeader.ValidateBasic(bv.chainID) - if err != nil { - return errors.Wrap(err, "in verify") - } - - // Check commit signatures. - err = bv.valset.VerifyCommit( - bv.chainID, signedHeader.Commit.BlockID, - signedHeader.Height, signedHeader.Commit) - if err != nil { - return errors.Wrap(err, "in verify") - } - - return nil -} diff --git a/lite/base_verifier_test.go b/lite/base_verifier_test.go deleted file mode 100644 index 7a79c42c5..000000000 --- a/lite/base_verifier_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package lite - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/tendermint/tendermint/crypto/tmhash" - lerr "github.com/tendermint/tendermint/lite/errors" - "github.com/tendermint/tendermint/types" -) - -func TestBaseCert(t *testing.T) { - // TODO: Requires proposer address to be set in header. - t.SkipNow() - - assert := assert.New(t) - - keys := genPrivKeys(4) - // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do! - vals := keys.ToValidators(20, 10) - // and a Verifier based on our known set - chainID := "test-static" - cert := NewBaseVerifier(chainID, 2, vals) - - cases := []struct { - keys privKeys - vals *types.ValidatorSet - height int64 - first, last int // who actually signs - proper bool // true -> expect no error - changed bool // true -> expect validator change error - }{ - // height regression - {keys, vals, 1, 0, len(keys), false, false}, - // perfect, signed by everyone - {keys, vals, 2, 0, len(keys), true, false}, - // skip little guy is okay - {keys, vals, 3, 1, len(keys), true, false}, - // but not the big guy - {keys, vals, 4, 0, len(keys) - 1, false, false}, - // Changing the power a little bit breaks the static validator. - // The sigs are enough, but the validator hash is unknown. - {keys, keys.ToValidators(20, 11), 5, 0, len(keys), false, true}, - } - - for _, tc := range cases { - sh := tc.keys.GenSignedHeader( - chainID, tc.height, nil, tc.vals, tc.vals, - tmhash.Sum([]byte("foo")), - tmhash.Sum([]byte("params")), - tmhash.Sum([]byte("results")), - tc.first, tc.last, - ) - - err := cert.Verify(sh) - if tc.proper { - assert.Nil(err, "%+v", err) - } else { - assert.NotNil(err) - if tc.changed { - assert.True(lerr.IsErrUnexpectedValidators(err), "%+v", err) - } - } - } -} diff --git a/lite/client/provider.go b/lite/client/provider.go deleted file mode 100644 index a79a3b9fc..000000000 --- a/lite/client/provider.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Package client defines a provider that uses a rpchttp -to get information, which is used to get new headers -and validators directly from a Tendermint client. -*/ -package client - -import ( - "fmt" - - log "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/lite" - lerr "github.com/tendermint/tendermint/lite/errors" - rpcclient "github.com/tendermint/tendermint/rpc/client" - rpchttp "github.com/tendermint/tendermint/rpc/client/http" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - "github.com/tendermint/tendermint/types" -) - -// SignStatusClient combines a SignClient and StatusClient. -type SignStatusClient interface { - rpcclient.SignClient - rpcclient.StatusClient -} - -type provider struct { - logger log.Logger - chainID string - client SignStatusClient -} - -// NewProvider implements Provider (but not PersistentProvider). -func NewProvider(chainID string, client SignStatusClient) lite.Provider { - return &provider{ - logger: log.NewNopLogger(), - chainID: chainID, - client: client, - } -} - -// NewHTTPProvider can connect to a tendermint json-rpc endpoint -// at the given url, and uses that as a read-only provider. -func NewHTTPProvider(chainID, remote string) (lite.Provider, error) { - httpClient, err := rpchttp.New(remote, "/websocket") - if err != nil { - return nil, err - } - return NewProvider(chainID, httpClient), nil -} - -// Implements Provider. -func (p *provider) SetLogger(logger log.Logger) { - logger = logger.With("module", "lite/client") - p.logger = logger -} - -// StatusClient returns the internal client as a StatusClient -func (p *provider) StatusClient() rpcclient.StatusClient { - return p.client -} - -// LatestFullCommit implements Provider. -func (p *provider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (fc lite.FullCommit, err error) { - if chainID != p.chainID { - err = fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID) - return - } - if maxHeight != 0 && maxHeight < minHeight { - err = fmt.Errorf("need maxHeight == 0 or minHeight <= maxHeight, got min %v and max %v", - minHeight, maxHeight) - return - } - commit, err := p.fetchLatestCommit(minHeight, maxHeight) - if err != nil { - return - } - fc, err = p.fillFullCommit(commit.SignedHeader) - return -} - -// fetchLatestCommit fetches the latest commit from the client. -func (p *provider) fetchLatestCommit(minHeight int64, maxHeight int64) (*ctypes.ResultCommit, error) { - status, err := p.client.Status() - if err != nil { - return nil, err - } - if status.SyncInfo.LatestBlockHeight < minHeight { - err = fmt.Errorf("provider is at %v but require minHeight=%v", - status.SyncInfo.LatestBlockHeight, minHeight) - return nil, err - } - if maxHeight == 0 { - maxHeight = status.SyncInfo.LatestBlockHeight - } else if status.SyncInfo.LatestBlockHeight < maxHeight { - maxHeight = status.SyncInfo.LatestBlockHeight - } - return p.client.Commit(&maxHeight) -} - -// Implements Provider. -func (p *provider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) { - return p.getValidatorSet(chainID, height) -} - -func (p *provider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) { - if chainID != p.chainID { - err = fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID) - return - } - if height < 1 { - err = fmt.Errorf("expected height >= 1, got height %v", height) - return - } - res, err := p.client.Validators(&height, 0, 0) - if err != nil { - // TODO pass through other types of errors. - return nil, lerr.ErrUnknownValidators(chainID, height) - } - valset = types.NewValidatorSet(res.Validators) - return -} - -// This does no validation. -func (p *provider) fillFullCommit(signedHeader types.SignedHeader) (fc lite.FullCommit, err error) { - - // Get the validators. - valset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height) - if err != nil { - return lite.FullCommit{}, err - } - - // Get the next validators. - nextValset, err := p.getValidatorSet(signedHeader.ChainID, signedHeader.Height+1) - if err != nil { - return lite.FullCommit{}, err - } - - return lite.NewFullCommit(signedHeader, valset, nextValset), nil -} diff --git a/lite/client/provider_test.go b/lite/client/provider_test.go deleted file mode 100644 index 1dccdd172..000000000 --- a/lite/client/provider_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package client - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/abci/example/kvstore" - rpcclient "github.com/tendermint/tendermint/rpc/client" - rpctest "github.com/tendermint/tendermint/rpc/test" - "github.com/tendermint/tendermint/types" -) - -func TestMain(m *testing.M) { - app := kvstore.NewApplication() - node := rpctest.StartTendermint(app) - - code := m.Run() - - rpctest.StopTendermint(node) - os.Exit(code) -} - -func TestProvider(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - cfg := rpctest.GetConfig() - defer os.RemoveAll(cfg.RootDir) - rpcAddr := cfg.RPC.ListenAddress - genDoc, err := types.GenesisDocFromFile(cfg.GenesisFile()) - if err != nil { - panic(err) - } - chainID := genDoc.ChainID - t.Log("chainID:", chainID) - p, err := NewHTTPProvider(chainID, rpcAddr) - require.Nil(err) - require.NotNil(p) - - // let it produce some blocks - err = rpcclient.WaitForHeight(p.(*provider).client, 6, nil) - require.Nil(err) - - // let's get the highest block - fc, err := p.LatestFullCommit(chainID, 1, 1<<63-1) - - require.Nil(err, "%+v", err) - sh := fc.Height() - assert.True(sh < 5000) - - // let's check this is valid somehow - assert.Nil(fc.ValidateFull(chainID)) - - // historical queries now work :) - lower := sh - 5 - fc, err = p.LatestFullCommit(chainID, lower, lower) - assert.Nil(err, "%+v", err) - assert.Equal(lower, fc.Height()) - -} diff --git a/lite/commit.go b/lite/commit.go deleted file mode 100644 index 6cd354173..000000000 --- a/lite/commit.go +++ /dev/null @@ -1,87 +0,0 @@ -package lite - -import ( - "bytes" - "errors" - "fmt" - - "github.com/tendermint/tendermint/types" -) - -// FullCommit contains a SignedHeader (the block header and a commit that signs it), -// 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 -// revert to block-by-block updating of lite Verifier's latest validator set, -// even in the face of arbitrarily large power changes. -type FullCommit struct { - SignedHeader types.SignedHeader `json:"signed_header"` - Validators *types.ValidatorSet `json:"validator_set"` - NextValidators *types.ValidatorSet `json:"next_validator_set"` -} - -// NewFullCommit returns a new FullCommit. -func NewFullCommit(signedHeader types.SignedHeader, valset, nextValset *types.ValidatorSet) FullCommit { - return FullCommit{ - SignedHeader: signedHeader, - Validators: valset, - NextValidators: nextValset, - } -} - -// Validate the components and check for consistency. -// This also checks to make sure that Validators actually -// signed the SignedHeader.Commit. -// If > 2/3 did not sign the Commit from fc.Validators, it -// is not a valid commit! -func (fc FullCommit) ValidateFull(chainID string) error { - // Ensure that Validators exists and matches the header. - if fc.Validators.Size() == 0 { - return errors.New("need FullCommit.Validators") - } - if !bytes.Equal( - fc.SignedHeader.ValidatorsHash, - fc.Validators.Hash()) { - return fmt.Errorf("header has vhash %X but valset hash is %X", - fc.SignedHeader.ValidatorsHash, - fc.Validators.Hash(), - ) - } - // Ensure that NextValidators exists and matches the header. - if fc.NextValidators.Size() == 0 { - return errors.New("need FullCommit.NextValidators") - } - if !bytes.Equal( - fc.SignedHeader.NextValidatorsHash, - fc.NextValidators.Hash()) { - return fmt.Errorf("header has next vhash %X but next valset hash is %X", - fc.SignedHeader.NextValidatorsHash, - fc.NextValidators.Hash(), - ) - } - // Validate the header. - err := fc.SignedHeader.ValidateBasic(chainID) - if err != nil { - return err - } - // Validate the signatures on the commit. - hdr, cmt := fc.SignedHeader.Header, fc.SignedHeader.Commit - return fc.Validators.VerifyCommit( - hdr.ChainID, cmt.BlockID, - hdr.Height, cmt) -} - -// Height returns the height of the header. -func (fc FullCommit) Height() int64 { - if fc.SignedHeader.Header == nil { - panic("should not happen") - } - return fc.SignedHeader.Height -} - -// ChainID returns the chainID of the header. -func (fc FullCommit) ChainID() string { - if fc.SignedHeader.Header == nil { - panic("should not happen") - } - return fc.SignedHeader.ChainID -} diff --git a/lite/dbprovider.go b/lite/dbprovider.go deleted file mode 100644 index 9b1580314..000000000 --- a/lite/dbprovider.go +++ /dev/null @@ -1,285 +0,0 @@ -package lite - -import ( - "fmt" - "regexp" - "strconv" - - amino "github.com/tendermint/go-amino" - dbm "github.com/tendermint/tm-db" - - cryptoamino "github.com/tendermint/tendermint/crypto/encoding/amino" - log "github.com/tendermint/tendermint/libs/log" - lerr "github.com/tendermint/tendermint/lite/errors" - "github.com/tendermint/tendermint/types" -) - -var _ PersistentProvider = (*DBProvider)(nil) - -// DBProvider stores commits and validator sets in a DB. -type DBProvider struct { - logger log.Logger - label string - db dbm.DB - cdc *amino.Codec - limit int -} - -func NewDBProvider(label string, db dbm.DB) *DBProvider { - - // NOTE: when debugging, this type of construction might be useful. - //db = dbm.NewDebugDB("db provider "+tmrand.Str(4), db) - - cdc := amino.NewCodec() - cryptoamino.RegisterAmino(cdc) - dbp := &DBProvider{ - logger: log.NewNopLogger(), - label: label, - db: db, - cdc: cdc, - } - return dbp -} - -func (dbp *DBProvider) SetLogger(logger log.Logger) { - dbp.logger = logger.With("label", dbp.label) -} - -func (dbp *DBProvider) SetLimit(limit int) *DBProvider { - dbp.limit = limit - return dbp -} - -// Implements PersistentProvider. -func (dbp *DBProvider) SaveFullCommit(fc FullCommit) error { - - dbp.logger.Info("DBProvider.SaveFullCommit()...", "fc", fc) - batch := dbp.db.NewBatch() - defer batch.Close() - - // Save the fc.validators. - // We might be overwriting what we already have, but - // it makes the logic easier for now. - vsKey := validatorSetKey(fc.ChainID(), fc.Height()) - vsBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.Validators) - if err != nil { - return err - } - batch.Set(vsKey, vsBz) - - // Save the fc.NextValidators. - nvsKey := validatorSetKey(fc.ChainID(), fc.Height()+1) - nvsBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.NextValidators) - if err != nil { - return err - } - batch.Set(nvsKey, nvsBz) - - // Save the fc.SignedHeader - shKey := signedHeaderKey(fc.ChainID(), fc.Height()) - shBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.SignedHeader) - if err != nil { - return err - } - batch.Set(shKey, shBz) - - // And write sync. - batch.WriteSync() - - // Garbage collect. - // TODO: optimize later. - if dbp.limit > 0 { - dbp.deleteAfterN(fc.ChainID(), dbp.limit) - } - - return nil -} - -// Implements Provider. -func (dbp *DBProvider) LatestFullCommit(chainID string, minHeight, maxHeight int64) ( - FullCommit, error) { - - dbp.logger.Info("DBProvider.LatestFullCommit()...", - "chainID", chainID, "minHeight", minHeight, "maxHeight", maxHeight) - - if minHeight <= 0 { - minHeight = 1 - } - if maxHeight == 0 { - maxHeight = 1<<63 - 1 - } - - itr, err := dbp.db.ReverseIterator( - signedHeaderKey(chainID, minHeight), - append(signedHeaderKey(chainID, maxHeight), byte(0x00)), - ) - if err != nil { - panic(err) - } - defer itr.Close() - - for itr.Valid() { - key := itr.Key() - _, _, ok := parseSignedHeaderKey(key) - if !ok { - // Skip over other keys. - itr.Next() - continue - } else { - // Found the latest full commit signed header. - shBz := itr.Value() - sh := types.SignedHeader{} - err := dbp.cdc.UnmarshalBinaryLengthPrefixed(shBz, &sh) - if err != nil { - return FullCommit{}, err - } - - lfc, err := dbp.fillFullCommit(sh) - if err == nil { - dbp.logger.Info("DBProvider.LatestFullCommit() found latest.", "height", lfc.Height()) - return lfc, nil - } - - dbp.logger.Error("DBProvider.LatestFullCommit() got error", "lfc", lfc) - dbp.logger.Error(fmt.Sprintf("%+v", err)) - return lfc, err - - } - } - return FullCommit{}, lerr.ErrCommitNotFound() -} - -func (dbp *DBProvider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) { - return dbp.getValidatorSet(chainID, height) -} - -func (dbp *DBProvider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) { - vsBz, err := dbp.db.Get(validatorSetKey(chainID, height)) - if err != nil { - return nil, err - } - if len(vsBz) == 0 { - err = lerr.ErrUnknownValidators(chainID, height) - return - } - err = dbp.cdc.UnmarshalBinaryLengthPrefixed(vsBz, &valset) - if err != nil { - return - } - - // 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 -} - -func (dbp *DBProvider) fillFullCommit(sh types.SignedHeader) (FullCommit, error) { - var chainID = sh.ChainID - var height = sh.Height - var valset, nextValset *types.ValidatorSet - // Load the validator set. - valset, err := dbp.getValidatorSet(chainID, height) - if err != nil { - return FullCommit{}, err - } - // Load the next validator set. - nextValset, err = dbp.getValidatorSet(chainID, height+1) - if err != nil { - return FullCommit{}, err - } - // Return filled FullCommit. - return FullCommit{ - SignedHeader: sh, - Validators: valset, - NextValidators: nextValset, - }, nil -} - -func (dbp *DBProvider) deleteAfterN(chainID string, after int) error { - - dbp.logger.Info("DBProvider.deleteAfterN()...", "chainID", chainID, "after", after) - - itr, err := dbp.db.ReverseIterator( - signedHeaderKey(chainID, 1), - append(signedHeaderKey(chainID, 1<<63-1), byte(0x00)), - ) - if err != nil { - panic(err) - } - defer itr.Close() - - var lastHeight int64 = 1<<63 - 1 - var numSeen = 0 - var numDeleted = 0 - - for itr.Valid() { - key := itr.Key() - _, height, ok := parseChainKeyPrefix(key) - if !ok { - return fmt.Errorf("unexpected key %v", key) - } - - if height < lastHeight { - lastHeight = height - numSeen++ - } - if numSeen > after { - dbp.db.Delete(key) - numDeleted++ - } - - itr.Next() - } - - dbp.logger.Info(fmt.Sprintf("DBProvider.deleteAfterN() deleted %v items", numDeleted)) - return nil -} - -//---------------------------------------- -// key encoding - -func signedHeaderKey(chainID string, height int64) []byte { - return []byte(fmt.Sprintf("%s/%010d/sh", chainID, height)) -} - -func validatorSetKey(chainID string, height int64) []byte { - return []byte(fmt.Sprintf("%s/%010d/vs", chainID, height)) -} - -//---------------------------------------- -// key parsing - -var keyPattern = regexp.MustCompile(`^([^/]+)/([0-9]*)/(.*)$`) - -func parseKey(key []byte) (chainID string, height int64, part string, ok bool) { - submatch := keyPattern.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) - part = string(submatch[3]) - ok = true // good! - return -} - -func parseSignedHeaderKey(key []byte) (chainID string, height int64, ok bool) { - var part string - chainID, height, part, ok = parseKey(key) - if part != "sh" { - return "", 0, false - } - return -} - -func parseChainKeyPrefix(key []byte) (chainID string, height int64, ok bool) { - chainID, height, _, ok = parseKey(key) - return -} diff --git a/lite/doc.go b/lite/doc.go deleted file mode 100644 index ecb8d4cf6..000000000 --- a/lite/doc.go +++ /dev/null @@ -1,133 +0,0 @@ -/* -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 -relatively recent (< unbonding period) known validator set, one can get -indisputable proof that data is in the chain (current state) or detect if the -node is lying to the client. - -Tendermint RPC exposes a lot of info, but a malicious node could return any -data it wants to queries, or even to block headers, even making up fake -signatures from non-existent validators to justify it. This is a lot of logic -to get right, to be contained in a small, easy to use library, that does this -for you, so you can just build nice applications. - -We design for clients who have no strong trust relationship with any Tendermint -node, just the blockchain and validator set as a whole. - -SignedHeader - -SignedHeader is a block header along with a commit -- enough validator -precommit-vote signatures to prove its validity (> 2/3 of the voting power) -given the validator set responsible for signing that header. A FullCommit is a -SignedHeader along with the current and next validator sets. - -The hash of the next validator set is included and signed in the SignedHeader. -This lets the lite client keep track of arbitrary changes to the validator set, -as every change to the validator set must be approved by inclusion in the -header and signed in the commit. - -In the worst case, with every block changing the validators around completely, -a lite client can sync up with every block header to verify each validator set -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 -lite client syncing is optimized to use intelligent bisection and -block-skipping for efficient sourcing and verification of these data structures -and updates to the validator set (see the DynamicVerifier for more -information). - -The FullCommit is also declared in this package as a convenience structure, -which includes the SignedHeader along with the full current and next -ValidatorSets. - -Verifier - -A Verifier validates a new SignedHeader given the currently known state. There -are two different types of Verifiers provided. - -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 -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 -greater). - -DynamicVerifier - this Verifier implements an auto-update and persistence -strategy to verify any SignedHeader of the blockchain. - -Provider and PersistentProvider - -A Provider allows us to store and retrieve the FullCommits. - - type Provider interface { - // LatestFullCommit returns the latest commit with - // minHeight <= height <= maxHeight. - // If maxHeight is zero, returns the latest where - // minHeight <= height. - LatestFullCommit(chainID string, minHeight, maxHeight int64) (FullCommit, error) - } - -* client.NewHTTPProvider - query Tendermint rpc. - -A PersistentProvider is a Provider that also allows for saving state. This is -used by the DynamicVerifier for persistence. - - type PersistentProvider interface { - Provider - - // SaveFullCommit saves a FullCommit (without verification). - SaveFullCommit(fc FullCommit) error - } - -* DBProvider - persistence provider for use with any libs/DB. - -* MultiProvider - combine multiple providers. - -The suggested use for local light clients is client.NewHTTPProvider(...) for -getting new data (Source), and NewMultiProvider(NewDBProvider("label", -dbm.NewMemDB()), NewDBProvider("label", db.NewFileDB(...))) to store confirmed -full commits (Trusted) - - -How We Track Validators - -Unless you want to blindly trust the node you talk with, you need to trace -every response back to a hash in a block header and validate the commit -signatures of that block header match the proper validator set. If there is a -static validator set, you store it locally upon initialization of the client, -and check against that every time. - -If the validator set for the blockchain is dynamic, verifying block commits is -a bit more involved -- if there is a block at height H with a known (trusted) -validator set V, and another block at height H' (H' > H) with validator set V' -!= V, then we want a way to safely update it. - -First, we get the new (unconfirmed) validator set V' and verify that H' is -internally consistent and properly signed by this V'. Assuming it is a valid -block, we check that at least 2/3 of the validators in V also signed it, -meaning it would also be valid under our old assumptions. Then, we accept H' -and V' as valid and trusted and use that to validate for heights X > H' until a -more recent and updated validator set is found. - -If we cannot update directly from H -> H' because there was too much change to -the validator set, then we can look for some Hm (H < Hm < H') with a validator -set Vm. Then we try to update H -> Hm and then Hm -> H' in two steps. If one -of these steps doesn't work, then we continue bisecting, until we eventually -have to externally validate the validator set changes at every block. - -Since we never trust any server in this protocol, only the signatures -themselves, it doesn't matter if the seed comes from a (possibly malicious) -node or a (possibly malicious) user. We can accept it or reject it based only -on our trusted validator set and cryptographic proofs. This makes it extremely -important to verify that you have the proper validator set when initializing -the client, as that is the root of all trust. - -The software currently assumes that the unbonding period is infinite in -duration. If the DynamicVerifier hasn't been updated in a while, you should -manually verify the block headers using other sources. - -TODO: Update the software to handle cases around the unbonding period. - -*/ -package lite diff --git a/lite/dynamic_verifier.go b/lite/dynamic_verifier.go deleted file mode 100644 index d4efdcbeb..000000000 --- a/lite/dynamic_verifier.go +++ /dev/null @@ -1,275 +0,0 @@ -package lite - -import ( - "bytes" - "fmt" - "sync" - - log "github.com/tendermint/tendermint/libs/log" - lerr "github.com/tendermint/tendermint/lite/errors" - "github.com/tendermint/tendermint/types" -) - -const sizeOfPendingMap = 1024 - -var _ Verifier = (*DynamicVerifier)(nil) - -// DynamicVerifier implements an auto-updating Verifier. It uses a -// "source" provider to obtain the needed FullCommits to securely sync with -// validator set changes. It stores properly validated data on the -// "trusted" local system. -// TODO: make this single threaded and create a new -// ConcurrentDynamicVerifier that wraps it with concurrency. -// see https://github.com/tendermint/tendermint/issues/3170 -type DynamicVerifier struct { - chainID string - logger log.Logger - - // Already validated, stored locally - trusted PersistentProvider - - // New info, like a node rpc, or other import method. - source Provider - - // pending map to synchronize concurrent verification requests - mtx sync.Mutex - pendingVerifications map[int64]chan struct{} -} - -// NewDynamicVerifier returns a new DynamicVerifier. It uses the -// trusted provider to store validated data and the source provider to -// obtain missing data (e.g. FullCommits). -// -// The trusted provider should be a DBProvider. -// The source provider should be a client.HTTPProvider. -func NewDynamicVerifier(chainID string, trusted PersistentProvider, source Provider) *DynamicVerifier { - return &DynamicVerifier{ - logger: log.NewNopLogger(), - chainID: chainID, - trusted: trusted, - source: source, - pendingVerifications: make(map[int64]chan struct{}, sizeOfPendingMap), - } -} - -func (dv *DynamicVerifier) SetLogger(logger log.Logger) { - logger = logger.With("module", "lite") - dv.logger = logger - dv.trusted.SetLogger(logger) - dv.source.SetLogger(logger) -} - -// Implements Verifier. -func (dv *DynamicVerifier) ChainID() string { - return dv.chainID -} - -// Implements Verifier. -// -// If the validators have changed since the last known time, it looks to -// dv.trusted and dv.source to prove the new validators. On success, it will -// try to store the SignedHeader in dv.trusted if the next -// validator can be sourced. -func (dv *DynamicVerifier) Verify(shdr types.SignedHeader) error { - - // Performs synchronization for multi-threads verification at the same height. - dv.mtx.Lock() - if pending := dv.pendingVerifications[shdr.Height]; pending != nil { - dv.mtx.Unlock() - <-pending // pending is chan struct{} - } else { - pending := make(chan struct{}) - dv.pendingVerifications[shdr.Height] = pending - defer func() { - close(pending) - dv.mtx.Lock() - delete(dv.pendingVerifications, shdr.Height) - dv.mtx.Unlock() - }() - dv.mtx.Unlock() - } - - //Get the exact trusted commit for h, and if it is - // equal to shdr, then it's already trusted, so - // just return nil. - trustedFCSameHeight, err := dv.trusted.LatestFullCommit(dv.chainID, shdr.Height, shdr.Height) - if err == nil { - // If loading trust commit successfully, and trust commit equal to shdr, then don't verify it, - // just return nil. - if bytes.Equal(trustedFCSameHeight.SignedHeader.Hash(), shdr.Hash()) { - dv.logger.Info(fmt.Sprintf("Load full commit at height %d from cache, there is not need to verify.", shdr.Height)) - return nil - } - } else if !lerr.IsErrCommitNotFound(err) { - // Return error if it is not CommitNotFound error - dv.logger.Info(fmt.Sprintf("Encountered unknown error in loading full commit at height %d.", shdr.Height)) - return err - } - - // 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. - prevHeight := shdr.Height - 1 - trustedFC, err := dv.trusted.LatestFullCommit(dv.chainID, 1, prevHeight) - if err != nil { - return err - } - - // sync up to the prevHeight and assert our latest NextValidatorSet - // is the ValidatorSet for the SignedHeader - if trustedFC.Height() == prevHeight { - // Return error if valset doesn't match. - if !bytes.Equal( - trustedFC.NextValidators.Hash(), - shdr.Header.ValidatorsHash) { - return lerr.ErrUnexpectedValidators( - trustedFC.NextValidators.Hash(), - shdr.Header.ValidatorsHash) - } - } else { - // If valset doesn't match, try to update - if !bytes.Equal( - trustedFC.NextValidators.Hash(), - shdr.Header.ValidatorsHash) { - // ... update. - trustedFC, err = dv.updateToHeight(prevHeight) - if err != nil { - return err - } - // Return error if valset _still_ doesn't match. - if !bytes.Equal(trustedFC.NextValidators.Hash(), - shdr.Header.ValidatorsHash) { - return lerr.ErrUnexpectedValidators( - trustedFC.NextValidators.Hash(), - shdr.Header.ValidatorsHash) - } - } - } - - // Verify the signed header using the matching valset. - cert := NewBaseVerifier(dv.chainID, trustedFC.Height()+1, trustedFC.NextValidators) - err = cert.Verify(shdr) - if err != nil { - return err - } - - // By now, the SignedHeader is fully validated and we're synced up to - // SignedHeader.Height - 1. To sync to SignedHeader.Height, we need - // the validator set at SignedHeader.Height + 1 so we can verify the - // SignedHeader.NextValidatorSet. - // TODO: is the ValidateFull below mostly redundant with the BaseVerifier.Verify above? - // See https://github.com/tendermint/tendermint/issues/3174. - - // Get the next validator set. - nextValset, err := dv.source.ValidatorSet(dv.chainID, shdr.Height+1) - if lerr.IsErrUnknownValidators(err) { - // Ignore this error. - return nil - } else if err != nil { - return err - } - - // Create filled FullCommit. - nfc := FullCommit{ - SignedHeader: shdr, - Validators: trustedFC.NextValidators, - NextValidators: nextValset, - } - // Validate the full commit. This checks the cryptographic - // signatures of Commit against Validators. - if err := nfc.ValidateFull(dv.chainID); err != nil { - return err - } - // Trust it. - return dv.trusted.SaveFullCommit(nfc) -} - -// verifyAndSave will verify if this is a valid source full commit given the -// best match trusted full commit, and if good, persist to dv.trusted. -// Returns ErrNotEnoughVotingPowerSigned when >2/3 of trustedFC did not sign sourceFC. -// Panics if trustedFC.Height() >= sourceFC.Height(). -func (dv *DynamicVerifier) verifyAndSave(trustedFC, sourceFC FullCommit) error { - if trustedFC.Height() >= sourceFC.Height() { - panic("should not happen") - } - err := trustedFC.NextValidators.VerifyFutureCommit( - sourceFC.Validators, - dv.chainID, sourceFC.SignedHeader.Commit.BlockID, - sourceFC.SignedHeader.Height, sourceFC.SignedHeader.Commit, - ) - if err != nil { - return err - } - - return dv.trusted.SaveFullCommit(sourceFC) -} - -// updateToHeight will use divide-and-conquer to find a path to h. -// Returns nil error iff we successfully verify and persist a full commit -// for height h, using repeated applications of bisection if necessary. -// -// Returns ErrCommitNotFound if source provider doesn't have the commit for h. -func (dv *DynamicVerifier) updateToHeight(h int64) (FullCommit, error) { - - // Fetch latest full commit from source. - sourceFC, err := dv.source.LatestFullCommit(dv.chainID, h, h) - if err != nil { - return FullCommit{}, err - } - - // If sourceFC.Height() != h, we can't do it. - if sourceFC.Height() != h { - return FullCommit{}, lerr.ErrCommitNotFound() - } - - // Validate the full commit. This checks the cryptographic - // signatures of Commit against Validators. - if err := sourceFC.ValidateFull(dv.chainID); err != nil { - return FullCommit{}, err - } - - // Verify latest FullCommit against trusted FullCommits -FOR_LOOP: - for { - // Fetch latest full commit from trusted. - trustedFC, err := dv.trusted.LatestFullCommit(dv.chainID, 1, h) - if err != nil { - return FullCommit{}, err - } - // We have nothing to do. - if trustedFC.Height() == h { - return trustedFC, nil - } - - // Try to update to full commit with checks. - err = dv.verifyAndSave(trustedFC, sourceFC) - if err == nil { - // All good! - return sourceFC, nil - } - - // Handle special case when err is ErrNotEnoughVotingPowerSigned. - if types.IsErrNotEnoughVotingPowerSigned(err) { - // Divide and conquer. - start, end := trustedFC.Height(), sourceFC.Height() - if !(start < end) { - panic("should not happen") - } - mid := (start + end) / 2 - _, err = dv.updateToHeight(mid) - if err != nil { - return FullCommit{}, err - } - // If we made it to mid, we retry. - continue FOR_LOOP - } - return FullCommit{}, err - } -} - -func (dv *DynamicVerifier) LastTrustedHeight() int64 { - fc, err := dv.trusted.LatestFullCommit(dv.chainID, 1, 1<<63-1) - if err != nil { - panic("should not happen") - } - return fc.Height() -} diff --git a/lite/dynamic_verifier_test.go b/lite/dynamic_verifier_test.go deleted file mode 100644 index e09e64ab2..000000000 --- a/lite/dynamic_verifier_test.go +++ /dev/null @@ -1,299 +0,0 @@ -package lite - -import ( - "fmt" - "sync" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - dbm "github.com/tendermint/tm-db" - - "github.com/tendermint/tendermint/crypto/tmhash" - log "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/types" -) - -const testChainID = "inquiry-test" - -func TestInquirerValidPath(t *testing.T) { - assert, require := assert.New(t), require.New(t) - trust := NewDBProvider("trust", dbm.NewMemDB()) - source := NewDBProvider("source", dbm.NewMemDB()) - - // Set up the validators to generate test blocks. - var vote int64 = 10 - keys := genPrivKeys(5) - nkeys := keys.Extend(1) - - // Construct a bunch of commits, each with one more height than the last. - chainID := testChainID - consHash := []byte("params") - resHash := []byte("results") - count := 50 - fcz := make([]FullCommit, count) - for i := 0; i < count; i++ { - vals := keys.ToValidators(vote, 0) - nextVals := nkeys.ToValidators(vote, 0) - h := int64(1 + i) - appHash := []byte(fmt.Sprintf("h=%d", h)) - fcz[i] = keys.GenFullCommit( - chainID, h, nil, - vals, nextVals, - appHash, consHash, resHash, 0, len(keys)) - // Extend the keys by 1 each time. - keys = nkeys - nkeys = nkeys.Extend(1) - } - - // Initialize a Verifier with the initial state. - err := trust.SaveFullCommit(fcz[0]) - require.Nil(err) - cert := NewDynamicVerifier(chainID, trust, source) - cert.SetLogger(log.TestingLogger()) - - // This should fail validation: - sh := fcz[count-1].SignedHeader - err = cert.Verify(sh) - require.NotNil(err) - - // Adding a few commits in the middle should be insufficient. - for i := 10; i < 13; i++ { - err := source.SaveFullCommit(fcz[i]) - require.Nil(err) - } - err = cert.Verify(sh) - assert.NotNil(err) - - // With more info, we succeed. - for i := 0; i < count; i++ { - err := source.SaveFullCommit(fcz[i]) - require.Nil(err) - } - - // TODO: Requires proposer address to be set in header. - // err = cert.Verify(sh) - // assert.Nil(err, "%+v", err) -} - -func TestDynamicVerify(t *testing.T) { - trust := NewDBProvider("trust", dbm.NewMemDB()) - source := NewDBProvider("source", dbm.NewMemDB()) - - // 10 commits with one valset, 1 to change, - // 10 commits with the next one - n1, n2 := 10, 10 - nCommits := n1 + n2 + 1 - maxHeight := int64(nCommits) - fcz := make([]FullCommit, nCommits) - - // gen the 2 val sets - chainID := "dynamic-verifier" - power := int64(10) - keys1 := genPrivKeys(5) - vals1 := keys1.ToValidators(power, 0) - keys2 := genPrivKeys(5) - vals2 := keys2.ToValidators(power, 0) - - // make some commits with the first - for i := 0; i < n1; i++ { - fcz[i] = makeFullCommit(int64(i), keys1, vals1, vals1, chainID) - } - - // update the val set - fcz[n1] = makeFullCommit(int64(n1), keys1, vals1, vals2, chainID) - - // make some commits with the new one - for i := n1 + 1; i < nCommits; i++ { - fcz[i] = makeFullCommit(int64(i), keys2, vals2, vals2, chainID) - } - - // Save everything in the source - for _, fc := range fcz { - source.SaveFullCommit(fc) - } - - // Initialize a Verifier with the initial state. - err := trust.SaveFullCommit(fcz[0]) - require.Nil(t, err) - ver := NewDynamicVerifier(chainID, trust, source) - ver.SetLogger(log.TestingLogger()) - - // fetch the latest from the source - _, err = source.LatestFullCommit(chainID, 1, maxHeight) - require.NoError(t, err) - - // TODO: Requires proposer address to be set in header. - // try to update to the latest - // err = ver.Verify(latestFC.SignedHeader) - // require.NoError(t, err) -} - -func makeFullCommit(height int64, keys privKeys, vals, nextVals *types.ValidatorSet, chainID string) FullCommit { - height++ - - consHash := tmhash.Sum([]byte("special-params")) - appHash := tmhash.Sum([]byte(fmt.Sprintf("h=%d", height))) - resHash := tmhash.Sum([]byte(fmt.Sprintf("res=%d", height))) - - return keys.GenFullCommit( - chainID, height, nil, - vals, nextVals, - appHash, consHash, resHash, 0, len(keys), - ) -} - -func TestInquirerVerifyHistorical(t *testing.T) { - assert, require := assert.New(t), require.New(t) - trust := NewDBProvider("trust", dbm.NewMemDB()) - source := NewDBProvider("source", dbm.NewMemDB()) - - // Set up the validators to generate test blocks. - var vote int64 = 10 - keys := genPrivKeys(5) - nkeys := keys.Extend(1) - - // Construct a bunch of commits, each with one more height than the last. - chainID := testChainID - count := 10 - consHash := []byte("special-params") - fcz := make([]FullCommit, count) - for i := 0; i < count; i++ { - vals := keys.ToValidators(vote, 0) - nextVals := nkeys.ToValidators(vote, 0) - h := int64(1 + i) - appHash := []byte(fmt.Sprintf("h=%d", h)) - resHash := []byte(fmt.Sprintf("res=%d", h)) - fcz[i] = keys.GenFullCommit( - chainID, h, nil, - vals, nextVals, - appHash, consHash, resHash, 0, len(keys)) - // Extend the keys by 1 each time. - keys = nkeys - nkeys = nkeys.Extend(1) - } - - // Initialize a Verifier with the initial state. - err := trust.SaveFullCommit(fcz[0]) - require.Nil(err) - cert := NewDynamicVerifier(chainID, trust, source) - cert.SetLogger(log.TestingLogger()) - - // Store a few full commits as trust. - for _, i := range []int{2, 5} { - trust.SaveFullCommit(fcz[i]) - } - - // See if we can jump forward using trusted full commits. - // Souce doesn't have fcz[9] so cert.LastTrustedHeight wont' change. - err = source.SaveFullCommit(fcz[7]) - require.Nil(err, "%+v", err) - - // TODO: Requires proposer address to be set in header. - // sh := fcz[8].SignedHeader - // err = cert.Verify(sh) - // require.Nil(err, "%+v", err) - // assert.Equal(fcz[7].Height(), cert.LastTrustedHeight()) - - commit, err := trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height()) - require.NotNil(err, "%+v", err) - assert.Equal(commit, (FullCommit{})) - - // With fcz[9] Verify will update last trusted height. - err = source.SaveFullCommit(fcz[9]) - require.Nil(err, "%+v", err) - - // TODO: Requires proposer address to be set in header. - // sh = fcz[8].SignedHeader - // err = cert.Verify(sh) - // require.Nil(err, "%+v", err) - // assert.Equal(fcz[8].Height(), cert.LastTrustedHeight()) - - // TODO: Requires proposer address to be set in header. - // commit, err = trust.LatestFullCommit(chainID, fcz[8].Height(), fcz[8].Height()) - // require.Nil(err, "%+v", err) - // assert.Equal(commit.Height(), fcz[8].Height()) - - // Add access to all full commits via untrusted source. - for i := 0; i < count; i++ { - err := source.SaveFullCommit(fcz[i]) - require.Nil(err) - } - - // TODO: Requires proposer address to be set in header. - // Try to check an unknown seed in the past. - // sh = fcz[3].SignedHeader - // err = cert.Verify(sh) - // require.Nil(err, "%+v", err) - // assert.Equal(fcz[8].Height(), cert.LastTrustedHeight()) - - // TODO: Requires proposer address to be set in header. - // Jump all the way forward again. - // sh = fcz[count-1].SignedHeader - // err = cert.Verify(sh) - // require.Nil(err, "%+v", err) - // assert.Equal(fcz[9].Height(), cert.LastTrustedHeight()) -} - -func TestConcurrencyInquirerVerify(t *testing.T) { - _, require := assert.New(t), require.New(t) - trust := NewDBProvider("trust", dbm.NewMemDB()).SetLimit(10) - source := NewDBProvider("source", dbm.NewMemDB()) - - // Set up the validators to generate test blocks. - var vote int64 = 10 - keys := genPrivKeys(5) - nkeys := keys.Extend(1) - - // Construct a bunch of commits, each with one more height than the last. - chainID := testChainID - count := 10 - consHash := []byte("special-params") - fcz := make([]FullCommit, count) - for i := 0; i < count; i++ { - vals := keys.ToValidators(vote, 0) - nextVals := nkeys.ToValidators(vote, 0) - h := int64(1 + i) - appHash := []byte(fmt.Sprintf("h=%d", h)) - resHash := []byte(fmt.Sprintf("res=%d", h)) - fcz[i] = keys.GenFullCommit( - chainID, h, nil, - vals, nextVals, - appHash, consHash, resHash, 0, len(keys)) - // Extend the keys by 1 each time. - keys = nkeys - nkeys = nkeys.Extend(1) - } - - // Initialize a Verifier with the initial state. - err := trust.SaveFullCommit(fcz[0]) - require.Nil(err) - cert := NewDynamicVerifier(chainID, trust, source) - cert.SetLogger(log.TestingLogger()) - - err = source.SaveFullCommit(fcz[7]) - require.Nil(err, "%+v", err) - err = source.SaveFullCommit(fcz[8]) - require.Nil(err, "%+v", err) - sh := fcz[8].SignedHeader - - var wg sync.WaitGroup - count = 100 - errList := make([]error, count) - - for i := 0; i < count; i++ { - wg.Add(1) - go func(index int) { - errList[index] = cert.Verify(sh) - defer wg.Done() - }(i) - } - - wg.Wait() - - // TODO: Requires proposer address to be set in header. - // for _, err := range errList { - // require.Nil(err) - // } -} diff --git a/lite/errors/errors.go b/lite/errors/errors.go deleted file mode 100644 index 5bb829b0a..000000000 --- a/lite/errors/errors.go +++ /dev/null @@ -1,99 +0,0 @@ -package errors - -import ( - "fmt" - - "github.com/pkg/errors" -) - -//---------------------------------------- -// Error types - -type errCommitNotFound struct{} - -func (e errCommitNotFound) Error() string { - return "Commit not found by provider" -} - -type errUnexpectedValidators struct { - got []byte - want []byte -} - -func (e errUnexpectedValidators) Error() string { - return fmt.Sprintf("Validator set is different. Got %X want %X", - e.got, e.want) -} - -type errUnknownValidators struct { - chainID string - height int64 -} - -func (e errUnknownValidators) Error() string { - return fmt.Sprintf("Validators are unknown or missing for chain %s and height %d", - e.chainID, e.height) -} - -type errEmptyTree struct{} - -func (e errEmptyTree) Error() string { - return "Tree is empty" -} - -//---------------------------------------- -// Methods for above error types - -//----------------- -// ErrCommitNotFound - -// ErrCommitNotFound indicates that a the requested commit was not found. -func ErrCommitNotFound() error { - return errors.Wrap(errCommitNotFound{}, "") -} - -func IsErrCommitNotFound(err error) bool { - _, ok := errors.Cause(err).(errCommitNotFound) - return ok -} - -//----------------- -// ErrUnexpectedValidators - -// ErrUnexpectedValidators indicates a validator set mismatch. -func ErrUnexpectedValidators(got, want []byte) error { - return errors.Wrap(errUnexpectedValidators{ - got: got, - want: want, - }, "") -} - -func IsErrUnexpectedValidators(err error) bool { - _, ok := errors.Cause(err).(errUnexpectedValidators) - return ok -} - -//----------------- -// ErrUnknownValidators - -// ErrUnknownValidators indicates that some validator set was missing or unknown. -func ErrUnknownValidators(chainID string, height int64) error { - return errors.Wrap(errUnknownValidators{chainID, height}, "") -} - -func IsErrUnknownValidators(err error) bool { - _, ok := errors.Cause(err).(errUnknownValidators) - return ok -} - -//----------------- -// ErrEmptyTree - -func ErrEmptyTree() error { - return errors.Wrap(errEmptyTree{}, "") -} - -func IsErrEmptyTree(err error) bool { - _, ok := errors.Cause(err).(errEmptyTree) - return ok -} diff --git a/lite/helpers.go b/lite/helpers.go deleted file mode 100644 index 29dd50b5b..000000000 --- a/lite/helpers.go +++ /dev/null @@ -1,159 +0,0 @@ -package lite - -import ( - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/crypto/secp256k1" - - "github.com/tendermint/tendermint/types" - tmtime "github.com/tendermint/tendermint/types/time" -) - -// PrivKeys is a helper type for testing. -// -// It lets us simulate signing with many keys. The main use case is to create -// a set, and call GenSignedHeader to get properly signed header for testing. -// -// You can set different weights of validators each time you call ToValidators, -// and can optionally extend the validator set later with Extend. -type privKeys []crypto.PrivKey - -// genPrivKeys produces an array of private keys to generate commits. -func genPrivKeys(n int) privKeys { - res := make(privKeys, n) - for i := range res { - res[i] = ed25519.GenPrivKey() - } - return res -} - -// Change replaces the key at index i. -func (pkz privKeys) Change(i int) privKeys { - res := make(privKeys, len(pkz)) - copy(res, pkz) - res[i] = ed25519.GenPrivKey() - return res -} - -// Extend adds n more keys (to remove, just take a slice). -func (pkz privKeys) Extend(n int) privKeys { - extra := genPrivKeys(n) - return append(pkz, extra...) -} - -// GenSecpPrivKeys produces an array of secp256k1 private keys to generate commits. -func genSecpPrivKeys(n int) privKeys { - res := make(privKeys, n) - for i := range res { - res[i] = secp256k1.GenPrivKey() - } - return res -} - -// ExtendSecp adds n more secp256k1 keys (to remove, just take a slice). -func (pkz privKeys) ExtendSecp(n int) privKeys { - extra := genSecpPrivKeys(n) - return append(pkz, extra...) -} - -// ToValidators produces a valset from the set of keys. -// The first key has weight `init` and it increases by `inc` every step -// so we can have all the same weight, or a simple linear distribution -// (should be enough for testing). -func (pkz privKeys) ToValidators(init, inc int64) *types.ValidatorSet { - res := make([]*types.Validator, len(pkz)) - for i, k := range pkz { - res[i] = types.NewValidator(k.PubKey(), init+int64(i)*inc) - } - return types.NewValidatorSet(res) -} - -// signHeader properly signs the header with all keys from first to last exclusive. -func (pkz privKeys) signHeader(header *types.Header, first, last int) *types.Commit { - commitSigs := make([]types.CommitSig, len(pkz)) - for i := 0; i < len(pkz); i++ { - commitSigs[i] = types.NewCommitSigAbsent() - } - - // We need this list to keep the ordering. - vset := pkz.ToValidators(1, 0) - - blockID := types.BlockID{ - Hash: header.Hash(), - PartsHeader: types.PartSetHeader{Total: 1, Hash: crypto.CRandBytes(32)}, - } - - // Fill in the votes we want. - for i := first; i < last && i < len(pkz); i++ { - vote := makeVote(header, vset, pkz[i], blockID) - commitSigs[vote.ValidatorIndex] = vote.CommitSig() - } - - return types.NewCommit(header.Height, 1, blockID, commitSigs) -} - -func makeVote(header *types.Header, valset *types.ValidatorSet, key crypto.PrivKey, blockID types.BlockID) *types.Vote { - addr := key.PubKey().Address() - idx, _ := valset.GetByAddress(addr) - vote := &types.Vote{ - ValidatorAddress: addr, - ValidatorIndex: idx, - Height: header.Height, - Round: 1, - Timestamp: tmtime.Now(), - Type: types.PrecommitType, - BlockID: blockID, - } - // Sign it - signBytes := vote.SignBytes(header.ChainID) - // TODO Consider reworking makeVote API to return an error - sig, err := key.Sign(signBytes) - if err != nil { - panic(err) - } - vote.Signature = sig - - return vote -} - -func genHeader(chainID string, height int64, txs types.Txs, - valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte) *types.Header { - - return &types.Header{ - ChainID: chainID, - Height: height, - Time: tmtime.Now(), - // LastBlockID - // LastCommitHash - ValidatorsHash: valset.Hash(), - NextValidatorsHash: nextValset.Hash(), - DataHash: txs.Hash(), - AppHash: appHash, - ConsensusHash: consHash, - LastResultsHash: resHash, - } -} - -// GenSignedHeader calls genHeader and signHeader and combines them into a SignedHeader. -func (pkz privKeys) GenSignedHeader(chainID string, height int64, txs types.Txs, - valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) types.SignedHeader { - - header := genHeader(chainID, height, txs, valset, nextValset, appHash, consHash, resHash) - check := types.SignedHeader{ - Header: header, - Commit: pkz.signHeader(header, first, last), - } - return check -} - -// GenFullCommit calls genHeader and signHeader and combines them into a FullCommit. -func (pkz privKeys) GenFullCommit(chainID string, height int64, txs types.Txs, - valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) FullCommit { - - header := genHeader(chainID, height, txs, valset, nextValset, appHash, consHash, resHash) - commit := types.SignedHeader{ - Header: header, - Commit: pkz.signHeader(header, first, last), - } - return NewFullCommit(commit, valset, nextValset) -} diff --git a/lite/multiprovider.go b/lite/multiprovider.go deleted file mode 100644 index 364647a40..000000000 --- a/lite/multiprovider.go +++ /dev/null @@ -1,85 +0,0 @@ -package lite - -import ( - log "github.com/tendermint/tendermint/libs/log" - lerr "github.com/tendermint/tendermint/lite/errors" - "github.com/tendermint/tendermint/types" -) - -var _ PersistentProvider = (*multiProvider)(nil) - -// multiProvider allows you to place one or more caches in front of a source -// Provider. It runs through them in order until a match is found. -type multiProvider struct { - logger log.Logger - providers []PersistentProvider -} - -// NewMultiProvider returns a new provider which wraps multiple other providers. -func NewMultiProvider(providers ...PersistentProvider) PersistentProvider { - return &multiProvider{ - logger: log.NewNopLogger(), - providers: providers, - } -} - -// SetLogger sets logger on self and all subproviders. -func (mc *multiProvider) SetLogger(logger log.Logger) { - mc.logger = logger - for _, p := range mc.providers { - p.SetLogger(logger) - } -} - -// SaveFullCommit saves on all providers, and aborts on the first error. -func (mc *multiProvider) SaveFullCommit(fc FullCommit) (err error) { - for _, p := range mc.providers { - err = p.SaveFullCommit(fc) - if err != nil { - return - } - } - return -} - -// LatestFullCommit loads the latest from all providers and provides -// the latest FullCommit that satisfies the conditions. -// Returns the first error encountered. -func (mc *multiProvider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (fc FullCommit, err error) { - for _, p := range mc.providers { - var commit FullCommit - commit, err = p.LatestFullCommit(chainID, minHeight, maxHeight) - if lerr.IsErrCommitNotFound(err) { - err = nil - continue - } else if err != nil { - return - } - if fc == (FullCommit{}) { - fc = commit - } else if commit.Height() > fc.Height() { - fc = commit - } - if fc.Height() == maxHeight { - return - } - } - if fc == (FullCommit{}) { - err = lerr.ErrCommitNotFound() - return - } - return -} - -// ValidatorSet returns validator set at height as provided by the first -// provider which has it, or an error otherwise. -func (mc *multiProvider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) { - for _, p := range mc.providers { - valset, err = p.ValidatorSet(chainID, height) - if err == nil { - // TODO Log unexpected types of errors. - return valset, nil - } - } - return nil, lerr.ErrUnknownValidators(chainID, height) -} diff --git a/lite/provider.go b/lite/provider.go deleted file mode 100644 index ebab16264..000000000 --- a/lite/provider.go +++ /dev/null @@ -1,32 +0,0 @@ -package lite - -import ( - "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/types" -) - -// Provider provides information for the lite client to sync validators. -// Examples: MemProvider, files.Provider, client.Provider, CacheProvider. -type Provider interface { - - // LatestFullCommit returns the latest commit with minHeight <= height <= - // maxHeight. - // If maxHeight is zero, returns the latest where minHeight <= height. - LatestFullCommit(chainID string, minHeight, maxHeight int64) (FullCommit, error) - - // Get the valset that corresponds to chainID and height and return. - // Height must be >= 1. - ValidatorSet(chainID string, height int64) (*types.ValidatorSet, error) - - // Set a logger. - SetLogger(logger log.Logger) -} - -// A provider that can also persist new information. -// Examples: MemProvider, files.Provider, CacheProvider. -type PersistentProvider interface { - Provider - - // SaveFullCommit saves a FullCommit (without verification). - SaveFullCommit(fc FullCommit) error -} diff --git a/lite/provider_test.go b/lite/provider_test.go deleted file mode 100644 index b820418ff..000000000 --- a/lite/provider_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package lite - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - dbm "github.com/tendermint/tm-db" - - log "github.com/tendermint/tendermint/libs/log" - lerr "github.com/tendermint/tendermint/lite/errors" - "github.com/tendermint/tendermint/types" -) - -// missingProvider doesn't store anything, always a miss. -// Designed as a mock for testing. -type missingProvider struct{} - -// NewMissingProvider returns a provider which does not store anything and always misses. -func NewMissingProvider() PersistentProvider { - return missingProvider{} -} - -func (missingProvider) SaveFullCommit(FullCommit) error { return nil } -func (missingProvider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (FullCommit, error) { - return FullCommit{}, lerr.ErrCommitNotFound() -} -func (missingProvider) ValidatorSet(chainID string, height int64) (*types.ValidatorSet, error) { - return nil, errors.New("missing validator set") -} -func (missingProvider) SetLogger(_ log.Logger) {} - -func TestMemProvider(t *testing.T) { - p := NewDBProvider("mem", dbm.NewMemDB()) - checkProvider(t, p, "test-mem", "empty") -} - -func TestMultiProvider(t *testing.T) { - p := NewMultiProvider( - NewMissingProvider(), - NewDBProvider("mem", dbm.NewMemDB()), - NewMissingProvider(), - ) - checkProvider(t, p, "test-cache", "kjfhekfhkewhgit") -} - -func checkProvider(t *testing.T, p PersistentProvider, chainID, app string) { - assert, require := assert.New(t), require.New(t) - appHash := []byte(app) - keys := genPrivKeys(5) - count := 10 - - // Make a bunch of full commits. - fcz := make([]FullCommit, count) - for i := 0; i < count; i++ { - vals := keys.ToValidators(10, int64(count/2)) - h := int64(20 + 10*i) - fcz[i] = keys.GenFullCommit(chainID, h, nil, vals, vals, appHash, []byte("params"), []byte("results"), 0, 5) - } - - // Check that provider is initially empty. - fc, err := p.LatestFullCommit(chainID, 1, 1<<63-1) - require.NotNil(err) - assert.True(lerr.IsErrCommitNotFound(err)) - - // Save all full commits to the provider. - for _, fc := range fcz { - err = p.SaveFullCommit(fc) - require.Nil(err) - // Make sure we can get it back. - fc2, err := p.LatestFullCommit(chainID, fc.Height(), fc.Height()) - assert.Nil(err) - assert.Equal(fc.SignedHeader, fc2.SignedHeader) - assert.Equal(fc.Validators, fc2.Validators) - assert.Equal(fc.NextValidators, fc2.NextValidators) - } - - // Make sure we get the last hash if we overstep. - fc, err = p.LatestFullCommit(chainID, 1, 5000) - if assert.Nil(err) { - assert.Equal(fcz[count-1].Height(), fc.Height()) - assert.Equal(fcz[count-1], fc) - } - - // ... and middle ones as well. - fc, err = p.LatestFullCommit(chainID, 1, 47) - if assert.Nil(err) { - // we only step by 10, so 40 must be the one below this - assert.EqualValues(40, fc.Height()) - } - -} - -// This will make a get height, and if it is good, set the data as well. -func checkLatestFullCommit(t *testing.T, p PersistentProvider, chainID string, ask, expect int64) { - fc, err := p.LatestFullCommit(chainID, 1, ask) - require.Nil(t, err) - if assert.Equal(t, expect, fc.Height()) { - err = p.SaveFullCommit(fc) - require.Nil(t, err) - } -} - -func TestMultiLatestFullCommit(t *testing.T) { - require := require.New(t) - - // We will write data to the second level of the cache (p2), and see what - // gets cached/stored in. - p := NewDBProvider("mem1", dbm.NewMemDB()) - p2 := NewDBProvider("mem2", dbm.NewMemDB()) - cp := NewMultiProvider(p, p2) - - chainID := "cache-best-height" - appHash := []byte("01234567") - keys := genPrivKeys(5) - count := 10 - - // Set a bunch of full commits. - for i := 0; i < count; i++ { - vals := keys.ToValidators(10, int64(count/2)) - h := int64(10 * (i + 1)) - fc := keys.GenFullCommit(chainID, h, nil, vals, vals, appHash, []byte("params"), []byte("results"), 0, 5) - err := p2.SaveFullCommit(fc) - require.NoError(err) - } - - // Get a few heights from the cache and set them proper. - checkLatestFullCommit(t, cp, chainID, 57, 50) - checkLatestFullCommit(t, cp, chainID, 33, 30) - - // make sure they are set in p as well (but nothing else) - checkLatestFullCommit(t, p, chainID, 44, 30) - checkLatestFullCommit(t, p, chainID, 50, 50) - checkLatestFullCommit(t, p, chainID, 99, 50) - - // now, query the cache for a higher value - checkLatestFullCommit(t, p2, chainID, 99, 90) - checkLatestFullCommit(t, cp, chainID, 99, 90) -} diff --git a/lite/proxy/block.go b/lite/proxy/block.go deleted file mode 100644 index d154bf333..000000000 --- a/lite/proxy/block.go +++ /dev/null @@ -1,48 +0,0 @@ -package proxy - -import ( - "bytes" - "errors" - - "github.com/tendermint/tendermint/types" -) - -func ValidateBlockMeta(meta *types.BlockMeta, sh types.SignedHeader) error { - if meta == nil { - return errors.New("expecting a non-nil BlockMeta") - } - // TODO: check the BlockID?? - return ValidateHeader(&meta.Header, sh) -} - -func ValidateBlock(meta *types.Block, sh types.SignedHeader) error { - if meta == nil { - return errors.New("expecting a non-nil Block") - } - err := ValidateHeader(&meta.Header, sh) - if err != nil { - return err - } - if !bytes.Equal(meta.Data.Hash(), meta.Header.DataHash) { - return errors.New("data hash doesn't match header") - } - return nil -} - -func ValidateHeader(head *types.Header, sh types.SignedHeader) error { - if head == nil { - return errors.New("expecting a non-nil Header") - } - if sh.Header == nil { - return errors.New("unexpected empty SignedHeader") - } - // Make sure they are for the same height (obvious fail). - if head.Height != sh.Height { - return errors.New("header heights mismatched") - } - // Check if they are equal by using hashes. - if !bytes.Equal(head.Hash(), sh.Hash()) { - return errors.New("headers don't match") - } - return nil -} diff --git a/lite/proxy/errors.go b/lite/proxy/errors.go deleted file mode 100644 index 41923659f..000000000 --- a/lite/proxy/errors.go +++ /dev/null @@ -1,21 +0,0 @@ -package proxy - -import ( - "github.com/pkg/errors" -) - -type errNoData struct{} - -func (e errNoData) Error() string { - return "No data returned for query" -} - -// IsErrNoData checks whether an error is due to a query returning empty data -func IsErrNoData(err error) bool { - _, ok := errors.Cause(err).(errNoData) - return ok -} - -func ErrNoData() error { - return errors.Wrap(errNoData{}, "") -} diff --git a/lite/proxy/proof.go b/lite/proxy/proof.go deleted file mode 100644 index 452dee277..000000000 --- a/lite/proxy/proof.go +++ /dev/null @@ -1,14 +0,0 @@ -package proxy - -import ( - "github.com/tendermint/tendermint/crypto/merkle" -) - -func defaultProofRuntime() *merkle.ProofRuntime { - prt := merkle.NewProofRuntime() - prt.RegisterOpDecoder( - merkle.ProofOpSimpleValue, - merkle.SimpleValueOpDecoder, - ) - return prt -} diff --git a/lite/proxy/proxy.go b/lite/proxy/proxy.go deleted file mode 100644 index 461fddea0..000000000 --- a/lite/proxy/proxy.go +++ /dev/null @@ -1,187 +0,0 @@ -package proxy - -import ( - "context" - "net/http" - - amino "github.com/tendermint/go-amino" - - "github.com/tendermint/tendermint/libs/bytes" - "github.com/tendermint/tendermint/libs/log" - rpcclient "github.com/tendermint/tendermint/rpc/client" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" - "github.com/tendermint/tendermint/types" -) - -const ( - wsEndpoint = "/websocket" -) - -// StartProxy will start the websocket manager on the client, -// 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) -// NOTE: This function blocks - you may want to call it in a go-routine. -func StartProxy(c rpcclient.Client, listenAddr string, logger log.Logger, maxOpenConnections int) error { - err := c.Start() - if err != nil { - return err - } - - cdc := amino.NewCodec() - ctypes.RegisterAmino(cdc) - r := RPCRoutes(c) - - // build the handler... - mux := http.NewServeMux() - rpcserver.RegisterRPCFuncs(mux, r, cdc, logger) - - unsubscribeFromAllEvents := func(remoteAddr string) { - if err := c.UnsubscribeAll(context.Background(), remoteAddr); err != nil { - logger.Error("Failed to unsubscribe from events", "err", err) - } - } - wm := rpcserver.NewWebsocketManager(r, cdc, rpcserver.OnDisconnect(unsubscribeFromAllEvents)) - wm.SetLogger(logger) - // core.SetLogger(logger) - mux.HandleFunc(wsEndpoint, wm.WebsocketHandler) - - config := rpcserver.DefaultConfig() - config.MaxOpenConnections = maxOpenConnections - l, err := rpcserver.Listen(listenAddr, config) - if err != nil { - return err - } - return rpcserver.Serve(l, mux, logger, config) -} - -// RPCRoutes just routes everything to the given client, as if it were -// a tendermint fullnode. -// -// if we want security, the client must implement it as a secure client -func RPCRoutes(c rpcclient.Client) map[string]*rpcserver.RPCFunc { - return map[string]*rpcserver.RPCFunc{ - // Subscribe/unsubscribe are reserved for websocket events. - "subscribe": rpcserver.NewWSRPCFunc(c.(Wrapper).SubscribeWS, "query"), - "unsubscribe": rpcserver.NewWSRPCFunc(c.(Wrapper).UnsubscribeWS, "query"), - "unsubscribe_all": rpcserver.NewWSRPCFunc(c.(Wrapper).UnsubscribeAllWS, ""), - - // info API - "status": rpcserver.NewRPCFunc(makeStatusFunc(c), ""), - "blockchain": rpcserver.NewRPCFunc(makeBlockchainInfoFunc(c), "minHeight,maxHeight"), - "genesis": rpcserver.NewRPCFunc(makeGenesisFunc(c), ""), - "block": rpcserver.NewRPCFunc(makeBlockFunc(c), "height"), - "block_by_hash": rpcserver.NewRPCFunc(makeBlockByHashFunc(c), "hash"), - "commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height"), - "tx": rpcserver.NewRPCFunc(makeTxFunc(c), "hash,prove"), - "validators": rpcserver.NewRPCFunc(makeValidatorsFunc(c), "height"), - - // broadcast API - "broadcast_tx_commit": rpcserver.NewRPCFunc(makeBroadcastTxCommitFunc(c), "tx"), - "broadcast_tx_sync": rpcserver.NewRPCFunc(makeBroadcastTxSyncFunc(c), "tx"), - "broadcast_tx_async": rpcserver.NewRPCFunc(makeBroadcastTxAsyncFunc(c), "tx"), - - // abci API - "abci_query": rpcserver.NewRPCFunc(makeABCIQueryFunc(c), "path,data"), - "abci_info": rpcserver.NewRPCFunc(makeABCIInfoFunc(c), ""), - } -} - -func makeStatusFunc(c rpcclient.StatusClient) func(ctx *rpctypes.Context) (*ctypes.ResultStatus, error) { - return func(ctx *rpctypes.Context) (*ctypes.ResultStatus, error) { - return c.Status() - } -} - -func makeBlockchainInfoFunc(c rpcclient.Client) func( - ctx *rpctypes.Context, - minHeight, - maxHeight int64, -) (*ctypes.ResultBlockchainInfo, error) { - return func(ctx *rpctypes.Context, minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) { - return c.BlockchainInfo(minHeight, maxHeight) - } -} - -func makeGenesisFunc(c rpcclient.Client) func(ctx *rpctypes.Context) (*ctypes.ResultGenesis, error) { - return func(ctx *rpctypes.Context) (*ctypes.ResultGenesis, error) { - return c.Genesis() - } -} - -func makeBlockFunc(c rpcclient.Client) func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultBlock, error) { - return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultBlock, error) { - return c.Block(height) - } -} - -func makeBlockByHashFunc(c rpcclient.Client) func(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error) { - return func(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error) { - return c.BlockByHash(hash) - } -} - -func makeCommitFunc(c rpcclient.Client) func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultCommit, error) { - return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultCommit, error) { - return c.Commit(height) - } -} - -func makeTxFunc(c rpcclient.Client) func(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { - return func(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { - return c.Tx(hash, prove) - } -} - -func makeValidatorsFunc(c rpcclient.Client) func( - ctx *rpctypes.Context, - height *int64, -) (*ctypes.ResultValidators, error) { - return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultValidators, error) { - return c.Validators(height, 0, 0) - } -} - -func makeBroadcastTxCommitFunc(c rpcclient.Client) func( - ctx *rpctypes.Context, - tx types.Tx, -) (*ctypes.ResultBroadcastTxCommit, error) { - return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { - return c.BroadcastTxCommit(tx) - } -} - -func makeBroadcastTxSyncFunc(c rpcclient.Client) func( - ctx *rpctypes.Context, - tx types.Tx, -) (*ctypes.ResultBroadcastTx, error) { - return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) { - return c.BroadcastTxSync(tx) - } -} - -func makeBroadcastTxAsyncFunc(c rpcclient.Client) func( - ctx *rpctypes.Context, - tx types.Tx, -) (*ctypes.ResultBroadcastTx, error) { - return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) { - return c.BroadcastTxAsync(tx) - } -} - -func makeABCIQueryFunc(c rpcclient.Client) func( - ctx *rpctypes.Context, - path string, - data bytes.HexBytes, -) (*ctypes.ResultABCIQuery, error) { - return func(ctx *rpctypes.Context, path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) { - return c.ABCIQuery(path, data) - } -} - -func makeABCIInfoFunc(c rpcclient.Client) func(ctx *rpctypes.Context) (*ctypes.ResultABCIInfo, error) { - return func(ctx *rpctypes.Context) (*ctypes.ResultABCIInfo, error) { - return c.ABCIInfo() - } -} diff --git a/lite/proxy/query.go b/lite/proxy/query.go deleted file mode 100644 index f95b4708b..000000000 --- a/lite/proxy/query.go +++ /dev/null @@ -1,148 +0,0 @@ -package proxy - -import ( - "fmt" - "strings" - - "github.com/pkg/errors" - - "github.com/tendermint/tendermint/crypto/merkle" - "github.com/tendermint/tendermint/libs/bytes" - "github.com/tendermint/tendermint/lite" - lerr "github.com/tendermint/tendermint/lite/errors" - rpcclient "github.com/tendermint/tendermint/rpc/client" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - "github.com/tendermint/tendermint/types" -) - -// GetWithProof will query the key on the given node, and verify it has -// a valid proof, as defined by the Verifier. -// -// If there is any error in checking, returns an error. -func GetWithProof(prt *merkle.ProofRuntime, key []byte, reqHeight int64, node rpcclient.Client, - cert lite.Verifier) ( - val bytes.HexBytes, height int64, proof *merkle.Proof, err error) { - - if reqHeight < 0 { - err = errors.New("height cannot be negative") - return - } - - res, err := GetWithProofOptions(prt, "/key", key, - rpcclient.ABCIQueryOptions{Height: reqHeight, Prove: true}, - node, cert) - if err != nil { - return - } - - resp := res.Response - val, height = resp.Value, resp.Height - return val, height, proof, err -} - -// GetWithProofOptions is useful if you want full access to the ABCIQueryOptions. -// XXX Usage of path? It's not used, and sometimes it's /, sometimes /key, sometimes /store. -func GetWithProofOptions(prt *merkle.ProofRuntime, path string, key []byte, opts rpcclient.ABCIQueryOptions, - node rpcclient.Client, cert lite.Verifier) ( - *ctypes.ResultABCIQuery, error) { - opts.Prove = true - res, err := node.ABCIQueryWithOptions(path, key, opts) - if err != nil { - return nil, err - } - resp := res.Response - - // Validate the response, e.g. height. - if resp.IsErr() { - err = errors.Errorf("query error for key %d: %d", key, resp.Code) - return nil, err - } - - if len(resp.Key) == 0 || resp.Proof == nil { - return nil, lerr.ErrEmptyTree() - } - if resp.Height == 0 { - return nil, errors.New("height returned is zero") - } - - // AppHash for height H is in header H+1 - signedHeader, err := GetCertifiedCommit(resp.Height+1, node, cert) - if err != nil { - return nil, err - } - - // Validate the proof against the certified header to ensure data integrity. - if resp.Value != nil { - // Value exists - // XXX How do we encode the key into a string... - storeName, err := parseQueryStorePath(path) - if err != nil { - return nil, err - } - - kp := merkle.KeyPath{} - kp = kp.AppendKey([]byte(storeName), merkle.KeyEncodingURL) - kp = kp.AppendKey(resp.Key, merkle.KeyEncodingURL) - err = prt.VerifyValue(resp.Proof, signedHeader.AppHash, kp.String(), resp.Value) - if err != nil { - return nil, errors.Wrap(err, "couldn't verify value proof") - } - - return &ctypes.ResultABCIQuery{Response: resp}, nil - } - - // Value absent - // Validate the proof against the certified header to ensure data integrity. - // XXX How do we encode the key into a string... - err = prt.VerifyAbsence(resp.Proof, signedHeader.AppHash, string(resp.Key)) - if err != nil { - return nil, errors.Wrap(err, "couldn't verify absence proof") - } - - return &ctypes.ResultABCIQuery{Response: resp}, nil -} - -func parseQueryStorePath(path string) (storeName string, err error) { - if !strings.HasPrefix(path, "/") { - return "", fmt.Errorf("expected path to start with /") - } - - paths := strings.SplitN(path[1:], "/", 3) - switch { - case len(paths) != 3: - return "", fmt.Errorf("expected format like /store//key") - case paths[0] != "store": - return "", fmt.Errorf("expected format like /store//key") - case paths[2] != "key": - return "", fmt.Errorf("expected format like /store//key") - } - - return paths[1], nil -} - -// 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, client rpcclient.Client, cert lite.Verifier) (types.SignedHeader, error) { - - // FIXME: cannot use cert.GetByHeight for now, as it also requires - // Validators and will fail on querying tendermint for non-current height. - // When this is supported, we should use it instead... - rpcclient.WaitForHeight(client, h, nil) - cresp, err := client.Commit(&h) - if err != nil { - return types.SignedHeader{}, err - } - - // Validate downloaded checkpoint with our request and trust store. - sh := cresp.SignedHeader - if sh.Height != h { - return types.SignedHeader{}, fmt.Errorf("height mismatch: want %v got %v", - h, sh.Height) - } - - if err = cert.Verify(sh); err != nil { - return types.SignedHeader{}, err - } - - return sh, nil -} diff --git a/lite/proxy/query_test.go b/lite/proxy/query_test.go deleted file mode 100644 index 766a86040..000000000 --- a/lite/proxy/query_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package proxy - -import ( - "fmt" - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/abci/example/kvstore" - "github.com/tendermint/tendermint/crypto/merkle" - "github.com/tendermint/tendermint/lite" - certclient "github.com/tendermint/tendermint/lite/client" - nm "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/rpc/client" - rpclocal "github.com/tendermint/tendermint/rpc/client/local" - rpctest "github.com/tendermint/tendermint/rpc/test" - "github.com/tendermint/tendermint/types" -) - -var node *nm.Node -var chainID = "tendermint_test" // TODO use from config. -//nolint:unused -var waitForEventTimeout = 5 * time.Second - -// TODO fix tests!! - -func TestMain(m *testing.M) { - app := kvstore.NewApplication() - node = rpctest.StartTendermint(app) - - code := m.Run() - - rpctest.StopTendermint(node) - os.Exit(code) -} - -func kvstoreTx(k, v []byte) []byte { - return []byte(fmt.Sprintf("%s=%s", k, v)) -} - -// TODO: enable it after general proof format has been adapted -// in abci/examples/kvstore.go -//nolint:unused,deadcode -func _TestAppProofs(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - prt := defaultProofRuntime() - cl := rpclocal.New(node) - client.WaitForHeight(cl, 1, nil) - - // This sets up our trust on the node based on some past point. - source := certclient.NewProvider(chainID, cl) - seed, err := source.LatestFullCommit(chainID, 1, 1) - require.NoError(err, "%#v", err) - cert := lite.NewBaseVerifier(chainID, seed.Height(), seed.Validators) - - // Wait for tx confirmation. - done := make(chan int64) - go func() { - evtTyp := types.EventTx - _, err = client.WaitForOneEvent(cl, evtTyp, waitForEventTimeout) - require.Nil(err, "%#v", err) - close(done) - }() - - // Submit a transaction. - k := []byte("my-key") - v := []byte("my-value") - tx := kvstoreTx(k, v) - br, err := cl.BroadcastTxCommit(tx) - require.NoError(err, "%#v", err) - require.EqualValues(0, br.CheckTx.Code, "%#v", br.CheckTx) - require.EqualValues(0, br.DeliverTx.Code) - brh := br.Height - - // Fetch latest after tx commit. - <-done - latest, err := source.LatestFullCommit(chainID, 1, 1<<63-1) - require.NoError(err, "%#v", err) - rootHash := latest.SignedHeader.AppHash - if rootHash == nil { - // Fetch one block later, AppHash hasn't been committed yet. - // TODO find a way to avoid doing this. - client.WaitForHeight(cl, latest.SignedHeader.Height+1, nil) - latest, err = source.LatestFullCommit(chainID, latest.SignedHeader.Height+1, 1<<63-1) - require.NoError(err, "%#v", err) - rootHash = latest.SignedHeader.AppHash - } - require.NotNil(rootHash) - - // verify a query before the tx block has no data (and valid non-exist proof) - bs, height, proof, err := GetWithProof(prt, k, brh-1, cl, cert) - require.NoError(err, "%#v", err) - require.NotNil(proof) - require.Equal(height, brh-1) - // require.NotNil(proof) - // TODO: Ensure that *some* keys will be there, ensuring that proof is nil, - // (currently there's a race condition) - // and ensure that proof proves absence of k. - require.Nil(bs) - - // but given that block it is good - bs, height, proof, err = GetWithProof(prt, k, brh, cl, cert) - require.NoError(err, "%#v", err) - require.NotNil(proof) - require.Equal(height, brh) - - assert.EqualValues(v, bs) - err = prt.VerifyValue(proof, rootHash, string(k), bs) // XXX key encoding - assert.NoError(err, "%#v", err) - - // Test non-existing key. - missing := []byte("my-missing-key") - bs, _, proof, err = GetWithProof(prt, missing, 0, cl, cert) - require.NoError(err) - require.Nil(bs) - require.NotNil(proof) - err = prt.VerifyAbsence(proof, rootHash, string(missing)) // XXX VerifyAbsence(), keyencoding - assert.NoError(err, "%#v", err) - err = prt.VerifyAbsence(proof, rootHash, string(k)) // XXX VerifyAbsence(), keyencoding - assert.Error(err, "%#v", err) -} - -func TestTxProofs(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - cl := rpclocal.New(node) - client.WaitForHeight(cl, 1, nil) - - tx := kvstoreTx([]byte("key-a"), []byte("value-a")) - br, err := cl.BroadcastTxCommit(tx) - require.NoError(err, "%#v", err) - require.EqualValues(0, br.CheckTx.Code, "%#v", br.CheckTx) - require.EqualValues(0, br.DeliverTx.Code) - brh := br.Height - - source := certclient.NewProvider(chainID, cl) - seed, err := source.LatestFullCommit(chainID, brh-2, brh-2) - require.NoError(err, "%#v", err) - cert := lite.NewBaseVerifier(chainID, seed.Height(), seed.Validators) - - // First let's make sure a bogus transaction hash returns a valid non-existence proof. - key := types.Tx([]byte("bogus")).Hash() - _, err = cl.Tx(key, true) - require.NotNil(err) - require.Contains(err.Error(), "not found") - - // Now let's check with the real tx root hash. - key = types.Tx(tx).Hash() - res, err := cl.Tx(key, true) - require.NoError(err, "%#v", err) - require.NotNil(res) - keyHash := merkle.SimpleHashFromByteSlices([][]byte{key}) - err = res.Proof.Validate(keyHash) - assert.NoError(err, "%#v", err) - - commit, err := GetCertifiedCommit(br.Height, cl, cert) - require.Nil(err, "%#v", err) - require.Equal(res.Proof.RootHash, commit.Header.DataHash) -} diff --git a/lite/proxy/validate_test.go b/lite/proxy/validate_test.go deleted file mode 100644 index cf9a0de6b..000000000 --- a/lite/proxy/validate_test.go +++ /dev/null @@ -1,211 +0,0 @@ -package proxy_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/tendermint/tendermint/lite/proxy" - "github.com/tendermint/tendermint/types" -) - -var ( - deadBeefTxs = types.Txs{[]byte("DE"), []byte("AD"), []byte("BE"), []byte("EF")} - deadBeefHash = deadBeefTxs.Hash() - testTime1 = time.Date(2018, 1, 1, 1, 1, 1, 1, time.UTC) - testTime2 = time.Date(2017, 1, 2, 1, 1, 1, 1, time.UTC) -) - -var hdrHeight11 = types.Header{ - Height: 11, - Time: testTime1, - ValidatorsHash: []byte("Tendermint"), -} - -func TestValidateBlock(t *testing.T) { - tests := []struct { - block *types.Block - signedHeader types.SignedHeader - wantErr string - }{ - { - block: nil, wantErr: "non-nil Block", - }, - { - block: &types.Block{}, wantErr: "unexpected empty SignedHeader", - }, - - // Start Header.Height mismatch test - { - block: &types.Block{Header: types.Header{Height: 10}}, - signedHeader: types.SignedHeader{Header: &types.Header{Height: 11}}, - wantErr: "header heights mismatched", - }, - - { - block: &types.Block{Header: types.Header{Height: 11}}, - signedHeader: types.SignedHeader{Header: &types.Header{Height: 11}}, - }, - // End Header.Height mismatch test - - // Start Header.Hash mismatch test - { - block: &types.Block{Header: hdrHeight11}, - signedHeader: types.SignedHeader{Header: &types.Header{Height: 11}}, - wantErr: "headers don't match", - }, - - { - block: &types.Block{Header: hdrHeight11}, - signedHeader: types.SignedHeader{Header: &hdrHeight11}, - }, - // End Header.Hash mismatch test - - // Start Header.Data hash mismatch test - { - block: &types.Block{ - Header: types.Header{Height: 11}, - Data: types.Data{Txs: []types.Tx{[]byte("0xDE"), []byte("AD")}}, - }, - signedHeader: types.SignedHeader{ - Header: &types.Header{Height: 11}, - Commit: types.NewCommit(11, 0, types.BlockID{Hash: []byte("0xDEADBEEF")}, nil), - }, - wantErr: "data hash doesn't match header", - }, - { - block: &types.Block{ - Header: types.Header{Height: 11, DataHash: deadBeefHash}, - Data: types.Data{Txs: deadBeefTxs}, - }, - signedHeader: types.SignedHeader{ - Header: &types.Header{Height: 11}, - Commit: types.NewCommit(11, 0, types.BlockID{Hash: []byte("DEADBEEF")}, nil), - }, - }, - // End Header.Data hash mismatch test - } - - for i, tt := range tests { - err := proxy.ValidateBlock(tt.block, tt.signedHeader) - if tt.wantErr != "" { - if err == nil { - assert.FailNowf(t, "Unexpectedly passed", "#%d", i) - } else { - assert.Contains(t, err.Error(), tt.wantErr, "#%d should contain the substring\n\n", i) - } - continue - } - - assert.Nil(t, err, "#%d: expecting a nil error", i) - } -} - -func TestValidateBlockMeta(t *testing.T) { - tests := []struct { - meta *types.BlockMeta - signedHeader types.SignedHeader - wantErr string - }{ - { - meta: nil, wantErr: "non-nil BlockMeta", - }, - { - meta: &types.BlockMeta{}, wantErr: "unexpected empty SignedHeader", - }, - - // Start Header.Height mismatch test - { - meta: &types.BlockMeta{Header: types.Header{Height: 10}}, - signedHeader: types.SignedHeader{Header: &types.Header{Height: 11}}, - wantErr: "header heights mismatched", - }, - - { - meta: &types.BlockMeta{Header: types.Header{Height: 11}}, - signedHeader: types.SignedHeader{Header: &types.Header{Height: 11}}, - }, - // End Header.Height mismatch test - - // Start Headers don't match test - { - meta: &types.BlockMeta{Header: hdrHeight11}, - signedHeader: types.SignedHeader{Header: &types.Header{Height: 11}}, - wantErr: "headers don't match", - }, - - { - meta: &types.BlockMeta{Header: hdrHeight11}, - signedHeader: types.SignedHeader{Header: &hdrHeight11}, - }, - - { - meta: &types.BlockMeta{ - Header: types.Header{ - Height: 11, - ValidatorsHash: []byte("lite-test"), - // TODO: should be able to use empty time after Amino upgrade - Time: testTime1, - }, - }, - signedHeader: types.SignedHeader{ - Header: &types.Header{Height: 11, DataHash: deadBeefHash}, - }, - wantErr: "headers don't match", - }, - - { - meta: &types.BlockMeta{ - Header: types.Header{ - Height: 11, DataHash: deadBeefHash, - ValidatorsHash: []byte("Tendermint"), - Time: testTime1, - }, - }, - signedHeader: types.SignedHeader{ - Header: &types.Header{ - Height: 11, DataHash: deadBeefHash, - ValidatorsHash: []byte("Tendermint"), - Time: testTime2, - }, - Commit: types.NewCommit(11, 0, types.BlockID{Hash: []byte("DEADBEEF")}, nil), - }, - wantErr: "headers don't match", - }, - - { - meta: &types.BlockMeta{ - Header: types.Header{ - Height: 11, DataHash: deadBeefHash, - ValidatorsHash: []byte("Tendermint"), - Time: testTime2, - }, - }, - signedHeader: types.SignedHeader{ - Header: &types.Header{ - Height: 11, DataHash: deadBeefHash, - ValidatorsHash: []byte("Tendermint-x"), - Time: testTime2, - }, - Commit: types.NewCommit(11, 0, types.BlockID{Hash: []byte("DEADBEEF")}, nil), - }, - wantErr: "headers don't match", - }, - // End Headers don't match test - } - - for i, tt := range tests { - err := proxy.ValidateBlockMeta(tt.meta, tt.signedHeader) - if tt.wantErr != "" { - if err == nil { - assert.FailNowf(t, "Unexpectedly passed", "#%d: wanted error %q", i, tt.wantErr) - } else { - assert.Contains(t, err.Error(), tt.wantErr, "#%d should contain the substring\n\n", i) - } - continue - } - - assert.Nil(t, err, "#%d: expecting a nil error", i) - } -} diff --git a/lite/proxy/verifier.go b/lite/proxy/verifier.go deleted file mode 100644 index 5486a3ea9..000000000 --- a/lite/proxy/verifier.go +++ /dev/null @@ -1,49 +0,0 @@ -package proxy - -import ( - "github.com/pkg/errors" - - dbm "github.com/tendermint/tm-db" - - log "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/lite" - lclient "github.com/tendermint/tendermint/lite/client" -) - -func NewVerifier( - chainID, - rootDir string, - client lclient.SignStatusClient, - logger log.Logger, - cacheSize int, -) (*lite.DynamicVerifier, error) { - - logger = logger.With("module", "lite/proxy") - logger.Info("lite/proxy/NewVerifier()...", "chainID", chainID, "rootDir", rootDir, "client", client) - - memProvider := lite.NewDBProvider("trusted.mem", dbm.NewMemDB()).SetLimit(cacheSize) - lvlProvider := lite.NewDBProvider("trusted.lvl", dbm.NewDB("trust-base", dbm.GoLevelDBBackend, rootDir)) - trust := lite.NewMultiProvider( - memProvider, - lvlProvider, - ) - source := lclient.NewProvider(chainID, client) - cert := lite.NewDynamicVerifier(chainID, trust, source) - cert.SetLogger(logger) // Sets logger recursively. - - // TODO: Make this more secure, e.g. make it interactive in the console? - _, err := trust.LatestFullCommit(chainID, 1, 1<<63-1) - if err != nil { - logger.Info("lite/proxy/NewVerifier found no trusted full commit, initializing from source from height 1...") - fc, err := source.LatestFullCommit(chainID, 1, 1) - if err != nil { - return nil, errors.Wrap(err, "fetching source full commit @ height 1") - } - err = trust.SaveFullCommit(fc) - if err != nil { - return nil, errors.Wrap(err, "saving full commit to trusted") - } - } - - return cert, nil -} diff --git a/lite/proxy/wrapper.go b/lite/proxy/wrapper.go deleted file mode 100644 index 82337f6a8..000000000 --- a/lite/proxy/wrapper.go +++ /dev/null @@ -1,275 +0,0 @@ -package proxy - -import ( - "context" - - "github.com/tendermint/tendermint/crypto/merkle" - "github.com/tendermint/tendermint/libs/bytes" - "github.com/tendermint/tendermint/lite" - rpcclient "github.com/tendermint/tendermint/rpc/client" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" -) - -var _ rpcclient.Client = Wrapper{} - -// 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. -type Wrapper struct { - rpcclient.Client - cert *lite.DynamicVerifier - prt *merkle.ProofRuntime -} - -// SecureClient uses a given Verifier 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.DynamicVerifier) Wrapper { - prt := defaultProofRuntime() - wrap := Wrapper{c, cert, prt} - // 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 hc, ok := c.(*rpcclient.HTTP); ok { - // evt := hc.WSEvents.EventSwitch - // hc.WSEvents.EventSwitch = WrappedSwitch{evt, wrap} - // } - return wrap -} - -// ABCIQueryWithOptions exposes all options for the ABCI query and verifies the returned proof -func (w Wrapper) ABCIQueryWithOptions(path string, data bytes.HexBytes, - opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { - - res, err := GetWithProofOptions(w.prt, path, data, opts, w.Client, w.cert) - return res, err -} - -// ABCIQuery uses default options for the ABCI query and verifies the returned proof -func (w Wrapper) ABCIQuery(path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) { - return w.ABCIQueryWithOptions(path, data, rpcclient.DefaultABCIQueryOptions) -} - -// Tx queries for a given tx and verifies the proof if it was requested -func (w Wrapper) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) { - res, err := w.Client.Tx(hash, prove) - if !prove || err != nil { - return res, err - } - h := res.Height - sh, err := GetCertifiedCommit(h, w.Client, w.cert) - if err != nil { - return res, err - } - err = res.Proof.Validate(sh.DataHash) - return res, err -} - -// BlockchainInfo requests a list of headers and verifies them all... -// Rather expensive. -// -// TODO: optimize this if used for anything needing performance -func (w Wrapper) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) { - r, err := w.Client.BlockchainInfo(minHeight, maxHeight) - if err != nil { - return nil, err - } - - // go and verify every blockmeta in the result.... - for _, meta := range r.BlockMetas { - // get a checkpoint to verify from - res, err := w.Commit(&meta.Header.Height) - if err != nil { - return nil, err - } - sh := res.SignedHeader - err = ValidateBlockMeta(meta, sh) - if err != nil { - return nil, err - } - } - - return r, nil -} - -// Block returns an entire block and verifies all signatures -func (w Wrapper) Block(height *int64) (*ctypes.ResultBlock, error) { - resBlock, err := w.Client.Block(height) - if err != nil { - return nil, err - } - // get a checkpoint to verify from - resCommit, err := w.Commit(height) - if err != nil { - return nil, err - } - sh := resCommit.SignedHeader - - err = ValidateBlock(resBlock.Block, sh) - if err != nil { - return nil, err - } - return resBlock, nil -} - -// BlockByHash returns an entire block and verifies all signatures -func (w Wrapper) BlockByHash(hash []byte) (*ctypes.ResultBlock, error) { - resBlock, err := w.Client.BlockByHash(hash) - if err != nil { - return nil, err - } - // get a checkpoint to verify from - resCommit, err := w.Commit(&resBlock.Block.Height) - if err != nil { - return nil, err - } - sh := resCommit.SignedHeader - - err = ValidateBlock(resBlock.Block, sh) - if err != nil { - return nil, err - } - return resBlock, nil -} - -// Commit downloads the Commit and certifies it with the lite. -// -// This is the foundation for all other verification in this module -func (w Wrapper) Commit(height *int64) (*ctypes.ResultCommit, error) { - if height == nil { - resStatus, err := w.Client.Status() - if err != nil { - return nil, err - } - // NOTE: If resStatus.CatchingUp, there is a race - // condition where the validator set for the next height - // isn't available until some time after the blockstore - // has height h on the remote node. This isn't an issue - // once the node has caught up, and a syncing node likely - // won't have this issue esp with the implementation we - // have here, but we may have to address this at some - // point. - height = new(int64) - *height = resStatus.SyncInfo.LatestBlockHeight - } - rpcclient.WaitForHeight(w.Client, *height, nil) - res, err := w.Client.Commit(height) - // if we got it, then verify it - if err == nil { - sh := res.SignedHeader - err = w.cert.Verify(sh) - } - return res, err -} - -func (w Wrapper) RegisterOpDecoder(typ string, dec merkle.OpDecoder) { - w.prt.RegisterOpDecoder(typ, dec) -} - -// SubscribeWS subscribes for events using the given query and remote address as -// a subscriber, but does not verify responses (UNSAFE)! -func (w Wrapper) SubscribeWS(ctx *rpctypes.Context, query string) (*ctypes.ResultSubscribe, error) { - out, err := w.Client.Subscribe(context.Background(), ctx.RemoteAddr(), query) - if err != nil { - return nil, err - } - - go func() { - for { - select { - case resultEvent := <-out: - // XXX(melekes) We should have a switch here that performs a validation - // depending on the event's type. - ctx.WSConn.TryWriteRPCResponse( - rpctypes.NewRPCSuccessResponse( - ctx.WSConn.Codec(), - ctx.JSONReq.ID, - resultEvent, - )) - case <-w.Client.Quit(): - return - } - } - }() - - return &ctypes.ResultSubscribe{}, nil -} - -// UnsubscribeWS calls original client's Unsubscribe using remote address as a -// subscriber. -func (w Wrapper) UnsubscribeWS(ctx *rpctypes.Context, query string) (*ctypes.ResultUnsubscribe, error) { - err := w.Client.Unsubscribe(context.Background(), ctx.RemoteAddr(), query) - if err != nil { - return nil, err - } - return &ctypes.ResultUnsubscribe{}, nil -} - -// UnsubscribeAllWS calls original client's UnsubscribeAll using remote address -// as a subscriber. -func (w Wrapper) UnsubscribeAllWS(ctx *rpctypes.Context) (*ctypes.ResultUnsubscribe, error) { - err := w.Client.UnsubscribeAll(context.Background(), ctx.RemoteAddr()) - if err != nil { - return nil, err - } - return &ctypes.ResultUnsubscribe{}, nil -} - -// // WrappedSwitch creates a websocket connection that auto-verifies any info -// // coming through before passing it along. -// // -// // Since the verification takes 1-2 rpc calls, this is obviously only for -// // relatively low-throughput situations that can tolerate a bit extra latency -// type WrappedSwitch struct { -// types.EventSwitch -// client rpcclient.Client -// } - -// // FireEvent verifies any block or header returned from the eventswitch -// func (s WrappedSwitch) FireEvent(event string, data events.EventData) { -// tm, ok := data.(types.TMEventData) -// if !ok { -// fmt.Printf("bad type %#v\n", data) -// return -// } - -// // check to validate it if possible, and drop if not valid -// switch t := tm.(type) { -// case types.EventDataNewBlockHeader: -// err := verifyHeader(s.client, t.Header) -// if err != nil { -// fmt.Printf("Invalid header: %#v\n", err) -// return -// } -// case types.EventDataNewBlock: -// err := verifyBlock(s.client, t.Block) -// if err != nil { -// fmt.Printf("Invalid block: %#v\n", err) -// return -// } -// // TODO: can we verify tx as well? anything else -// } - -// // looks good, we fire it -// s.EventSwitch.FireEvent(event, data) -// } - -// func verifyHeader(c rpcclient.Client, head *types.Header) error { -// // get a checkpoint to verify from -// commit, err := c.Commit(&head.Height) -// if err != nil { -// return err -// } -// check := certclient.CommitFromResult(commit) -// return ValidateHeader(head, check) -// } -// -// func verifyBlock(c rpcclient.Client, block *types.Block) error { -// // get a checkpoint to verify from -// commit, err := c.Commit(&block.Height) -// if err != nil { -// return err -// } -// check := certclient.CommitFromResult(commit) -// return ValidateBlock(block, check) -// } diff --git a/lite/types.go b/lite/types.go deleted file mode 100644 index 643f5ad48..000000000 --- a/lite/types.go +++ /dev/null @@ -1,13 +0,0 @@ -package lite - -import ( - "github.com/tendermint/tendermint/types" -) - -// Verifier checks the votes to make sure the block really is signed properly. -// Verifier must know the current or recent set of validitors by some other -// means. -type Verifier interface { - Verify(sheader types.SignedHeader) error - ChainID() string -} diff --git a/node/node.go b/node/node.go index 540362529..2e5b14c1e 100644 --- a/node/node.go +++ b/node/node.go @@ -29,7 +29,7 @@ import ( "github.com/tendermint/tendermint/libs/log" tmpubsub "github.com/tendermint/tendermint/libs/pubsub" "github.com/tendermint/tendermint/libs/service" - lite "github.com/tendermint/tendermint/lite2" + "github.com/tendermint/tendermint/light" mempl "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p/pex" @@ -574,11 +574,11 @@ func startStateSync(ssR *statesync.Reactor, bcR fastSyncReactor, conR *cs.Reacto if stateProvider == nil { var err error stateProvider, err = statesync.NewLightClientStateProvider(state.ChainID, state.Version, - config.RPCServers, lite.TrustOptions{ + config.RPCServers, light.TrustOptions{ Period: config.TrustPeriod, Height: config.TrustHeight, Hash: config.TrustHashBytes(), - }, ssR.Logger.With("module", "lite")) + }, ssR.Logger.With("module", "light")) if err != nil { return fmt.Errorf("failed to set up light client state provider: %w", err) } diff --git a/statesync/stateprovider.go b/statesync/stateprovider.go index 2726de853..a6e411465 100644 --- a/statesync/stateprovider.go +++ b/statesync/stateprovider.go @@ -9,11 +9,11 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/tendermint/tendermint/libs/log" - lite "github.com/tendermint/tendermint/lite2" - liteprovider "github.com/tendermint/tendermint/lite2/provider" - litehttp "github.com/tendermint/tendermint/lite2/provider/http" - literpc "github.com/tendermint/tendermint/lite2/rpc" - litedb "github.com/tendermint/tendermint/lite2/store/db" + "github.com/tendermint/tendermint/light" + lightprovider "github.com/tendermint/tendermint/light/provider" + lighthttp "github.com/tendermint/tendermint/light/provider/http" + lightrpc "github.com/tendermint/tendermint/light/rpc" + lightdb "github.com/tendermint/tendermint/light/store/db" rpchttp "github.com/tendermint/tendermint/rpc/client/http" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" @@ -34,10 +34,10 @@ type StateProvider interface { // lightClientStateProvider is a state provider using the light client. type lightClientStateProvider struct { - sync.Mutex // lite.Client is not concurrency-safe - lc *lite.Client + sync.Mutex // light.Client is not concurrency-safe + lc *light.Client version sm.Version - providers map[liteprovider.Provider]string + providers map[lightprovider.Provider]string } // NewLightClientStateProvider creates a new StateProvider using a light client and RPC clients. @@ -45,29 +45,29 @@ func NewLightClientStateProvider( chainID string, version sm.Version, servers []string, - trustOptions lite.TrustOptions, + trustOptions light.TrustOptions, logger log.Logger, ) (StateProvider, error) { if len(servers) < 2 { return nil, fmt.Errorf("at least 2 RPC servers are required, got %v", len(servers)) } - providers := make([]liteprovider.Provider, 0, len(servers)) - providerRemotes := make(map[liteprovider.Provider]string) + providers := make([]lightprovider.Provider, 0, len(servers)) + providerRemotes := make(map[lightprovider.Provider]string) for _, server := range servers { client, err := rpcClient(server) if err != nil { return nil, fmt.Errorf("failed to set up RPC client: %w", err) } - provider := litehttp.NewWithClient(chainID, client) + provider := lighthttp.NewWithClient(chainID, client) providers = append(providers, provider) // We store the RPC addresses keyed by provider, so we can find the address of the primary // provider used by the light client and use it to fetch consensus parameters. providerRemotes[provider] = server } - lc, err := lite.NewClient(chainID, trustOptions, providers[0], providers[1:], - litedb.New(dbm.NewMemDB(), ""), lite.Logger(logger), lite.MaxRetryAttempts(5)) + lc, err := light.NewClient(chainID, trustOptions, providers[0], providers[1:], + lightdb.New(dbm.NewMemDB(), ""), light.Logger(logger), light.MaxRetryAttempts(5)) if err != nil { return nil, err } @@ -155,7 +155,7 @@ func (s *lightClientStateProvider) State(height uint64) (sm.State, error) { if err != nil { return sm.State{}, fmt.Errorf("unable to create RPC client: %w", err) } - rpcclient := literpc.NewClient(primaryRPC, s.lc) + rpcclient := lightrpc.NewClient(primaryRPC, s.lc) result, err := rpcclient.ConsensusParams(&nextHeader.Height) if err != nil { return sm.State{}, fmt.Errorf("unable to fetch consensus parameters for height %v: %w", diff --git a/types/block.go b/types/block.go index c4c9dacfa..043357742 100644 --- a/types/block.go +++ b/types/block.go @@ -902,7 +902,7 @@ func CommitFromProto(cp *tmproto.Commit) (*Commit, error) { //----------------------------------------------------------------------------- // SignedHeader is a header along with the commits that prove it. -// It is the basis of the lite client. +// It is the basis of the light client. type SignedHeader struct { *Header `json:"header"` diff --git a/types/validator_set.go b/types/validator_set.go index 940404f0f..70afaa790 100644 --- a/types/validator_set.go +++ b/types/validator_set.go @@ -728,7 +728,7 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, // old vals to sign the future commit at H, that way we preserve the property // that if they weren't being truthful about the validator set at H (block hash // -> vals hash) or about the app state (block hash -> app hash) we can slash -// > 2/3. Otherwise, the lite client isn't providing the same security +// > 2/3. Otherwise, the light client isn't providing the same security // guarantees. // // Even if we added a slashing condition that if you sign a block header with