diff --git a/Makefile b/Makefile index 291e647f2f..70068a9d86 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,9 @@ dist: check_tools: cd tools && $(MAKE) check +update_tools: + cd tools && $(MAKE) glide_update + get_tools: cd tools && $(MAKE) diff --git a/_attic/ROADMAP.md b/_attic/ROADMAP.md deleted file mode 100644 index 9e344eb62f..0000000000 --- a/_attic/ROADMAP.md +++ /dev/null @@ -1,66 +0,0 @@ -# Roadmap for future basecoin development - -Warning: there are current plans, they may change based on other developments, needs. The further in the future, the less clear, like all plans. - -## 0.6.x - Testnet and Light Client (late June 2017) - -The current release cycle is making sure the server is usable for deploying testnets (easy config, safe restarts, moving nodes). Also that we have a useable light client that does full cryptographic prooofs without syncing the entire block headers. See the [changelog](CHANGELOG.md). - -Patch release here involve improving the usability of the cli tools, adding subcommands, more flags, helper functions, shell integrations, etc. Please add issues if you find the client tool difficult to use, or deployment troublesome. - -## 0.7.x - Towards a modular framework (late July 2017) - -**Breaking changes** - -* Renaming likely: this release may well lead to a [renaming of the repository](https://github.com/tendermint/basecoin/issues/119) to emphasize that it is a generalized framework. `basecoin` and `basecli` executables will remain with generally unchanged usage. -* This will also provide a tx structure that is very different than the current one, and a non-trivial upgrade of running chains. - -The next release cycle involves a big upgrade to the core, especially how one can write modules (aka plugins) as well as configure a basecoin-based executable. The main goal is to leave us with basecoin as a single executable with a similar API, but create a new module/middleware system with a number of standard modules provided (and easy addition of third party modules), so developers can quickly mix-and-match pieces and add custom business logic for there chain. - -The main goal here is to migrate from a basecoin with plugins for extra enhancements, to a proper app development framework, of which basecoin is one example app that can quickly be built. - -Some ideas: - -* Flexible fee/gas system (good for both public and private blockchains) -* Flexible authentication systems (with multi-sig support) -* Basic role permission system -* Abstract IBC to support other transactions from various modules (not just sendtx) - -This will be done in conjunction with some sample apps also building on this framework, where other logic is interesting and money transfers is not the central goal, like [trackomatron](https://github.com/tendermint/trackomatron) - -## Next steps - -The following are three planned steps, the order of which may change. At least one or two of these will most likely occur before any other developments. Clearly, any other feature that are urgent for cosmos can jump the list in priority, but all these pieces are part of the cosmos roadmap, especially the first two. - -### 0.8.x??? - Local client API for UI - -Beyond the CLI, we want to add more interfaces for easily building a UI on top of the basecoin client. One clear example is a local REST API, so you can easily integrate with an electron app, or a chrome app, just as if you wrote a normal Single-Page Application, but connecting to a local proxy to do full crypto-graphic proofs. - -Another **possible** development is providing an SDK, which we can compile with [go-mobile](https://github.com/golang/go/wiki/Mobile) for both Android and iOS to support secure mobile applications. Progress on this front is contingent on participation of an experienced mobile developer. - -Further, when the planned enhancements to real-time events happen in tendermint core, we should expose that via a simple subscriber/listener model in these local APIs. - -### 0.9.x??? - Proof of Stake and Voting Modules - -We should integrate developments on a [proof-of-stake module](https://github.com/tendermint/basecoin-stake) (currently a work-in-progress) and basic voting modules (currently planned) into properly supported for modules. These would provide the basis for dynamic validator set changes with bondign periods, and the basis for making governance decisions (eg. voting to change the block reward). - -At this point we would have to give full support to these plugins, and third-party devs can build on them to add more complex delegation or governance logic. - -### 0.10.x??? - Database enhancements - -Depending on developments with merkleeyes, we would like to increase the expressiveness of the storage layer while maintaining provability of all queries. We would also add a number of new primatives to the key-value store, to allow some general data-structures. - -Also, full support for historical queries and performance optimizations of the storage later. But this all depends on supporting developments of another repo, so timing here is unclear. Here are some example ideas: - -Merkle proofs: - -* **Proof of key-value**: only current proof -* **Proof of missing key**: prove there is no data for that key -* **Proof of range**: one proof for all key-values in a range of keys -* **Proof of highest/lowest in range**: just get one key, for example, prove validator hash with highest height <= H - -Data structures: - -* **Queues**: provable push-pop operations, split over multiple keys, so it can scale to 1000s of entries without deserializing them all every time. -* **Priority Queues**: as above, but ordered by priority instead of FIFO. -* **Secondary Indexes**: add support for secondary indexes with proofs. So, I can not only prove my balance, but for example, the list of all accouns with a balance of > 1000000 atoms. These indexes would have to be created by the application and stored extra in the database, but if you have a common query that you want proofs/trust, it can be very useful. diff --git a/_attic/benchmarks/app_test.go b/_attic/benchmarks/app_test.go deleted file mode 100644 index dc9e544743..0000000000 --- a/_attic/benchmarks/app_test.go +++ /dev/null @@ -1,194 +0,0 @@ -package app - -import ( - "fmt" - "io/ioutil" - "testing" - - wire "github.com/tendermint/go-wire" - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - sdkapp "github.com/cosmos/cosmos-sdk/app" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/base" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/modules/fee" - "github.com/cosmos/cosmos-sdk/modules/nonce" - "github.com/cosmos/cosmos-sdk/modules/roles" - "github.com/cosmos/cosmos-sdk/stack" -) - -type BenchApp struct { - App *sdkapp.BaseApp - Accounts []*coin.AccountWithKey - ChainID string -} - -// DefaultHandler - placeholder to just handle sendtx -func DefaultHandler(feeDenom string) sdk.Handler { - // use the default stack - c := coin.NewHandler() - r := roles.NewHandler() - d := stack.NewDispatcher( - c, - stack.WrapHandler(r), - ) - return stack.New( - base.Logger{}, - stack.Recovery{}, - auth.Signatures{}, - base.Chain{}, - nonce.ReplayCheck{}, - roles.NewMiddleware(), - fee.NewSimpleFeeMiddleware(coin.Coin{feeDenom, 0}, fee.Bank), - ).Use(d) -} - -func NewBenchApp(h sdk.Handler, chainID string, n int, - persist bool) BenchApp { - - logger := log.NewNopLogger() - // logger := log.NewFilter(log.NewTMLogger(os.Stdout), log.AllowError()) - // logger = log.NewTracingLogger(logger) - - dbDir, cache := "", 0 - if persist { - dbDir, _ = ioutil.TempDir("", "bc-app-benchmark") - cache = 500 - } - - store, err := sdkapp.NewStoreApp("bench", dbDir, cache, logger) - if err != nil { - panic(err) - } - app := sdkapp.NewBaseApp(store, h, nil) - - err = app.InitState("base", "chain_id", chainID) - if err != nil { - panic("cannot set chain") - } - - // make keys - money := coin.Coins{{"mycoin", 1234567890}} - accts := make([]*coin.AccountWithKey, n) - for i := 0; i < n; i++ { - accts[i] = coin.NewAccountWithKey(money) - err = app.InitState("coin", "account", accts[i].MakeOption()) - if err != nil { - panic("can't set account") - } - } - - return BenchApp{ - App: app, - Accounts: accts, - ChainID: chainID, - } -} - -// make a random tx... -func (b BenchApp) makeTx(useFee bool) []byte { - n := len(b.Accounts) - sender := b.Accounts[cmn.RandInt()%n] - recipient := b.Accounts[cmn.RandInt()%n] - amount := coin.Coins{{"mycoin", 123}} - tx := coin.NewSendOneTx(sender.Actor(), recipient.Actor(), amount) - if useFee { - toll := coin.Coin{"mycoin", 2} - tx = fee.NewFee(tx, toll, sender.Actor()) - } - sequence := sender.NextSequence() - tx = nonce.NewTx(sequence, []sdk.Actor{sender.Actor()}, tx) - tx = base.NewChainTx(b.ChainID, 0, tx) - stx := auth.NewMulti(tx) - auth.Sign(stx, sender.Key) - res := wire.BinaryBytes(stx.Wrap()) - return res -} - -func BenchmarkMakeTx(b *testing.B) { - h := DefaultHandler("mycoin") - app := NewBenchApp(h, "bench-chain", 10, false) - b.ResetTimer() - for i := 1; i <= b.N; i++ { - txBytes := app.makeTx(true) - if len(txBytes) < 2 { - panic("cannot commit") - } - } -} - -func benchmarkTransfers(b *testing.B, app BenchApp, blockSize int, useFee bool) { - // prepare txs - txs := make([][]byte, b.N) - for i := 1; i <= b.N; i++ { - txBytes := app.makeTx(useFee) - if len(txBytes) < 2 { - panic("cannot make bytes") - } - txs[i-1] = txBytes - } - - b.ResetTimer() - - for i := 1; i <= b.N; i++ { - res := app.App.DeliverTx(txs[i-1]) - if res.IsErr() { - panic(res.Error()) - } - if i%blockSize == 0 { - res := app.App.Commit() - if res.IsErr() { - panic("cannot commit") - } - } - } -} - -func BenchmarkSimpleTransfer(b *testing.B) { - benchmarks := []struct { - accounts int - blockSize int - useFee bool - toDisk bool - }{ - {100, 10, false, false}, - {100, 10, true, false}, - {100, 200, false, false}, - {100, 200, true, false}, - {10000, 10, false, false}, - {10000, 10, true, false}, - {10000, 200, false, false}, - {10000, 200, true, false}, - {100, 10, false, true}, - {100, 10, true, true}, - {100, 200, false, true}, - {100, 200, true, true}, - {10000, 10, false, true}, - {10000, 10, true, true}, - {10000, 200, false, true}, - {10000, 200, true, true}, - } - - for _, bb := range benchmarks { - prefix := fmt.Sprintf("%d-%d", bb.accounts, bb.blockSize) - if bb.useFee { - prefix += "-fee" - } else { - prefix += "-nofee" - } - if bb.toDisk { - prefix += "-persist" - } else { - prefix += "-memdb" - } - - h := DefaultHandler("mycoin") - app := NewBenchApp(h, "bench-chain", bb.accounts, bb.toDisk) - b.Run(prefix, func(sub *testing.B) { - benchmarkTransfers(sub, app, bb.blockSize, bb.useFee) - }) - } -} diff --git a/_attic/benchmarks/bonsai-speed.txt b/_attic/benchmarks/bonsai-speed.txt deleted file mode 100644 index ec4bae354b..0000000000 --- a/_attic/benchmarks/bonsai-speed.txt +++ /dev/null @@ -1,19 +0,0 @@ -BenchmarkMakeTx-4 2000 603153 ns/op -BenchmarkSimpleTransfer/100-10-nofee-memdb-4 5000 313154 ns/op -BenchmarkSimpleTransfer/100-10-fee-memdb-4 5000 366534 ns/op -BenchmarkSimpleTransfer/100-200-nofee-memdb-4 5000 296381 ns/op -BenchmarkSimpleTransfer/100-200-fee-memdb-4 5000 350973 ns/op -BenchmarkSimpleTransfer/10000-10-nofee-memdb-4 5000 351425 ns/op -BenchmarkSimpleTransfer/10000-10-fee-memdb-4 3000 410855 ns/op -BenchmarkSimpleTransfer/10000-200-nofee-memdb-4 5000 344839 ns/op -BenchmarkSimpleTransfer/10000-200-fee-memdb-4 5000 394080 ns/op -BenchmarkSimpleTransfer/100-10-nofee-persist-4 3000 433890 ns/op -BenchmarkSimpleTransfer/100-10-fee-persist-4 3000 496133 ns/op -BenchmarkSimpleTransfer/100-200-nofee-persist-4 5000 310174 ns/op -BenchmarkSimpleTransfer/100-200-fee-persist-4 5000 366868 ns/op -BenchmarkSimpleTransfer/10000-10-nofee-persist-4 2000 815755 ns/op -BenchmarkSimpleTransfer/10000-10-fee-persist-4 2000 874532 ns/op -BenchmarkSimpleTransfer/10000-200-nofee-persist-4 5000 567349 ns/op -BenchmarkSimpleTransfer/10000-200-fee-persist-4 5000 621833 ns/op -PASS -ok github.com/tendermint/basecoin/benchmarks 93.047s diff --git a/_attic/benchmarks/cleanup-speed.txt b/_attic/benchmarks/cleanup-speed.txt deleted file mode 100644 index 7bd397bd90..0000000000 --- a/_attic/benchmarks/cleanup-speed.txt +++ /dev/null @@ -1,19 +0,0 @@ -BenchmarkMakeTx-4 2000 648379 ns/op -BenchmarkSimpleTransfer/100-10-nofee-memdb-4 5000 356487 ns/op -BenchmarkSimpleTransfer/100-10-fee-memdb-4 5000 413435 ns/op -BenchmarkSimpleTransfer/100-200-nofee-memdb-4 5000 321859 ns/op -BenchmarkSimpleTransfer/100-200-fee-memdb-4 5000 393578 ns/op -BenchmarkSimpleTransfer/10000-10-nofee-memdb-4 5000 379129 ns/op -BenchmarkSimpleTransfer/10000-10-fee-memdb-4 3000 480334 ns/op -BenchmarkSimpleTransfer/10000-200-nofee-memdb-4 5000 384398 ns/op -BenchmarkSimpleTransfer/10000-200-fee-memdb-4 3000 443481 ns/op -BenchmarkSimpleTransfer/100-10-nofee-persist-4 3000 498460 ns/op -BenchmarkSimpleTransfer/100-10-fee-persist-4 3000 559034 ns/op -BenchmarkSimpleTransfer/100-200-nofee-persist-4 5000 314090 ns/op -BenchmarkSimpleTransfer/100-200-fee-persist-4 5000 397457 ns/op -BenchmarkSimpleTransfer/10000-10-nofee-persist-4 2000 845872 ns/op -BenchmarkSimpleTransfer/10000-10-fee-persist-4 2000 929205 ns/op -BenchmarkSimpleTransfer/10000-200-nofee-persist-4 5000 596601 ns/op -BenchmarkSimpleTransfer/10000-200-fee-persist-4 5000 667093 ns/op -PASS -ok github.com/tendermint/basecoin/benchmarks 97.097s diff --git a/_attic/benchmarks/unstable-speed.txt b/_attic/benchmarks/unstable-speed.txt deleted file mode 100644 index ce4ad2806f..0000000000 --- a/_attic/benchmarks/unstable-speed.txt +++ /dev/null @@ -1,19 +0,0 @@ -BenchmarkMakeTx-4 2000 660064 ns/op -BenchmarkSimpleTransfer/100-10-nofee-memdb-4 5000 338378 ns/op -BenchmarkSimpleTransfer/100-10-fee-memdb-4 5000 380171 ns/op -BenchmarkSimpleTransfer/100-200-nofee-memdb-4 5000 306365 ns/op -BenchmarkSimpleTransfer/100-200-fee-memdb-4 5000 359344 ns/op -BenchmarkSimpleTransfer/10000-10-nofee-memdb-4 5000 366057 ns/op -BenchmarkSimpleTransfer/10000-10-fee-memdb-4 3000 433549 ns/op -BenchmarkSimpleTransfer/10000-200-nofee-memdb-4 5000 351662 ns/op -BenchmarkSimpleTransfer/10000-200-fee-memdb-4 3000 421573 ns/op -BenchmarkSimpleTransfer/100-10-nofee-persist-4 3000 479848 ns/op -BenchmarkSimpleTransfer/100-10-fee-persist-4 3000 544164 ns/op -BenchmarkSimpleTransfer/100-200-nofee-persist-4 5000 327999 ns/op -BenchmarkSimpleTransfer/100-200-fee-persist-4 5000 385751 ns/op -BenchmarkSimpleTransfer/10000-10-nofee-persist-4 2000 852128 ns/op -BenchmarkSimpleTransfer/10000-10-fee-persist-4 2000 1055130 ns/op -BenchmarkSimpleTransfer/10000-200-nofee-persist-4 5000 642872 ns/op -BenchmarkSimpleTransfer/10000-200-fee-persist-4 3000 686337 ns/op -PASS -ok github.com/tendermint/basecoin/benchmarks 91.717s diff --git a/_attic/client/commands/auto/cmd.go b/_attic/client/commands/auto/cmd.go deleted file mode 100644 index 704ba17851..0000000000 --- a/_attic/client/commands/auto/cmd.go +++ /dev/null @@ -1,33 +0,0 @@ -package auto - -import ( - "os" - - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -// AutoCompleteCmd - command to generate bash autocompletions -var AutoCompleteCmd = &cobra.Command{ - Use: "complete", - Short: "generate bash autocompletions", - RunE: doAutoComplete, -} - -// nolint - flags -const ( - FlagOutput = "file" -) - -func init() { - AutoCompleteCmd.Flags().String(FlagOutput, "", "file to output bash autocompletion") - AutoCompleteCmd.MarkFlagFilename(FlagOutput) -} - -func doAutoComplete(cmd *cobra.Command, args []string) error { - output := viper.GetString(FlagOutput) - if output == "" { - return cmd.Root().GenBashCompletion(os.Stdout) - } - return cmd.Root().GenBashCompletionFile(output) -} diff --git a/_attic/client/commands/commits/export.go b/_attic/client/commands/commits/export.go deleted file mode 100644 index c27826fa76..0000000000 --- a/_attic/client/commands/commits/export.go +++ /dev/null @@ -1,46 +0,0 @@ -package commits - -import ( - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/tendermint/light-client/certifiers/files" - - "github.com/cosmos/cosmos-sdk/client/commands" -) - -var exportCmd = &cobra.Command{ - Use: "export ", - Short: "Export selected commits to given file", - Long: `Exports the most recent commit to a binary file. -If desired, you can select by an older height or validator hash. -`, - RunE: commands.RequireInit(exportCommit), - SilenceUsage: true, -} - -func init() { - exportCmd.Flags().Int(heightFlag, 0, "Show the commit with closest height to this") - exportCmd.Flags().String(hashFlag, "", "Show the commit matching the validator hash") - RootCmd.AddCommand(exportCmd) -} - -func exportCommit(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide a filepath to output") - } - path := args[0] - - // load the seed as specified - trust, _ := commands.GetProviders() - h := viper.GetInt(heightFlag) - hash := viper.GetString(hashFlag) - fc, err := loadCommit(trust, h, hash, "") - if err != nil { - return err - } - - // now get the output file and write it - return files.SaveFullCommitJSON(fc, path) -} diff --git a/_attic/client/commands/commits/import.go b/_attic/client/commands/commits/import.go deleted file mode 100644 index 936d25b063..0000000000 --- a/_attic/client/commands/commits/import.go +++ /dev/null @@ -1,59 +0,0 @@ -package commits - -import ( - "fmt" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/tendermint/light-client/certifiers/files" - - "github.com/cosmos/cosmos-sdk/client/commands" -) - -const ( - dryFlag = "dry-run" -) - -var importCmd = &cobra.Command{ - Use: "import ", - Short: "Imports a new commit from the given file", - Long: `Validate this file and update to the given commit if secure.`, - RunE: commands.RequireInit(importCommit), - SilenceUsage: true, -} - -func init() { - importCmd.Flags().Bool(dryFlag, false, "Test the import fully, but do not import") - RootCmd.AddCommand(importCmd) -} - -func importCommit(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide an input file") - } - - // prepare the certifier - cert, err := commands.GetCertifier() - if err != nil { - return err - } - - // parse the input file - path := args[0] - fc, err := files.LoadFullCommitJSON(path) - if err != nil { - return err - } - - // just do simple checks in --dry-run - if viper.GetBool(dryFlag) { - fmt.Printf("Testing commit %d/%X\n", fc.Height(), fc.ValidatorsHash()) - err = fc.ValidateBasic(cert.ChainID()) - } else { - fmt.Printf("Importing commit %d/%X\n", fc.Height(), fc.ValidatorsHash()) - err = cert.Update(fc) - } - return err -} diff --git a/_attic/client/commands/commits/root.go b/_attic/client/commands/commits/root.go deleted file mode 100644 index 513d86873e..0000000000 --- a/_attic/client/commands/commits/root.go +++ /dev/null @@ -1,15 +0,0 @@ -package commits - -import "github.com/spf13/cobra" - -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ - Use: "commits", - Short: "Verify commits from your local store", - Long: `Commits allows you to inspect and update the validator set for the chain. - -Since all security in a PoS system is based on having the correct validator -set, it is important to inspect the commits to maintain the security, which -is used to verify all header and merkle proofs. -`, -} diff --git a/_attic/client/commands/commits/show.go b/_attic/client/commands/commits/show.go deleted file mode 100644 index e9cc6ed28f..0000000000 --- a/_attic/client/commands/commits/show.go +++ /dev/null @@ -1,74 +0,0 @@ -package commits - -import ( - "encoding/hex" - "encoding/json" - "fmt" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/tendermint/light-client/certifiers" - "github.com/tendermint/light-client/certifiers/files" - - "github.com/cosmos/cosmos-sdk/client/commands" -) - -const ( - heightFlag = "height" - hashFlag = "hash" - fileFlag = "file" -) - -var showCmd = &cobra.Command{ - Use: "show", - Short: "Show the details of one selected commit", - Long: `Shows the most recent downloaded key by default. -If desired, you can select by height, validator hash, or a file. -`, - RunE: commands.RequireInit(showCommit), - SilenceUsage: true, -} - -func init() { - showCmd.Flags().Int(heightFlag, 0, "Show the commit with closest height to this") - showCmd.Flags().String(hashFlag, "", "Show the commit matching the validator hash") - showCmd.Flags().String(fileFlag, "", "Show the commit stored in the given file") - RootCmd.AddCommand(showCmd) -} - -func loadCommit(p certifiers.Provider, h int, hash, file string) (fc certifiers.FullCommit, err error) { - // load the commit from the proper place - if h != 0 { - fc, err = p.GetByHeight(h) - } else if hash != "" { - var vhash []byte - vhash, err = hex.DecodeString(hash) - if err == nil { - fc, err = p.GetByHash(vhash) - } - } else if file != "" { - fc, err = files.LoadFullCommitJSON(file) - } else { - // default is latest commit - fc, err = p.LatestCommit() - } - return -} - -func showCommit(cmd *cobra.Command, args []string) error { - trust, _ := commands.GetProviders() - - h := viper.GetInt(heightFlag) - hash := viper.GetString(hashFlag) - file := viper.GetString(fileFlag) - fc, err := loadCommit(trust, h, hash, file) - if err != nil { - return err - } - - // now render it! - data, err := json.MarshalIndent(fc, "", " ") - fmt.Println(string(data)) - return err -} diff --git a/_attic/client/commands/commits/update.go b/_attic/client/commands/commits/update.go deleted file mode 100644 index c42144b61b..0000000000 --- a/_attic/client/commands/commits/update.go +++ /dev/null @@ -1,52 +0,0 @@ -package commits - -import ( - "fmt" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/tendermint/light-client/certifiers" - - "github.com/cosmos/cosmos-sdk/client/commands" -) - -var updateCmd = &cobra.Command{ - Use: "update", - Short: "Update commit to current height if possible", - RunE: commands.RequireInit(updateCommit), - SilenceUsage: true, -} - -func init() { - updateCmd.Flags().Int(heightFlag, 0, "Update to this height, not latest") - RootCmd.AddCommand(updateCmd) -} - -func updateCommit(cmd *cobra.Command, args []string) error { - cert, err := commands.GetCertifier() - if err != nil { - return err - } - - h := viper.GetInt(heightFlag) - var fc certifiers.FullCommit - if h <= 0 { - // get the lastest from our source - fc, err = cert.Source.LatestCommit() - } else { - fc, err = cert.Source.GetByHeight(h) - } - if err != nil { - return err - } - - // let the certifier do it's magic to update.... - fmt.Printf("Trying to update to height: %d...\n", fc.Height()) - err = cert.Update(fc) - if err != nil { - return err - } - fmt.Println("Success!") - return nil -} diff --git a/_attic/client/commands/common.go b/_attic/client/commands/common.go deleted file mode 100644 index c51dbb469b..0000000000 --- a/_attic/client/commands/common.go +++ /dev/null @@ -1,154 +0,0 @@ -/* -Package commands contains any general setup/helpers valid for all subcommands -*/ -package commands - -import ( - "encoding/hex" - "fmt" - "strings" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/tendermint/light-client/certifiers" - "github.com/tendermint/tmlibs/cli" - cmn "github.com/tendermint/tmlibs/common" - - rpcclient "github.com/tendermint/tendermint/rpc/client" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/modules/auth" -) - -var ( - trustedProv certifiers.Provider - sourceProv certifiers.Provider -) - -const ( - ChainFlag = "chain-id" - NodeFlag = "node" -) - -// AddBasicFlags adds --node and --chain-id, which we need for everything -func AddBasicFlags(cmd *cobra.Command) { - cmd.PersistentFlags().String(ChainFlag, "", "Chain ID of tendermint node") - cmd.PersistentFlags().String(NodeFlag, "", ": to tendermint rpc interface for this chain") -} - -// GetChainID reads ChainID from the flags -func GetChainID() string { - return viper.GetString(ChainFlag) -} - -// GetNode prepares a simple rpc.Client from the flags -func GetNode() rpcclient.Client { - return client.GetNode(viper.GetString(NodeFlag)) -} - -// GetSourceProvider returns a provider pointing to an rpc handler -func GetSourceProvider() certifiers.Provider { - if sourceProv == nil { - node := viper.GetString(NodeFlag) - sourceProv = client.GetRPCProvider(node) - } - return sourceProv -} - -// GetTrustedProvider returns a reference to a local store with cache -func GetTrustedProvider() certifiers.Provider { - if trustedProv == nil { - rootDir := viper.GetString(cli.HomeFlag) - trustedProv = client.GetLocalProvider(rootDir) - } - return trustedProv -} - -// GetProviders creates a trusted (local) seed provider and a remote -// provider based on configuration. -func GetProviders() (trusted certifiers.Provider, source certifiers.Provider) { - return GetTrustedProvider(), GetSourceProvider() -} - -// GetCertifier constructs a dynamic certifier from the config info -func GetCertifier() (*certifiers.Inquiring, error) { - // load up the latest store.... - trust := GetTrustedProvider() - source := GetSourceProvider() - chainID := GetChainID() - return client.GetCertifier(chainID, trust, source) -} - -// ParseActor parses an address of form: -// [:][:] -// into a sdk.Actor. -// If app is not specified or "", then assume auth.NameSigs -func ParseActor(input string) (res sdk.Actor, err error) { - chain, app := "", auth.NameSigs - input = strings.TrimSpace(input) - spl := strings.SplitN(input, ":", 3) - - if len(spl) == 3 { - chain = spl[0] - spl = spl[1:] - } - if len(spl) == 2 { - if spl[0] != "" { - app = spl[0] - } - spl = spl[1:] - } - - addr, err := hex.DecodeString(cmn.StripHex(spl[0])) - if err != nil { - return res, errors.Errorf("Address is invalid hex: %v\n", err) - } - res = sdk.Actor{ - ChainID: chain, - App: app, - Address: addr, - } - return -} - -// ParseActors takes a comma-separated list of actors and parses them into -// a slice -func ParseActors(key string) (signers []sdk.Actor, err error) { - var act sdk.Actor - for _, k := range strings.Split(key, ",") { - act, err = ParseActor(k) - if err != nil { - return - } - signers = append(signers, act) - } - return -} - -// GetOneArg makes sure there is exactly one positional argument -func GetOneArg(args []string, argname string) (string, error) { - if len(args) == 0 { - return "", errors.Errorf("Missing required argument [%s]", argname) - } - if len(args) > 1 { - return "", errors.Errorf("Only accepts one argument [%s]", argname) - } - return args[0], nil -} - -// ParseHexFlag takes a flag name and parses the viper contents as hex -func ParseHexFlag(flag string) ([]byte, error) { - arg := viper.GetString(flag) - if arg == "" { - return nil, errors.Errorf("No such flag: %s", flag) - } - value, err := hex.DecodeString(cmn.StripHex(arg)) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("Cannot parse %s", flag)) - } - return value, nil - -} diff --git a/_attic/client/commands/init.go b/_attic/client/commands/init.go deleted file mode 100644 index 807dd1c0b2..0000000000 --- a/_attic/client/commands/init.go +++ /dev/null @@ -1,352 +0,0 @@ -package commands - -import ( - "bytes" - "encoding/hex" - "fmt" - "io" - "os" - "path/filepath" - "strings" - - "github.com/BurntSushi/toml" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - "github.com/spf13/viper" - - "github.com/tendermint/light-client/certifiers" - "github.com/tendermint/light-client/certifiers/files" - "github.com/tendermint/tmlibs/cli" - cmn "github.com/tendermint/tmlibs/common" - - "github.com/tendermint/tendermint/types" -) - -var ( - dirPerm = os.FileMode(0700) -) - -//nolint -const ( - CommitFlag = "commit" - HashFlag = "valhash" - GenesisFlag = "genesis" - FlagTrustNode = "trust-node" - - ConfigFile = "config.toml" -) - -// InitCmd will initialize the basecli store -var InitCmd = &cobra.Command{ - Use: "init", - Short: "Initialize the light client for a new chain", - RunE: runInit, -} - -var ResetCmd = &cobra.Command{ - Use: "reset_all", - Short: "DANGEROUS: Wipe out all client data, including keys", - RunE: runResetAll, -} - -func init() { - InitCmd.Flags().Bool("force-reset", false, "Wipe clean an existing client store, except for keys") - InitCmd.Flags().String(CommitFlag, "", "Commit file to import (optional)") - InitCmd.Flags().String(HashFlag, "", "Trusted validator hash (must match to accept)") - InitCmd.Flags().String(GenesisFlag, "", "Genesis file with chainid and validators (optional)") -} - -func runInit(cmd *cobra.Command, args []string) error { - root := viper.GetString(cli.HomeFlag) - if viper.GetBool("force-reset") { - resetRoot(root, true) - } - - // make sure we don't have an existing client initialized - inited, err := WasInited(root) - if err != nil { - return err - } - if inited { - return errors.Errorf("%s already is initialized, --force-reset if you really want to wipe it out", root) - } - - // clean up dir if init fails - err = doInit(cmd, root) - if err != nil { - resetRoot(root, true) - } - return err -} - -// doInit actually creates all the files, on error, we should revert it all -func doInit(cmd *cobra.Command, root string) error { - // read the genesis file if present, and populate --chain-id and --valhash - err := checkGenesis(cmd) - if err != nil { - return err - } - - err = initConfigFile(cmd) - if err != nil { - return err - } - err = initTrust() - return err -} - -func runResetAll(cmd *cobra.Command, args []string) error { - root := viper.GetString(cli.HomeFlag) - resetRoot(root, false) - return nil -} - -func resetRoot(root string, saveKeys bool) { - tmp := filepath.Join(os.TempDir(), cmn.RandStr(16)) - keys := filepath.Join(root, "keys") - if saveKeys { - os.Rename(keys, tmp) - } - os.RemoveAll(root) - if saveKeys { - os.Mkdir(root, 0700) - os.Rename(tmp, keys) - } -} - -type Runable func(cmd *cobra.Command, args []string) error - -// Any commands that require and init'ed basecoin directory -// should wrap their RunE command with RequireInit -// to make sure that the client is initialized. -// -// This cannot be called during PersistentPreRun, -// as they are called from the most specific command first, and root last, -// and the root command sets up viper, which is needed to find the home dir. -func RequireInit(run Runable) Runable { - return func(cmd *cobra.Command, args []string) error { - // otherwise, run the wrappped command - if viper.GetBool(FlagTrustNode) { - return run(cmd, args) - } - - // first check if we were Init'ed and if not, return an error - root := viper.GetString(cli.HomeFlag) - init, err := WasInited(root) - if err != nil { - return err - } - if !init { - return errors.Errorf("You must run '%s init' first", cmd.Root().Name()) - } - - // otherwise, run the wrappped command - return run(cmd, args) - } -} - -// WasInited returns true if a basecoin was previously initialized -// in this directory. Important to ensure proper behavior. -// -// Returns error if we have filesystem errors -func WasInited(root string) (bool, error) { - // make sure there is a directory here in any case - os.MkdirAll(root, dirPerm) - - // check if there is a config.toml file - cfgFile := filepath.Join(root, "config.toml") - _, err := os.Stat(cfgFile) - if os.IsNotExist(err) { - return false, nil - } - if err != nil { - return false, errors.WithStack(err) - } - - // check if there are non-empty checkpoints and validators dirs - dirs := []string{ - filepath.Join(root, files.CheckDir), - filepath.Join(root, files.ValDir), - } - // if any of these dirs is empty, then we have no data - for _, d := range dirs { - empty, err := isEmpty(d) - if err != nil { - return false, err - } - if empty { - return false, nil - } - } - - // looks like we have everything - return true, nil -} - -func checkGenesis(cmd *cobra.Command) error { - genesis := viper.GetString(GenesisFlag) - if genesis == "" { - return nil - } - - doc, err := types.GenesisDocFromFile(genesis) - if err != nil { - return err - } - - flags := cmd.Flags() - flags.Set(ChainFlag, doc.ChainID) - hash := doc.ValidatorHash() - hexHash := hex.EncodeToString(hash) - flags.Set(HashFlag, hexHash) - - return nil -} - -// isEmpty returns false if we can read files in this dir. -// if it doesn't exist, read issues, etc... return true -// -// TODO: should we handle errors otherwise? -func isEmpty(dir string) (bool, error) { - // check if we can read the directory, missing is fine, other error is not - d, err := os.Open(dir) - if os.IsNotExist(err) { - return true, nil - } - if err != nil { - return false, errors.WithStack(err) - } - defer d.Close() - - // read to see if any (at least one) files here... - files, err := d.Readdirnames(1) - if err == io.EOF { - return true, nil - } - if err != nil { - return false, errors.WithStack(err) - } - empty := len(files) == 0 - return empty, nil -} - -type Config struct { - Chain string `toml:"chain-id,omitempty"` - Node string `toml:"node,omitempty"` - Output string `toml:"output,omitempty"` - Encoding string `toml:"encoding,omitempty"` -} - -func setConfig(flags *pflag.FlagSet, f string, v *string) { - if flags.Changed(f) { - *v = viper.GetString(f) - } -} - -func initConfigFile(cmd *cobra.Command) error { - flags := cmd.Flags() - var cfg Config - - required := []string{ChainFlag, NodeFlag} - for _, f := range required { - if !flags.Changed(f) { - return errors.Errorf(`"--%s" required`, f) - } - } - - setConfig(flags, ChainFlag, &cfg.Chain) - setConfig(flags, NodeFlag, &cfg.Node) - setConfig(flags, cli.OutputFlag, &cfg.Output) - setConfig(flags, cli.EncodingFlag, &cfg.Encoding) - - out, err := os.Create(filepath.Join(viper.GetString(cli.HomeFlag), ConfigFile)) - if err != nil { - return errors.WithStack(err) - } - defer out.Close() - - // save the config file - err = toml.NewEncoder(out).Encode(cfg) - if err != nil { - return errors.WithStack(err) - } - - return nil -} - -func initTrust() (err error) { - // create a provider.... - trust, source := GetProviders() - - // load a commit file, or get data from the provider - var fc certifiers.FullCommit - commitFile := viper.GetString(CommitFlag) - if commitFile == "" { - fmt.Println("Loading validator set from tendermint rpc...") - fc, err = source.LatestCommit() - } else { - fmt.Printf("Loading validators from file %s\n", commitFile) - fc, err = files.LoadFullCommit(commitFile) - } - // can't load the commit? abort! - if err != nil { - return err - } - - // make sure it is a proper commit - err = fc.ValidateBasic(viper.GetString(ChainFlag)) - if err != nil { - return err - } - - // validate hash interactively or not - hash := viper.GetString(HashFlag) - if hash != "" { - var hashb []byte - hashb, err = hex.DecodeString(hash) - if err == nil && !bytes.Equal(hashb, fc.ValidatorsHash()) { - err = errors.Errorf("Validator hash doesn't match expectation: %X", fc.ValidatorsHash()) - } - } else { - err = validateHash(fc) - } - - if err != nil { - return err - } - - // if accepted, store commit as current state - trust.StoreCommit(fc) - return nil -} - -func validateHash(fc certifiers.FullCommit) error { - // ask the user to verify the validator hash - fmt.Println("\nImportant: if this is incorrect, all interaction with the chain will be insecure!") - fmt.Printf(" Given validator hash valid: %X\n", fc.ValidatorsHash()) - fmt.Println("Is this valid (y/n)?") - valid := askForConfirmation() - if !valid { - return errors.New("Invalid validator hash, try init with proper commit later") - } - return nil -} - -func askForConfirmation() bool { - var resp string - _, err := fmt.Scanln(&resp) - if err != nil { - fmt.Println("Please type yes or no and then press enter:") - return askForConfirmation() - } - resp = strings.ToLower(resp) - if resp == "y" || resp == "yes" { - return true - } else if resp == "n" || resp == "no" { - return false - } else { - fmt.Println("Please type yes or no and then press enter:") - return askForConfirmation() - } -} diff --git a/_attic/client/commands/keys/README.md b/_attic/client/commands/keys/README.md deleted file mode 100644 index 8bf9ca73b6..0000000000 --- a/_attic/client/commands/keys/README.md +++ /dev/null @@ -1,117 +0,0 @@ -# Keys CLI - -This is as much an example how to expose cobra/viper, as for a cli itself -(I think this code is overkill for what go-keys needs). But please look at -the commands, and give feedback and changes. - -`RootCmd` calls some initialization functions (`cobra.OnInitialize` and `RootCmd.PersistentPreRunE`) which serve to connect environmental variables and cobra flags, as well as load the config file. It also validates the flags registered on root and creates the cryptomanager, which will be used by all subcommands. - -## Help info - -``` -# keys help - -Keys allows you to manage your local keystore for tendermint. - -These keys may be in any format supported by go-crypto and can be -used by light-clients, full nodes, or any other application that -needs to sign with a private key. - -Usage: - keys [command] - -Available Commands: - get Get details of one key - list List all keys - new Create a new public/private key pair - serve Run the key manager as an http server - update Change the password for a private key - -Flags: - --keydir string Directory to store private keys (subdir of root) (default "keys") - -o, --output string Output format (text|json) (default "text") - -r, --root string root directory for config and data (default "/Users/ethan/.tlc") - -Use "keys [command] --help" for more information about a command. -``` - -## Getting the config file - -The first step is to load in root, by checking the following in order: - -* -r, --root command line flag -* TM_ROOT environmental variable -* default ($HOME/.tlc evaluated at runtime) - -Once the `rootDir` is established, the script looks for a config file named `keys.{json,toml,yaml,hcl}` in that directory and parses it. These values will provide defaults for flags of the same name. - -There is an example config file for testing out locally, which writes keys to `./.mykeys`. You can - -## Getting/Setting variables - -When we want to get the value of a user-defined variable (eg. `output`), we can call `viper.GetString("output")`, which will do the following checks, until it finds a match: - -* Is `--output` command line flag present? -* Is `TM_OUTPUT` environmental variable set? -* Was a config file found and does it have an `output` variable? -* Is there a default set on the command line flag? - -If no variable is set and there was no default, we get back "". - -This setup allows us to have powerful command line flags, but use env variables or config files (local or 12-factor style) to avoid passing these arguments every time. - -## Nesting structures - -Sometimes we don't just need key-value pairs, but actually a multi-level config file, like - -``` -[mail] -from = "no-reply@example.com" -server = "mail.example.com" -port = 567 -password = "XXXXXX" -``` - -This CLI is too simple to warant such a structure, but I think eg. tendermint could benefit from such an approach. Here are some pointers: - -* [Accessing nested keys from config files](https://github.com/spf13/viper#accessing-nested-keys) -* [Overriding nested values with envvars](https://www.netlify.com/blog/2016/09/06/creating-a-microservice-boilerplate-in-go/#nested-config-values) - the mentioned outstanding PR is already merged into master! -* Overriding nested values with cli flags? (use `--log_config.level=info` ??) - -I'd love to see an example of this fully worked out in a more complex CLI. - -## Have your cake and eat it too - -It's easy to render data different ways. Some better for viewing, some better for importing to other programs. You can just add some global (persistent) flags to control the output formatting, and everyone gets what they want. - -``` -# keys list -e hex -All keys: -betty d0789984492b1674e276b590d56b7ae077f81adc -john b77f4720b220d1411a649b6c7f1151eb6b1c226a - -# keys list -e btc -All keys: -betty 3uTF4r29CbtnzsNHZoPSYsE4BDwH -john 3ZGp2Md35iw4XVtRvZDUaAEkCUZP - -# keys list -e b64 -o json -[ - { - "name": "betty", - "address": "0HiZhEkrFnTidrWQ1Wt64Hf4Gtw=", - "pubkey": { - "type": "secp256k1", - "data": "F83WvhT0KwttSoqQqd_0_r2ztUUaQix5EXdO8AZyREoV31Og780NW59HsqTAb2O4hZ-w-j0Z-4b2IjfdqqfhVQ==" - } - }, - { - "name": "john", - "address": "t39HILIg0UEaZJtsfxFR62scImo=", - "pubkey": { - "type": "ed25519", - "data": "t1LFmbg_8UTwj-n1wkqmnTp6NfaOivokEhlYySlGYCY=" - } - } -] -``` diff --git a/_attic/client/commands/keys/delete.go b/_attic/client/commands/keys/delete.go deleted file mode 100644 index d79f7254f6..0000000000 --- a/_attic/client/commands/keys/delete.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright © 2017 Ethan Frey -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keys - -import ( - "fmt" - - "github.com/pkg/errors" - - "github.com/spf13/cobra" -) - -// deleteCmd represents the delete command -var deleteCmd = &cobra.Command{ - Use: "delete [name]", - Short: "DANGER: Delete a private key from your system", - RunE: runDeleteCmd, -} - -func runDeleteCmd(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide a name for the key") - } - name := args[0] - - oldpass, err := getPassword("DANGER - enter password to permanently delete key:") - if err != nil { - return err - } - - err = GetKeyManager().Delete(name, oldpass) - if err != nil { - return err - } - fmt.Println("Password deleted forever (uh oh!)") - return nil -} diff --git a/_attic/client/commands/keys/get.go b/_attic/client/commands/keys/get.go deleted file mode 100644 index 7310d83c19..0000000000 --- a/_attic/client/commands/keys/get.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright © 2017 Ethan Frey -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keys - -import ( - "github.com/pkg/errors" - - "github.com/spf13/cobra" -) - -// getCmd represents the get command -var getCmd = &cobra.Command{ - Use: "get [name]", - Short: "Get details of one key", - Long: `Return public details of one local key.`, - RunE: runGetCmd, -} - -func runGetCmd(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide a name for the key") - } - name := args[0] - - info, err := GetKeyManager().Get(name) - if err == nil { - printInfo(info) - } - return err -} diff --git a/_attic/client/commands/keys/list.go b/_attic/client/commands/keys/list.go deleted file mode 100644 index afdfb27845..0000000000 --- a/_attic/client/commands/keys/list.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright © 2017 Ethan Frey -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keys - -import "github.com/spf13/cobra" - -// listCmd represents the list command -var listCmd = &cobra.Command{ - Use: "list", - Short: "List all keys", - Long: `Return a list of all public keys stored by this key manager -along with their associated name and address.`, - RunE: runListCmd, -} - -func runListCmd(cmd *cobra.Command, args []string) error { - infos, err := GetKeyManager().List() - if err == nil { - printInfos(infos) - } - return err -} diff --git a/_attic/client/commands/keys/new.go b/_attic/client/commands/keys/new.go deleted file mode 100644 index f1f422a20a..0000000000 --- a/_attic/client/commands/keys/new.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright © 2017 Ethan Frey -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keys - -import ( - "fmt" - - "github.com/pkg/errors" - "github.com/tendermint/go-crypto/keys" - "github.com/tendermint/go-wire/data" - "github.com/tendermint/tmlibs/cli" - - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -const ( - flagType = "type" - flagNoBackup = "no-backup" -) - -// newCmd represents the new command -var newCmd = &cobra.Command{ - Use: "new [name]", - Short: "Create a new public/private key pair", - Long: `Add a public/private key pair to the key store. -The password muts be entered in the terminal and not -passed as a command line argument for security.`, - RunE: runNewCmd, -} - -func init() { - newCmd.Flags().StringP(flagType, "t", "ed25519", "Type of key (ed25519|secp256k1|ledger") - newCmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") -} - -func runNewCmd(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide a name for the key") - } - name := args[0] - algo := viper.GetString(flagType) - - pass, err := getCheckPassword("Enter a passphrase:", "Repeat the passphrase:") - if err != nil { - return err - } - - info, seed, err := GetKeyManager().Create(name, pass, algo) - if err == nil { - printCreate(info, seed) - } - return err -} - -type NewOutput struct { - Key keys.Info `json:"key"` - Seed string `json:"seed"` -} - -func printCreate(info keys.Info, seed string) { - switch viper.Get(cli.OutputFlag) { - case "text": - printInfo(info) - // print seed unless requested not to. - if !viper.GetBool(flagNoBackup) { - fmt.Println("**Important** write this seed phrase in a safe place.") - fmt.Println("It is the only way to recover your account if you ever forget your password.\n") - fmt.Println(seed) - } - case "json": - out := NewOutput{Key: info} - if !viper.GetBool(flagNoBackup) { - out.Seed = seed - } - json, err := data.ToJSON(out) - if err != nil { - panic(err) // really shouldn't happen... - } - fmt.Println(string(json)) - } -} diff --git a/_attic/client/commands/keys/recover.go b/_attic/client/commands/keys/recover.go deleted file mode 100644 index 52a8d08608..0000000000 --- a/_attic/client/commands/keys/recover.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright © 2017 Ethan Frey -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keys - -import ( - "github.com/pkg/errors" - - "github.com/spf13/cobra" -) - -// recoverCmd represents the recover command -var recoverCmd = &cobra.Command{ - Use: "recover [name]", - Short: "Recover a private key from a seed phrase", - Long: `Recover a private key from a seed phrase. - -I really hope you wrote this down when you created the new key. -The seed is only displayed on creation, never again. - -You can also use this to copy a key between multiple testnets, -simply by "recovering" the key in the other nets you want to copy -to. Of course, it has no coins on the other nets, just the same address.`, - RunE: runRecoverCmd, -} - -func runRecoverCmd(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide a name for the key") - } - name := args[0] - - pass, err := getPassword("Enter the new passphrase:") - if err != nil { - return err - } - - // not really a password... huh? - seed, err := getSeed("Enter your recovery seed phrase:") - if err != nil { - return err - } - - info, err := GetKeyManager().Recover(name, pass, seed) - if err != nil { - return err - } - printInfo(info) - return nil -} diff --git a/_attic/client/commands/keys/root.go b/_attic/client/commands/keys/root.go deleted file mode 100644 index 9ec37a8cee..0000000000 --- a/_attic/client/commands/keys/root.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright © 2017 Ethan Frey -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keys - -import ( - "github.com/spf13/cobra" - keys "github.com/tendermint/go-crypto/keys" -) - -var ( - manager keys.Manager -) - -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ - Use: "keys", - Short: "Key manager for tendermint clients", - Long: `Keys allows you to manage your local keystore for tendermint. - -These keys may be in any format supported by go-crypto and can be -used by light-clients, full nodes, or any other application that -needs to sign with a private key.`, -} - -func init() { - RootCmd.AddCommand(getCmd) - RootCmd.AddCommand(listCmd) - RootCmd.AddCommand(newCmd) - RootCmd.AddCommand(updateCmd) - RootCmd.AddCommand(deleteCmd) - RootCmd.AddCommand(recoverCmd) -} diff --git a/_attic/client/commands/keys/update.go b/_attic/client/commands/keys/update.go deleted file mode 100644 index f79a5cc1a9..0000000000 --- a/_attic/client/commands/keys/update.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright © 2017 Ethan Frey -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keys - -import ( - "fmt" - - "github.com/pkg/errors" - - "github.com/spf13/cobra" -) - -// updateCmd represents the update command -var updateCmd = &cobra.Command{ - Use: "update [name]", - Short: "Change the password for a private key", - RunE: runUpdateCmd, -} - -func runUpdateCmd(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide a name for the key") - } - name := args[0] - - oldpass, err := getPassword("Enter the current passphrase:") - if err != nil { - return err - } - newpass, err := getCheckPassword("Enter the new passphrase:", "Repeat the new passphrase:") - if err != nil { - return err - } - - err = GetKeyManager().Update(name, oldpass, newpass) - if err != nil { - return err - } - fmt.Println("Password successfully updated!") - return nil -} diff --git a/_attic/client/commands/keys/utils.go b/_attic/client/commands/keys/utils.go deleted file mode 100644 index 85aa434b24..0000000000 --- a/_attic/client/commands/keys/utils.go +++ /dev/null @@ -1,131 +0,0 @@ -package keys - -import ( - "bufio" - "fmt" - "os" - "strings" - - "github.com/bgentry/speakeasy" - isatty "github.com/mattn/go-isatty" - "github.com/pkg/errors" - "github.com/spf13/viper" - - keys "github.com/tendermint/go-crypto/keys" - data "github.com/tendermint/go-wire/data" - "github.com/tendermint/tmlibs/cli" - - "github.com/cosmos/cosmos-sdk/client" -) - -const MinPassLength = 10 - -// GetKeyManager initializes a key manager based on the configuration -func GetKeyManager() keys.Manager { - if manager == nil { - rootDir := viper.GetString(cli.HomeFlag) - manager = client.GetKeyManager(rootDir) - } - return manager -} - -// if we read from non-tty, we just need to init the buffer reader once, -// in case we try to read multiple passwords (eg. update) -var buf *bufio.Reader - -func inputIsTty() bool { - return isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd()) -} - -func stdinPassword() (string, error) { - if buf == nil { - buf = bufio.NewReader(os.Stdin) - } - pass, err := buf.ReadString('\n') - if err != nil { - return "", err - } - return strings.TrimSpace(pass), nil -} - -func getPassword(prompt string) (pass string, err error) { - if inputIsTty() { - pass, err = speakeasy.Ask(prompt) - } else { - pass, err = stdinPassword() - } - if err != nil { - return "", err - } - if len(pass) < MinPassLength { - return "", errors.Errorf("Password must be at least %d characters", MinPassLength) - } - return pass, nil -} - -func getSeed(prompt string) (seed string, err error) { - if inputIsTty() { - fmt.Println(prompt) - } - seed, err = stdinPassword() - seed = strings.TrimSpace(seed) - return -} - -func getCheckPassword(prompt, prompt2 string) (string, error) { - // simple read on no-tty - if !inputIsTty() { - return getPassword(prompt) - } - - // TODO: own function??? - pass, err := getPassword(prompt) - if err != nil { - return "", err - } - pass2, err := getPassword(prompt2) - if err != nil { - return "", err - } - if pass != pass2 { - return "", errors.New("Passphrases don't match") - } - return pass, nil -} - -func printInfo(info keys.Info) { - switch viper.Get(cli.OutputFlag) { - case "text": - addr, err := data.ToText(info.Address) - if err != nil { - panic(err) // really shouldn't happen... - } - sep := "\t\t" - if len(info.Name) > 7 { - sep = "\t" - } - fmt.Printf("%s%s%s\n", info.Name, sep, addr) - case "json": - json, err := data.ToJSON(info) - if err != nil { - panic(err) // really shouldn't happen... - } - fmt.Println(string(json)) - } -} - -func printInfos(infos keys.Infos) { - switch viper.Get(cli.OutputFlag) { - case "text": - fmt.Println("All keys:") - for _, i := range infos { - printInfo(i) - } - case "json": - json, err := data.ToJSON(infos) - if err != nil { - panic(err) // really shouldn't happen... - } - fmt.Println(string(json)) - } -} diff --git a/_attic/client/commands/proxy/root.go b/_attic/client/commands/proxy/root.go deleted file mode 100644 index e8170015c2..0000000000 --- a/_attic/client/commands/proxy/root.go +++ /dev/null @@ -1,66 +0,0 @@ -package proxy - -import ( - "os" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/commands" -) - -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ - Use: "proxy", - Short: "Run proxy server, verifying tendermint rpc", - Long: `This node will run a secure proxy to a tendermint rpc server. - -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 that -that it will present the same interface as a full tendermint node, -just with added trust and running locally.`, - RunE: commands.RequireInit(runProxy), - SilenceUsage: true, -} - -const ( - bindFlag = "serve" -) - -func init() { - RootCmd.Flags().String(bindFlag, ":8888", "Serve the proxy on the given port") -} - -// TODO: pass in a proper logger -var logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - -func init() { - logger = logger.With("module", "main") - logger = log.NewFilter(logger, log.AllowInfo()) -} - -func runProxy(cmd *cobra.Command, args []string) error { - // First, connect a client - node := commands.GetNode() - bind := viper.GetString(bindFlag) - cert, err := commands.GetCertifier() - if err != nil { - return err - } - sc := client.SecureClient(node, cert) - - err = client.StartProxy(sc, bind, logger) - if err != nil { - return err - } - - cmn.TrapSignal(func() { - // TODO: close up shop - }) - - return nil -} diff --git a/_attic/client/commands/query/get.go b/_attic/client/commands/query/get.go deleted file mode 100644 index 7ffc1c1f5d..0000000000 --- a/_attic/client/commands/query/get.go +++ /dev/null @@ -1,121 +0,0 @@ -package query - -import ( - "fmt" - "io" - "os" - - "github.com/pkg/errors" - "github.com/spf13/viper" - - wire "github.com/tendermint/go-wire" - "github.com/tendermint/go-wire/data" - "github.com/tendermint/iavl" - "github.com/tendermint/light-client/proofs" - - rpcclient "github.com/tendermint/tendermint/rpc/client" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/commands" -) - -// GetParsed does most of the work of the query commands, but is quite -// opinionated, so if you want more control about parsing, call Get -// directly. -// -// It will try to get the proof for the given key. If it is successful, -// it will return the height and also unserialize proof.Data into the data -// argument (so pass in a pointer to the appropriate struct) -func GetParsed(key []byte, data interface{}, height int, prove bool) (uint64, error) { - bs, h, err := Get(key, height, prove) - if err != nil { - return 0, err - } - err = wire.ReadBinaryBytes(bs, data) - if err != nil { - return 0, err - } - return h, nil -} - -// Get queries the given key and returns the value stored there and the -// height we checked at. -// -// If prove is true (and why shouldn't it be?), -// the data is fully verified before returning. If prove is false, -// we just repeat whatever any (potentially malicious) node gives us. -// Only use that if you are running the full node yourself, -// and it is localhost or you have a secure connection (not HTTP) -func Get(key []byte, height int, prove bool) (data.Bytes, uint64, error) { - if height < 0 { - return nil, 0, fmt.Errorf("Height cannot be negative") - } - - if !prove { - node := commands.GetNode() - resp, err := node.ABCIQueryWithOptions("/key", key, - rpcclient.ABCIQueryOptions{Trusted: true, Height: uint64(height)}) - return data.Bytes(resp.Value), resp.Height, err - } - val, h, _, err := GetWithProof(key, height) - return val, h, err -} - -// GetWithProof returns the values stored under a given key at the named -// height as in Get. Additionally, it will return a validated merkle -// proof for the key-value pair if it exists, and all checks pass. -func GetWithProof(key []byte, height int) (data.Bytes, uint64, iavl.KeyProof, error) { - node := commands.GetNode() - cert, err := commands.GetCertifier() - if err != nil { - return nil, 0, nil, err - } - return client.GetWithProof(key, height, node, cert) -} - -// ParseHexKey parses the key flag as hex and converts to bytes or returns error -// argname is used to customize the error message -func ParseHexKey(args []string, argname string) ([]byte, error) { - if len(args) == 0 { - return nil, errors.Errorf("Missing required argument [%s]", argname) - } - if len(args) > 1 { - return nil, errors.Errorf("Only accepts one argument [%s]", argname) - } - rawkey := args[0] - if rawkey == "" { - return nil, errors.Errorf("[%s] argument must be non-empty ", argname) - } - // with tx, we always just parse key as hex and use to lookup - return proofs.ParseHexKey(rawkey) -} - -// GetHeight reads the viper config for the query height -func GetHeight() int { - return viper.GetInt(FlagHeight) -} - -type proof struct { - Height uint64 `json:"height"` - Data interface{} `json:"data"` -} - -// FoutputProof writes the output of wrapping height and info -// in the form {"data": , "height": } -// to the provider io.Writer -func FoutputProof(w io.Writer, v interface{}, height uint64) error { - wrap := &proof{height, v} - blob, err := data.ToJSON(wrap) - if err != nil { - return err - } - _, err = fmt.Fprintf(w, "%s\n", blob) - return err -} - -// OutputProof prints the proof to stdout -// reuse this for printing proofs and we should enhance this for text/json, -// better presentation of height -func OutputProof(data interface{}, height uint64) error { - return FoutputProof(os.Stdout, data, height) -} diff --git a/_attic/client/commands/query/root.go b/_attic/client/commands/query/root.go deleted file mode 100644 index ec583dd79f..0000000000 --- a/_attic/client/commands/query/root.go +++ /dev/null @@ -1,30 +0,0 @@ -package query - -import ( - "github.com/spf13/cobra" - "github.com/cosmos/cosmos-sdk/client/commands" -) - -// nolint -const ( - FlagHeight = "height" -) - -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ - Use: "query", - Short: "Get and store merkle proofs for blockchain data", - Long: `Proofs allows you to validate data and merkle proofs. - -These proofs tie the data to a checkpoint, which is managed by "seeds". -Here we can validate these proofs and import/export them to prove specific -data to other peers as needed. -`, -} - -func init() { - RootCmd.PersistentFlags().Int(FlagHeight, 0, "Height to query (skip to use latest block)") - RootCmd.PersistentFlags().Bool(commands.FlagTrustNode, false, - "DANGEROUS: blindly trust all results from the server") - RootCmd.PersistentFlags().MarkHidden(commands.FlagTrustNode) -} diff --git a/_attic/client/commands/query/state.go b/_attic/client/commands/query/state.go deleted file mode 100644 index 4412d3e100..0000000000 --- a/_attic/client/commands/query/state.go +++ /dev/null @@ -1,36 +0,0 @@ -package query - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/commands" -) - -// KeyQueryCmd - CLI command to query a state by key with proof -var KeyQueryCmd = &cobra.Command{ - Use: "key [key]", - Short: "Handle proofs for state of abci app", - Long: `This will look up a given key in the abci app, verify the proof, -and output it as hex. - -If you want json output, use an app-specific command that knows key and value structure.`, - RunE: commands.RequireInit(keyQueryCmd), -} - -// Note: we cannot yse GetAndParseAppProof here, as we don't use go-wire to -// parse the object, but rather return the raw bytes -func keyQueryCmd(cmd *cobra.Command, args []string) error { - // parse cli - key, err := ParseHexKey(args, "key") - if err != nil { - return err - } - prove := !viper.GetBool(commands.FlagTrustNode) - - val, h, err := Get(key, GetHeight(), prove) - if err != nil { - return err - } - return OutputProof(val, h) -} diff --git a/_attic/client/commands/query/tx.go b/_attic/client/commands/query/tx.go deleted file mode 100644 index 24087b768f..0000000000 --- a/_attic/client/commands/query/tx.go +++ /dev/null @@ -1,76 +0,0 @@ -package query - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - - wire "github.com/tendermint/go-wire" - "github.com/tendermint/tendermint/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/commands" -) - -// TxQueryCmd - CLI command to query a transaction with proof -var TxQueryCmd = &cobra.Command{ - Use: "tx [txhash]", - Short: "Handle proofs of commited txs", - Long: `Proofs allows you to validate abci state with merkle proofs. - -These proofs tie the data to a checkpoint, which is managed by "seeds". -Here we can validate these proofs and import/export them to prove specific -data to other peers as needed. -`, - RunE: commands.RequireInit(txQueryCmd), -} - -func txQueryCmd(cmd *cobra.Command, args []string) error { - // parse cli - // TODO: when querying historical heights is allowed... pass it - // height := GetHeight() - bkey, err := ParseHexKey(args, "txhash") - if err != nil { - return err - } - - // get the proof -> this will be used by all prover commands - node := commands.GetNode() - prove := !viper.GetBool(commands.FlagTrustNode) - res, err := node.Tx(bkey, prove) - if err != nil { - return err - } - - // no checks if we don't get a proof - if !prove { - return showTx(res.Height, res.Tx) - } - - cert, err := commands.GetCertifier() - if err != nil { - return err - } - - check, err := client.GetCertifiedCommit(res.Height, node, cert) - if err != nil { - return err - } - err = res.Proof.Validate(check.Header.DataHash) - if err != nil { - return err - } - - // note that we return res.Proof.Data, not res.Tx, - // as res.Proof.Validate only verifies res.Proof.Data - return showTx(res.Height, res.Proof.Data) -} - -// showTx parses anything that was previously registered as interface{} -func showTx(h int, tx types.Tx) error { - var info interface{} - err := wire.ReadBinaryBytes(tx, &info) - if err != nil { - return err - } - return OutputProof(info, uint64(h)) -} diff --git a/_attic/client/commands/rpc/helpers.go b/_attic/client/commands/rpc/helpers.go deleted file mode 100644 index 7bcd074a0f..0000000000 --- a/_attic/client/commands/rpc/helpers.go +++ /dev/null @@ -1,49 +0,0 @@ -package rpc - -import ( - "fmt" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/commands" - - "github.com/tendermint/tendermint/rpc/client" -) - -var waitCmd = &cobra.Command{ - Use: "wait", - Short: "Wait until a given height, or number of new blocks", - RunE: commands.RequireInit(runWait), -} - -func init() { - waitCmd.Flags().Int(FlagHeight, -1, "wait for block height") - waitCmd.Flags().Int(FlagDelta, -1, "wait for given number of nodes") -} - -func runWait(cmd *cobra.Command, args []string) error { - c := commands.GetNode() - h := viper.GetInt(FlagHeight) - if h == -1 { - // read from delta - d := viper.GetInt(FlagDelta) - if d == -1 { - return errors.New("Must set --height or --delta") - } - status, err := c.Status() - if err != nil { - return err - } - h = status.LatestBlockHeight + d - } - - // now wait - err := client.WaitForHeight(c, h, nil) - if err != nil { - return err - } - fmt.Printf("Chain now at height %d\n", h) - return nil -} diff --git a/_attic/client/commands/rpc/insecure.go b/_attic/client/commands/rpc/insecure.go deleted file mode 100644 index 26c42e0ab8..0000000000 --- a/_attic/client/commands/rpc/insecure.go +++ /dev/null @@ -1,67 +0,0 @@ -package rpc - -import ( - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client/commands" -) - -var statusCmd = &cobra.Command{ - Use: "status", - Short: "Query the status of the node", - RunE: commands.RequireInit(runStatus), -} - -func runStatus(cmd *cobra.Command, args []string) error { - c := commands.GetNode() - status, err := c.Status() - if err != nil { - return err - } - return printResult(status) -} - -var infoCmd = &cobra.Command{ - Use: "info", - Short: "Query info on the abci app", - RunE: commands.RequireInit(runInfo), -} - -func runInfo(cmd *cobra.Command, args []string) error { - c := commands.GetNode() - info, err := c.ABCIInfo() - if err != nil { - return err - } - return printResult(info) -} - -var genesisCmd = &cobra.Command{ - Use: "genesis", - Short: "Query the genesis of the node", - RunE: commands.RequireInit(runGenesis), -} - -func runGenesis(cmd *cobra.Command, args []string) error { - c := commands.GetNode() - genesis, err := c.Genesis() - if err != nil { - return err - } - return printResult(genesis) -} - -var validatorsCmd = &cobra.Command{ - Use: "validators", - Short: "Query the validators of the node", - RunE: commands.RequireInit(runValidators), -} - -func runValidators(cmd *cobra.Command, args []string) error { - c := commands.GetNode() - validators, err := c.Validators(nil) - if err != nil { - return err - } - return printResult(validators) -} diff --git a/_attic/client/commands/rpc/root.go b/_attic/client/commands/rpc/root.go deleted file mode 100644 index 88003a43da..0000000000 --- a/_attic/client/commands/rpc/root.go +++ /dev/null @@ -1,64 +0,0 @@ -package rpc - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/tendermint/go-wire/data" - rpcclient "github.com/tendermint/tendermint/rpc/client" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/commands" -) - -const ( - FlagDelta = "delta" - FlagHeight = "height" - FlagMax = "max" - FlagMin = "min" -) - -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ - Use: "rpc", - Short: "Query the tendermint rpc, validating everything with a proof", -} - -// TODO: add support for subscribing to events???? -func init() { - RootCmd.AddCommand( - statusCmd, - infoCmd, - genesisCmd, - validatorsCmd, - blockCmd, - commitCmd, - headersCmd, - waitCmd, - ) -} - -func getSecureNode() (rpcclient.Client, error) { - // First, connect a client - c := commands.GetNode() - cert, err := commands.GetCertifier() - if err != nil { - return nil, err - } - return client.SecureClient(c, cert), nil -} - -// printResult just writes the struct to the console, returns an error if it can't -func printResult(res interface{}) error { - // TODO: handle text mode - // switch viper.Get(cli.OutputFlag) { - // case "text": - // case "json": - json, err := data.ToJSON(res) - if err != nil { - return err - } - fmt.Println(string(json)) - return nil -} diff --git a/_attic/client/commands/rpc/secure.go b/_attic/client/commands/rpc/secure.go deleted file mode 100644 index 86cf64f0c2..0000000000 --- a/_attic/client/commands/rpc/secure.go +++ /dev/null @@ -1,76 +0,0 @@ -package rpc - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/commands" -) - -func init() { - blockCmd.Flags().Int(FlagHeight, -1, "block height") - commitCmd.Flags().Int(FlagHeight, -1, "block height") - headersCmd.Flags().Int(FlagMin, -1, "minimum block height") - headersCmd.Flags().Int(FlagMax, -1, "maximum block height") -} - -var blockCmd = &cobra.Command{ - Use: "block", - Short: "Get a validated block at a given height", - RunE: commands.RequireInit(runBlock), -} - -func runBlock(cmd *cobra.Command, args []string) error { - c, err := getSecureNode() - if err != nil { - return err - } - - h := viper.GetInt(FlagHeight) - block, err := c.Block(&h) - if err != nil { - return err - } - return printResult(block) -} - -var commitCmd = &cobra.Command{ - Use: "commit", - Short: "Get the header and commit signature at a given height", - RunE: commands.RequireInit(runCommit), -} - -func runCommit(cmd *cobra.Command, args []string) error { - c, err := getSecureNode() - if err != nil { - return err - } - - h := viper.GetInt(FlagHeight) - commit, err := c.Commit(&h) - if err != nil { - return err - } - return printResult(commit) -} - -var headersCmd = &cobra.Command{ - Use: "headers", - Short: "Get all headers in the given height range", - RunE: commands.RequireInit(runHeaders), -} - -func runHeaders(cmd *cobra.Command, args []string) error { - c, err := getSecureNode() - if err != nil { - return err - } - - min := viper.GetInt(FlagMin) - max := viper.GetInt(FlagMax) - headers, err := c.BlockchainInfo(min, max) - if err != nil { - return err - } - return printResult(headers) -} diff --git a/_attic/client/commands/txs/helpers.go b/_attic/client/commands/txs/helpers.go deleted file mode 100644 index 716c430980..0000000000 --- a/_attic/client/commands/txs/helpers.go +++ /dev/null @@ -1,250 +0,0 @@ -package txs - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "strings" - - "github.com/bgentry/speakeasy" - isatty "github.com/mattn/go-isatty" - "github.com/pkg/errors" - "github.com/spf13/viper" - - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/go-crypto/keys" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/go-wire/data" - - ctypes "github.com/tendermint/tendermint/rpc/core/types" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/client/commands" - keycmd "github.com/cosmos/cosmos-sdk/client/commands/keys" - "github.com/cosmos/cosmos-sdk/modules/auth" -) - -// Validatable represents anything that can be Validated -type Validatable interface { - ValidateBasic() error -} - -// GetSigner returns the pub key that will sign the tx -// returns empty key if no name provided -func GetSigner() crypto.PubKey { - name := viper.GetString(FlagName) - manager := keycmd.GetKeyManager() - info, _ := manager.Get(name) // error -> empty pubkey - return info.PubKey -} - -// GetSignerAct returns the address of the signer of the tx -// (as we still only support single sig) -func GetSignerAct() (res sdk.Actor) { - // this could be much cooler with multisig... - signer := GetSigner() - if !signer.Empty() { - res = auth.SigPerm(signer.Address()) - } - return res -} - -// DoTx is a helper function for the lazy :) -// -// It uses only public functions and goes through the standard sequence of -// wrapping the tx with middleware layers, signing it, either preparing it, -// or posting it and displaying the result. -// -// If you want a non-standard flow, just call the various functions directly. -// eg. if you already set the middleware layers in your code, or want to -// output in another format. -func DoTx(tx interface{}) (err error) { - tx, err = Middleware.Wrap(tx) - if err != nil { - return err - } - - err = SignTx(tx) - if err != nil { - return err - } - - bres, err := PrepareOrPostTx(tx) - if err != nil { - return err - } - if bres == nil { - return nil // successful prep, nothing left to do - } - return OutputTx(bres) // print response of the post - -} - -// SignTx will validate the tx, and signs it if it is wrapping a Signable. -// Modifies tx in place, and returns an error if it should sign but couldn't -func SignTx(tx interface{}) (err error) { - // TODO: validate tx client-side - // err := tx.ValidateBasic() - // if err != nil { - // return err - // } - - // abort early if we don't want to sign - if viper.GetBool(FlagNoSign) { - return nil - } - - name := viper.GetString(FlagName) - manager := keycmd.GetKeyManager() - - if sign, ok := tx.(keys.Signable); ok { - // TODO: allow us not to sign? if so then what use? - if name == "" { - return errors.New("--name is required to sign tx") - } - err = signTx(manager, sign, name) - } - return err -} - -// PrepareOrPostTx checks the flags to decide to prepare the tx for future -// multisig, or to post it to the node. Returns error on any failure. -// If no error and the result is nil, it means it already wrote to file, -// no post, no need to do more. -func PrepareOrPostTx(tx interface{}) (*ctypes.ResultBroadcastTxCommit, error) { - wrote, err := PrepareTx(tx) - // error in prep - if err != nil { - return nil, err - } - // successfully wrote the tx! - if wrote { - return nil, nil - } - // or try to post it - return PostTx(tx) -} - -// PrepareTx checks for FlagPrepare and if set, write the tx as json -// to the specified location for later multi-sig. Returns true if it -// handled the tx (no futher work required), false if it did nothing -// (and we should post the tx) -func PrepareTx(tx interface{}) (bool, error) { - prep := viper.GetString(FlagPrepare) - if prep == "" { - return false, nil - } - - js, err := data.ToJSON(tx) - if err != nil { - return false, err - } - err = writeOutput(prep, js) - if err != nil { - return false, err - } - return true, nil -} - -// PostTx does all work once we construct a proper struct -// it validates the data, signs if needed, transforms to bytes, -// and posts to the node. -func PostTx(tx interface{}) (*ctypes.ResultBroadcastTxCommit, error) { - packet := wire.BinaryBytes(tx) - // post the bytes - node := commands.GetNode() - return node.BroadcastTxCommit(packet) -} - -// OutputTx validates if success and prints the tx result to stdout -func OutputTx(res *ctypes.ResultBroadcastTxCommit) error { - if res.CheckTx.IsErr() { - return errors.Errorf("CheckTx: (%d): %s", res.CheckTx.Code, res.CheckTx.Log) - } - if res.DeliverTx.IsErr() { - return errors.Errorf("DeliverTx: (%d): %s", res.DeliverTx.Code, res.DeliverTx.Log) - } - js, err := json.MarshalIndent(res, "", " ") - if err != nil { - return err - } - fmt.Println(string(js)) - return nil -} - -func signTx(manager keys.Manager, tx keys.Signable, name string) error { - prompt := fmt.Sprintf("Please enter passphrase for %s: ", name) - pass, err := getPassword(prompt) - if err != nil { - return err - } - return manager.Sign(name, pass, tx) -} - -// if we read from non-tty, we just need to init the buffer reader once, -// in case we try to read multiple passwords -var buf *bufio.Reader - -func inputIsTty() bool { - return isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd()) -} - -func stdinPassword() (string, error) { - if buf == nil { - buf = bufio.NewReader(os.Stdin) - } - pass, err := buf.ReadString('\n') - if err != nil { - return "", err - } - return strings.TrimSpace(pass), nil -} - -func getPassword(prompt string) (pass string, err error) { - if inputIsTty() { - pass, err = speakeasy.Ask(prompt) - } else { - pass, err = stdinPassword() - } - return -} - -func writeOutput(file string, d []byte) error { - var writer io.Writer - if file == "-" { - writer = os.Stdout - } else { - f, err := os.Create(file) - if err != nil { - return errors.WithStack(err) - } - defer f.Close() - writer = f - } - - _, err := writer.Write(d) - // this returns nil if err == nil - return errors.WithStack(err) -} - -func readInput(file string) ([]byte, error) { - var reader io.Reader - // get the input stream - if file == "" || file == "-" { - reader = os.Stdin - } else { - f, err := os.Open(file) - if err != nil { - return nil, errors.WithStack(err) - } - defer f.Close() - reader = f - } - - // and read it all! - data, err := ioutil.ReadAll(reader) - return data, errors.WithStack(err) -} diff --git a/_attic/client/commands/txs/root.go b/_attic/client/commands/txs/root.go deleted file mode 100644 index fca14f2e46..0000000000 --- a/_attic/client/commands/txs/root.go +++ /dev/null @@ -1,61 +0,0 @@ -package txs - -import ( - "encoding/json" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -// nolint -const ( - FlagName = "name" - FlagNoSign = "no-sign" - FlagIn = "in" - FlagPrepare = "prepare" -) - -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ - Use: "tx", - Short: "Post tx from json input", - RunE: doRawTx, -} - -func init() { - RootCmd.PersistentFlags().String(FlagName, "", "name to sign the tx") - RootCmd.PersistentFlags().Bool(FlagNoSign, false, "don't add a signature") - RootCmd.PersistentFlags().String(FlagPrepare, "", "file to store prepared tx") - RootCmd.Flags().String(FlagIn, "", "file with tx in json format") -} - -func doRawTx(cmd *cobra.Command, args []string) error { - raw, err := readInput(viper.GetString(FlagIn)) - if err != nil { - return err - } - - // parse the input - var tx interface{} - err = json.Unmarshal(raw, &tx) - if err != nil { - return errors.WithStack(err) - } - - // sign it - err = SignTx(tx) - if err != nil { - return err - } - - // otherwise, post it and display response - bres, err := PrepareOrPostTx(tx) - if err != nil { - return err - } - if bres == nil { - return nil // successful prep, nothing left to do - } - return OutputTx(bres) // print response of the post -} diff --git a/_attic/client/commands/txs/wrapper.go b/_attic/client/commands/txs/wrapper.go deleted file mode 100644 index fcfd994004..0000000000 --- a/_attic/client/commands/txs/wrapper.go +++ /dev/null @@ -1,43 +0,0 @@ -package txs - -import ( - "github.com/spf13/pflag" -) - -var ( - // Middleware must be set in main.go to defined the wrappers we should apply - Middleware Wrapper -) - -// Wrapper defines the information needed for each middleware package that -// wraps the data. They should read all configuration out of bounds via viper. -type Wrapper interface { - Wrap(interface{}) (interface{}, error) - Register(*pflag.FlagSet) -} - -// Wrappers combines a list of wrapper middlewares. -// The first one is the inner-most layer, eg. Fee, Nonce, Chain, Auth -type Wrappers []Wrapper - -var _ Wrapper = Wrappers{} - -// Wrap applies the wrappers to the passed in tx in order, -// aborting on the first error -func (ws Wrappers) Wrap(tx interface{}) (interface{}, error) { - var err error - for _, w := range ws { - tx, err = w.Wrap(tx) - if err != nil { - break - } - } - return tx, err -} - -// Register adds any needed flags to the command -func (ws Wrappers) Register(fs *pflag.FlagSet) { - for _, w := range ws { - w.Register(fs) - } -} diff --git a/_attic/client/commands/version.go b/_attic/client/commands/version.go deleted file mode 100644 index 172185fdfb..0000000000 --- a/_attic/client/commands/version.go +++ /dev/null @@ -1,21 +0,0 @@ -package commands - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/version" -) - -// CommitHash should be filled by linker flags -var CommitHash = "" - -// VersionCmd - command to show the application version -var VersionCmd = &cobra.Command{ - Use: "version", - Short: "Show version info", - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("%s-%s\n", version.Version, CommitHash) - }, -} diff --git a/_attic/client/common.go b/_attic/client/common.go deleted file mode 100644 index 5e79b8afbd..0000000000 --- a/_attic/client/common.go +++ /dev/null @@ -1,57 +0,0 @@ -package client - -import ( - "errors" - - "github.com/tendermint/light-client/certifiers" - certclient "github.com/tendermint/light-client/certifiers/client" - certerr "github.com/tendermint/light-client/certifiers/errors" - "github.com/tendermint/light-client/certifiers/files" - - "github.com/tendermint/light-client/proofs" - - rpcclient "github.com/tendermint/tendermint/rpc/client" -) - -// GetNode prepares a simple rpc.Client for the given endpoint -func GetNode(url string) rpcclient.Client { - return rpcclient.NewHTTP(url, "/websocket") -} - -// GetRPCProvider retuns a certifier compatible data source using -// tendermint RPC -func GetRPCProvider(url string) certifiers.Provider { - return certclient.NewHTTPProvider(url) -} - -// GetLocalProvider returns a reference to a file store of headers -// wrapped with an in-memory cache -func GetLocalProvider(dir string) certifiers.Provider { - return certifiers.NewCacheProvider( - certifiers.NewMemStoreProvider(), - files.NewProvider(dir), - ) -} - -// GetCertifier initializes an inquiring certifier given a fixed chainID -// and a local source of trusted data with at least one seed -func GetCertifier(chainID string, trust certifiers.Provider, - source certifiers.Provider) (*certifiers.Inquiring, error) { - - // this gets the most recent verified commit - fc, err := trust.LatestCommit() - if certerr.IsCommitNotFoundErr(err) { - return nil, errors.New("Please run init first to establish a root of trust") - } - if err != nil { - return nil, err - } - cert := certifiers.NewInquiring(chainID, fc, trust, source) - return cert, nil -} - -// SecureClient uses a given certifier to wrap an connection to an untrusted -// host and return a cryptographically secure rpc client. -func SecureClient(c rpcclient.Client, cert *certifiers.Inquiring) rpcclient.Client { - return proofs.Wrap(c, cert) -} diff --git a/_attic/client/errors.go b/_attic/client/errors.go deleted file mode 100644 index 9f69f5e129..0000000000 --- a/_attic/client/errors.go +++ /dev/null @@ -1,22 +0,0 @@ -package client - -import ( - "fmt" - - "github.com/pkg/errors" -) - -//-------------------------------------------- - -var errNoData = fmt.Errorf("No data returned for query") - -// IsNoDataErr checks whether an error is due to a query returning empty data -func IsNoDataErr(err error) bool { - return errors.Cause(err) == errNoData -} - -func ErrNoData() error { - return errors.WithStack(errNoData) -} - -//-------------------------------------------- diff --git a/_attic/client/errors_test.go b/_attic/client/errors_test.go deleted file mode 100644 index c561c35b7a..0000000000 --- a/_attic/client/errors_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package client - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestErrorNoData(t *testing.T) { - e1 := ErrNoData() - e1.Error() - assert.True(t, IsNoDataErr(e1)) - - e2 := errors.New("foobar") - assert.False(t, IsNoDataErr(e2)) - assert.False(t, IsNoDataErr(nil)) -} diff --git a/_attic/client/keys.go b/_attic/client/keys.go deleted file mode 100644 index 4c98c18425..0000000000 --- a/_attic/client/keys.go +++ /dev/null @@ -1,30 +0,0 @@ -package client - -/* - -import ( - "path/filepath" - - "github.com/tendermint/go-crypto/keys" - "github.com/tendermint/go-crypto/keys/cryptostore" - "github.com/tendermint/go-crypto/keys/storage/filestorage" -) - -// KeySubdir is the directory name under root where we store the keys -const KeySubdir = "keys" - -// GetKeyManager initializes a key manager based on the configuration -func GetKeyManager(rootDir string) keys.Manager { - keyDir := filepath.Join(rootDir, KeySubdir) - // TODO: smarter loading??? with language and fallback? - codec := keys.MustLoadCodec("english") - - // and construct the key manager - manager := cryptostore.New( - cryptostore.SecretBox, - filestorage.New(keyDir), - codec, - ) - return manager -} -*/ diff --git a/_attic/client/proxy.go b/_attic/client/proxy.go deleted file mode 100644 index 6518dfadbc..0000000000 --- a/_attic/client/proxy.go +++ /dev/null @@ -1,68 +0,0 @@ -package client - -import ( - "net/http" - - "github.com/tendermint/tmlibs/log" - - rpcclient "github.com/tendermint/tendermint/rpc/client" - "github.com/tendermint/tendermint/rpc/core" - rpc "github.com/tendermint/tendermint/rpc/lib/server" -) - -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) -func StartProxy(c rpcclient.Client, bind string, logger log.Logger) error { - c.Start() - r := RPCRoutes(c) - - // build the handler... - mux := http.NewServeMux() - rpc.RegisterRPCFuncs(mux, r, logger) - wm := rpc.NewWebsocketManager(r, c) - wm.SetLogger(logger) - core.SetLogger(logger) - mux.HandleFunc(wsEndpoint, wm.WebsocketHandler) - - _, err := rpc.StartHTTPServer(bind, mux, logger) - - return err -} - -// 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]*rpc.RPCFunc { - - return map[string]*rpc.RPCFunc{ - // Subscribe/unsubscribe are reserved for websocket events. - // We can just use the core tendermint impl, which uses the - // EventSwitch we registered in NewWebsocketManager above - "subscribe": rpc.NewWSRPCFunc(core.Subscribe, "event"), - "unsubscribe": rpc.NewWSRPCFunc(core.Unsubscribe, "event"), - - // info API - "status": rpc.NewRPCFunc(c.Status, ""), - "blockchain": rpc.NewRPCFunc(c.BlockchainInfo, "minHeight,maxHeight"), - "genesis": rpc.NewRPCFunc(c.Genesis, ""), - "block": rpc.NewRPCFunc(c.Block, "height"), - "commit": rpc.NewRPCFunc(c.Commit, "height"), - "tx": rpc.NewRPCFunc(c.Tx, "hash,prove"), - "validators": rpc.NewRPCFunc(c.Validators, ""), - - // broadcast API - "broadcast_tx_commit": rpc.NewRPCFunc(c.BroadcastTxCommit, "tx"), - "broadcast_tx_sync": rpc.NewRPCFunc(c.BroadcastTxSync, "tx"), - "broadcast_tx_async": rpc.NewRPCFunc(c.BroadcastTxAsync, "tx"), - - // abci API - "abci_query": rpc.NewRPCFunc(c.ABCIQuery, "path,data,prove"), - "abci_info": rpc.NewRPCFunc(c.ABCIInfo, ""), - } -} diff --git a/_attic/client/query.go b/_attic/client/query.go deleted file mode 100644 index 25b3823d6f..0000000000 --- a/_attic/client/query.go +++ /dev/null @@ -1,116 +0,0 @@ -package client - -import ( - "github.com/pkg/errors" - - "github.com/tendermint/go-wire/data" - "github.com/tendermint/iavl" - "github.com/tendermint/light-client/certifiers" - certerr "github.com/tendermint/light-client/certifiers/errors" - - "github.com/tendermint/tendermint/rpc/client" -) - -// GetWithProof will query the key on the given node, and verify it has -// a valid proof, as defined by the certifier. -// -// If there is any error in checking, returns an error. -// If val is non-empty, proof should be KeyExistsProof -// If val is empty, proof should be KeyMissingProof -func GetWithProof(key []byte, reqHeight int, node client.Client, - cert certifiers.Certifier) ( - val data.Bytes, height uint64, proof iavl.KeyProof, err error) { - - if reqHeight < 0 { - err = errors.Errorf("Height cannot be negative") - return - } - - resp, err := node.ABCIQueryWithOptions("/key", key, - client.ABCIQueryOptions{Height: uint64(reqHeight)}) - if err != nil { - return - } - - // make sure the proof is the proper height - if !resp.Code.IsOK() { - err = errors.Errorf("Query error %d: %s", resp.Code, resp.Code.String()) - return - } - if len(resp.Key) == 0 || len(resp.Proof) == 0 { - err = ErrNoData() - return - } - if resp.Height == 0 { - err = errors.New("Height returned is zero") - return - } - - // AppHash for height H is in header H+1 - var commit *certifiers.Commit - commit, err = GetCertifiedCommit(int(resp.Height+1), node, cert) - if err != nil { - return - } - - if len(resp.Value) > 0 { - // The key was found, construct a proof of existence. - var eproof *iavl.KeyExistsProof - eproof, err = iavl.ReadKeyExistsProof(resp.Proof) - if err != nil { - err = errors.Wrap(err, "Error reading proof") - return - } - - // Validate the proof against the certified header to ensure data integrity. - err = eproof.Verify(resp.Key, resp.Value, commit.Header.AppHash) - if err != nil { - err = errors.Wrap(err, "Couldn't verify proof") - return - } - val = data.Bytes(resp.Value) - proof = eproof - } else { - // The key wasn't found, construct a proof of non-existence. - var aproof *iavl.KeyAbsentProof - aproof, err = iavl.ReadKeyAbsentProof(resp.Proof) - if err != nil { - err = errors.Wrap(err, "Error reading proof") - return - } - // Validate the proof against the certified header to ensure data integrity. - err = aproof.Verify(resp.Key, nil, commit.Header.AppHash) - if err != nil { - err = errors.Wrap(err, "Couldn't verify proof") - return - } - err = ErrNoData() - proof = aproof - } - - height = resp.Height - return -} - -// GetCertifiedCommit gets the signed header for a given height -// and certifies it. Returns error if unable to get a proven header. -func GetCertifiedCommit(h int, node client.Client, - cert certifiers.Certifier) (empty *certifiers.Commit, err 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... - client.WaitForHeight(node, h, nil) - cresp, err := node.Commit(&h) - if err != nil { - return - } - commit := certifiers.CommitFromResult(cresp) - - // validate downloaded checkpoint with our request and trust store. - if commit.Height() != h { - return empty, certerr.ErrHeightMismatch(h, commit.Height()) - } - err = cert.Certify(commit) - return commit, nil -} diff --git a/_attic/client/query_test.go b/_attic/client/query_test.go deleted file mode 100644 index 0320176eb3..0000000000 --- a/_attic/client/query_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package client - -import ( - "fmt" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/tendermint/go-wire" - "github.com/tendermint/light-client/certifiers" - certclient "github.com/tendermint/light-client/certifiers/client" - "github.com/tendermint/tmlibs/log" - - nm "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/rpc/client" - rpctest "github.com/tendermint/tendermint/rpc/test" - "github.com/tendermint/tendermint/types" - - sdkapp "github.com/cosmos/cosmos-sdk/app" - "github.com/cosmos/cosmos-sdk/modules/eyes" -) - -var node *nm.Node - -func TestMain(m *testing.M) { - logger := log.TestingLogger() - store, err := sdkapp.MockStoreApp("query", logger) - if err != nil { - panic(err) - } - app := sdkapp.NewBaseApp(store, eyes.NewHandler(), nil) - - node = rpctest.StartTendermint(app) - - code := m.Run() - - node.Stop() - node.Wait() - os.Exit(code) -} - -func TestAppProofs(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - cl := client.NewLocal(node) - client.WaitForHeight(cl, 1, nil) - - k := []byte("my-key") - v := []byte("my-value") - - tx := eyes.SetTx{Key: k, Value: v}.Wrap() - btx := wire.BinaryBytes(tx) - br, err := cl.BroadcastTxCommit(btx) - require.NoError(err, "%+v", err) - require.EqualValues(0, br.CheckTx.Code, "%#v", br.CheckTx) - require.EqualValues(0, br.DeliverTx.Code) - brh := br.Height - - // This sets up our trust on the node based on some past point. - source := certclient.NewProvider(cl) - seed, err := source.GetByHeight(br.Height - 2) - require.NoError(err, "%+v", err) - cert := certifiers.NewStatic("my-chain", seed.Validators) - - client.WaitForHeight(cl, 3, nil) - latest, err := source.LatestCommit() - require.NoError(err, "%+v", err) - rootHash := latest.Header.AppHash - - // Test existing key. - var data eyes.Data - - // verify a query before the tx block has no data (and valid non-exist proof) - bs, height, proof, err := GetWithProof(k, brh-1, cl, cert) - require.NotNil(err) - require.True(IsNoDataErr(err)) - require.Nil(bs) - - // but given that block it is good - bs, height, proof, err = GetWithProof(k, brh, cl, cert) - require.NoError(err, "%+v", err) - require.NotNil(proof) - require.True(height >= uint64(latest.Header.Height)) - - // Alexis there is a bug here, somehow the above code gives us rootHash = nil - // and proof.Verify doesn't care, while proofNotExists.Verify fails. - // I am hacking this in to make it pass, but please investigate further. - rootHash = proof.Root() - - err = wire.ReadBinaryBytes(bs, &data) - require.NoError(err, "%+v", err) - assert.EqualValues(v, data.Value) - err = proof.Verify(k, bs, rootHash) - assert.NoError(err, "%+v", err) - - // Test non-existing key. - missing := []byte("my-missing-key") - bs, _, proof, err = GetWithProof(missing, 0, cl, cert) - require.True(IsNoDataErr(err)) - require.Nil(bs) - require.NotNil(proof) - err = proof.Verify(missing, nil, rootHash) - assert.NoError(err, "%+v", err) - err = proof.Verify(k, nil, rootHash) - assert.Error(err) -} - -func TestTxProofs(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - cl := client.NewLocal(node) - client.WaitForHeight(cl, 1, nil) - - tx := eyes.NewSetTx([]byte("key-a"), []byte("value-a")) - - btx := types.Tx(wire.BinaryBytes(tx)) - br, err := cl.BroadcastTxCommit(btx) - require.NoError(err, "%+v", err) - require.EqualValues(0, br.CheckTx.Code, "%#v", br.CheckTx) - require.EqualValues(0, br.DeliverTx.Code) - fmt.Printf("tx height: %d\n", br.Height) - - source := certclient.NewProvider(cl) - seed, err := source.GetByHeight(br.Height - 2) - require.NoError(err, "%+v", err) - cert := certifiers.NewStatic("my-chain", seed.Validators) - - // First let's make sure a bogus transaction hash returns a valid non-existence proof. - key := types.Tx([]byte("bogus")).Hash() - res, err := cl.Tx(key, true) - require.NotNil(err) - require.Contains(err.Error(), "not found") - - // Now let's check with the real tx hash. - key = btx.Hash() - res, err = cl.Tx(key, true) - require.NoError(err, "%+v", err) - require.NotNil(res) - err = res.Proof.Validate(key) - assert.NoError(err, "%+v", err) - - commit, err := GetCertifiedCommit(int(br.Height), cl, cert) - require.Nil(err, "%+v", err) - require.Equal(res.Proof.RootHash, commit.Header.DataHash) - -} diff --git a/_attic/client/rest/README.md b/_attic/client/rest/README.md deleted file mode 100644 index 8b8e68f22a..0000000000 --- a/_attic/client/rest/README.md +++ /dev/null @@ -1,25 +0,0 @@ -## basecoin-server - -### Proxy server -This package exposes access to key management i.e -- creating -- listing -- updating -- deleting - -The HTTP handlers can be embedded in a larger server that -does things like signing transactions and posting them to a -Tendermint chain (which requires domain-knowledge of the transaction -types and is out of scope of this generic app). - -### Key Management -We expose a couple of methods for safely managing your keychain. -If you are embedding this in a larger server, you will typically -want to mount all these paths /keys. - -HTTP Method | Route | Description ----|---|--- -POST|/|Requires a name and passphrase to create a brand new key -GET|/|Retrieves the list of all available key names, along with their public key and address -GET|/{name} | Updates the passphrase for the given key. It requires you to correctly provide the current passphrase, as well as a new one. -DELETE|/{name} | Permanently delete this private key. It requires you to correctly provide the current passphrase. diff --git a/_attic/client/rest/handlers.go b/_attic/client/rest/handlers.go deleted file mode 100644 index 330e82e2c9..0000000000 --- a/_attic/client/rest/handlers.go +++ /dev/null @@ -1,192 +0,0 @@ -package rest - -import ( - "net/http" - - "github.com/gorilla/mux" - "github.com/pkg/errors" - - keys "github.com/tendermint/go-crypto/keys" - "github.com/tendermint/tmlibs/common" - - sdk "github.com/cosmos/cosmos-sdk" - keycmd "github.com/cosmos/cosmos-sdk/client/commands/keys" -) - -type Keys struct { - algo string - manager keys.Manager -} - -func DefaultKeysManager() keys.Manager { - return keycmd.GetKeyManager() -} - -func NewDefaultKeysManager(algo string) *Keys { - return New(DefaultKeysManager(), algo) -} - -func New(manager keys.Manager, algo string) *Keys { - return &Keys{ - algo: algo, - manager: manager, - } -} - -func (k *Keys) GenerateKey(w http.ResponseWriter, r *http.Request) { - ckReq := &CreateKeyRequest{ - Algo: k.algo, - } - if err := common.ParseRequestAndValidateJSON(r, ckReq); err != nil { - common.WriteError(w, err) - return - } - - key, seed, err := k.manager.Create(ckReq.Name, ckReq.Passphrase, ckReq.Algo) - if err != nil { - common.WriteError(w, err) - return - } - - res := &CreateKeyResponse{Key: key, Seed: seed} - common.WriteSuccess(w, res) -} - -func (k *Keys) GetKey(w http.ResponseWriter, r *http.Request) { - query := mux.Vars(r) - name := query["name"] - key, err := k.manager.Get(name) - if err != nil { - common.WriteError(w, err) - return - } - common.WriteSuccess(w, &key) -} - -func (k *Keys) ListKeys(w http.ResponseWriter, r *http.Request) { - keys, err := k.manager.List() - if err != nil { - common.WriteError(w, err) - return - } - common.WriteSuccess(w, keys) -} - -var ( - errNonMatchingPathAndJSONKeyNames = errors.New("path and json key names don't match") -) - -func (k *Keys) UpdateKey(w http.ResponseWriter, r *http.Request) { - uReq := new(UpdateKeyRequest) - if err := common.ParseRequestAndValidateJSON(r, uReq); err != nil { - common.WriteError(w, err) - return - } - - query := mux.Vars(r) - name := query["name"] - if name != uReq.Name { - common.WriteError(w, errNonMatchingPathAndJSONKeyNames) - return - } - - if err := k.manager.Update(uReq.Name, uReq.OldPass, uReq.NewPass); err != nil { - common.WriteError(w, err) - return - } - - key, err := k.manager.Get(uReq.Name) - if err != nil { - common.WriteError(w, err) - return - } - common.WriteSuccess(w, &key) -} - -func (k *Keys) DeleteKey(w http.ResponseWriter, r *http.Request) { - dReq := new(DeleteKeyRequest) - if err := common.ParseRequestAndValidateJSON(r, dReq); err != nil { - common.WriteError(w, err) - return - } - - query := mux.Vars(r) - name := query["name"] - if name != dReq.Name { - common.WriteError(w, errNonMatchingPathAndJSONKeyNames) - return - } - - if err := k.manager.Delete(dReq.Name, dReq.Passphrase); err != nil { - common.WriteError(w, err) - return - } - - resp := &common.ErrorResponse{Success: true} - common.WriteSuccess(w, resp) -} - -func doPostTx(w http.ResponseWriter, r *http.Request) { - tx := new(sdk.Tx) - if err := common.ParseRequestAndValidateJSON(r, tx); err != nil { - common.WriteError(w, err) - return - } - commit, err := PostTx(*tx) - if err != nil { - common.WriteError(w, err) - return - } - - common.WriteSuccess(w, commit) -} - -func doSign(w http.ResponseWriter, r *http.Request) { - sr := new(SignRequest) - if err := common.ParseRequestAndValidateJSON(r, sr); err != nil { - common.WriteError(w, err) - return - } - - tx := sr.Tx - if err := SignTx(sr.Name, sr.Password, tx); err != nil { - common.WriteError(w, err) - return - } - common.WriteSuccess(w, tx) -} - -// mux.Router registrars - -// RegisterPostTx is a mux.Router handler that exposes POST -// method access to post a transaction to the blockchain. -func RegisterPostTx(r *mux.Router) error { - r.HandleFunc("/tx", doPostTx).Methods("POST") - return nil -} - -// RegisterAllCRUD is a convenience method to register all -// CRUD for keys to allow access by methods and routes: -// POST: /keys -// GET: /keys -// GET: /keys/{name} -// POST, PUT: /keys/{name} -// DELETE: /keys/{name} -func (k *Keys) RegisterAllCRUD(r *mux.Router) error { - r.HandleFunc("/keys", k.GenerateKey).Methods("POST") - r.HandleFunc("/keys", k.ListKeys).Methods("GET") - r.HandleFunc("/keys/{name}", k.GetKey).Methods("GET") - r.HandleFunc("/keys/{name}", k.UpdateKey).Methods("POST", "PUT") - r.HandleFunc("/keys/{name}", k.DeleteKey).Methods("DELETE") - - return nil -} - -// RegisterSignTx is a mux.Router handler that -// exposes POST method access to sign a transaction. -func RegisterSignTx(r *mux.Router) error { - r.HandleFunc("/sign", doSign).Methods("POST") - return nil -} - -// End of mux.Router registrars diff --git a/_attic/client/rest/helpers.go b/_attic/client/rest/helpers.go deleted file mode 100644 index 5085135e84..0000000000 --- a/_attic/client/rest/helpers.go +++ /dev/null @@ -1,29 +0,0 @@ -package rest - -import ( - "github.com/tendermint/go-crypto/keys" - wire "github.com/tendermint/go-wire" - - ctypes "github.com/tendermint/tendermint/rpc/core/types" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/client/commands" - keycmd "github.com/cosmos/cosmos-sdk/client/commands/keys" -) - -// PostTx is same as a tx -func PostTx(tx sdk.Tx) (*ctypes.ResultBroadcastTxCommit, error) { - packet := wire.BinaryBytes(tx) - // post the bytes - node := commands.GetNode() - return node.BroadcastTxCommit(packet) -} - -// SignTx will modify the tx in-place, adding a signature if possible -func SignTx(name, pass string, tx sdk.Tx) error { - if sign, ok := tx.Unwrap().(keys.Signable); ok { - manager := keycmd.GetKeyManager() - return manager.Sign(name, pass, sign) - } - return nil -} diff --git a/_attic/client/rest/types.go b/_attic/client/rest/types.go deleted file mode 100644 index 3ae0252ca6..0000000000 --- a/_attic/client/rest/types.go +++ /dev/null @@ -1,52 +0,0 @@ -package rest - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/tendermint/go-crypto/keys" -) - -type CreateKeyRequest struct { - Name string `json:"name,omitempty" validate:"required,min=3,printascii"` - Passphrase string `json:"password,omitempty" validate:"required,min=10"` - - // Algo is the requested algorithm to create the key - Algo string `json:"algo,omitempty"` -} - -type DeleteKeyRequest struct { - Name string `json:"name,omitempty" validate:"required,min=3,printascii"` - Passphrase string `json:"password,omitempty" validate:"required,min=10"` -} - -type UpdateKeyRequest struct { - Name string `json:"name,omitempty" validate:"required,min=3,printascii"` - OldPass string `json:"password,omitempty" validate:"required,min=10"` - NewPass string `json:"new_passphrase,omitempty" validate:"required,min=10"` -} - -type SignRequest struct { - Name string `json:"name,omitempty" validate:"required,min=3,printascii"` - Password string `json:"password,omitempty" validate:"required,min=10"` - - Tx sdk.Tx `json:"tx" validate:"required"` -} - -type CreateKeyResponse struct { - Key keys.Info `json:"key,omitempty"` - Seed string `json:"seed_phrase,omitempty"` -} - -// SendInput is the request to send an amount from one actor to another. -// Note: Not using the `validator:""` tags here because SendInput has -// many fields so it would be nice to figure out all the invalid -// inputs and report them back to the caller, in one shot. -type SendInput struct { - Fees *coin.Coin `json:"fees"` - Multi bool `json:"multi,omitempty"` - Sequence uint32 `json:"sequence"` - - To *sdk.Actor `json:"to"` - From *sdk.Actor `json:"from"` - Amount coin.Coins `json:"amount"` -} diff --git a/_attic/coins/bench_test.go b/_attic/coins/bench_test.go deleted file mode 100644 index 4fc5b8e8fd..0000000000 --- a/_attic/coins/bench_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package coin - -import ( - "testing" - - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -func makeHandler() stack.Dispatchable { - return NewHandler() -} - -func makeSimpleTx(from, to sdk.Actor, amount Coins) sdk.Tx { - in := []TxInput{{Address: from, Coins: amount}} - out := []TxOutput{{Address: to, Coins: amount}} - return NewSendTx(in, out) -} - -func BenchmarkSimpleTransfer(b *testing.B) { - h := makeHandler() - store := state.NewMemKVStore() - logger := log.NewNopLogger() - - // set the initial account - acct := NewAccountWithKey(Coins{{"mycoin", 1234567890}}) - h.InitState(logger, store, NameCoin, "account", acct.MakeOption(), nil) - sender := acct.Actor() - receiver := sdk.Actor{App: "foo", Address: cmn.RandBytes(20)} - - // now, loop... - for i := 1; i <= b.N; i++ { - ctx := stack.MockContext("foo", 100).WithPermissions(sender) - tx := makeSimpleTx(sender, receiver, Coins{{"mycoin", 2}}) - _, err := h.DeliverTx(ctx, store, tx, nil) - // never should error - if err != nil { - panic(err) - } - } - -} diff --git a/_attic/coins/commands/query.go b/_attic/coins/commands/query.go deleted file mode 100644 index 25c8b55705..0000000000 --- a/_attic/coins/commands/query.go +++ /dev/null @@ -1,44 +0,0 @@ -package commands - -import ( - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/query" - "github.com/cosmos/cosmos-sdk/x/coin" - "github.com/cosmos/cosmos-sdk/stack" -) - -// AccountQueryCmd - command to query an account -var AccountQueryCmd = &cobra.Command{ - Use: "account [address]", - Short: "Get details of an account, with proof", - RunE: commands.RequireInit(accountQueryCmd), -} - -func accountQueryCmd(cmd *cobra.Command, args []string) error { - addr, err := commands.GetOneArg(args, "address") - if err != nil { - return err - } - act, err := commands.ParseActor(addr) - if err != nil { - return err - } - act = coin.ChainAddr(act) - key := stack.PrefixedKey(coin.NameCoin, act.Bytes()) - - acc := coin.Account{} - prove := !viper.GetBool(commands.FlagTrustNode) - height, err := query.GetParsed(key, &acc, query.GetHeight(), prove) - if client.IsNoDataErr(err) { - return errors.Errorf("Account bytes are empty for address %s ", addr) - } else if err != nil { - return err - } - - return query.OutputProof(acc, height) -} diff --git a/_attic/coins/commands/tx.go b/_attic/coins/commands/tx.go deleted file mode 100644 index 452bf89eba..0000000000 --- a/_attic/coins/commands/tx.go +++ /dev/null @@ -1,105 +0,0 @@ -package commands - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/client/commands" - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - "github.com/cosmos/cosmos-sdk/x/coin" -) - -// SendTxCmd is CLI command to send tokens between basecoin accounts -var SendTxCmd = &cobra.Command{ - Use: "send", - Short: "send tokens from one account to another", - RunE: commands.RequireInit(sendTxCmd), -} - -// CreditTxCmd is CLI command to issue credit to one account -var CreditTxCmd = &cobra.Command{ - Use: "credit", - Short: "issue credit to one account", - RunE: commands.RequireInit(creditTxCmd), -} - -//nolint -const ( - FlagTo = "to" - FlagAmount = "amount" - FlagFrom = "from" -) - -func init() { - flags := SendTxCmd.Flags() - flags.String(FlagTo, "", "Destination address for the bits") - flags.String(FlagAmount, "", "Coins to send in the format ,...") - flags.String(FlagFrom, "", "Address sending coins, if not first signer") - - fs2 := CreditTxCmd.Flags() - fs2.String(FlagTo, "", "Destination address for the bits") - fs2.String(FlagAmount, "", "Coins to send in the format ,...") -} - -func sendTxCmd(cmd *cobra.Command, args []string) error { - tx, err := readSendTxFlags() - if err != nil { - return err - } - return txcmd.DoTx(tx) -} - -func readSendTxFlags() (tx sdk.Tx, err error) { - // parse to address - toAddr, err := commands.ParseActor(viper.GetString(FlagTo)) - if err != nil { - return tx, err - } - - fromAddr, err := readFromAddr() - if err != nil { - return tx, err - } - - amountCoins, err := coin.ParseCoins(viper.GetString(FlagAmount)) - if err != nil { - return tx, err - } - - // craft the inputs and outputs - tx = coin.NewSendOneTx(fromAddr, toAddr, amountCoins) - return -} - -func creditTxCmd(cmd *cobra.Command, args []string) error { - tx, err := readCreditTxFlags() - if err != nil { - return err - } - return txcmd.DoTx(tx) -} - -func readCreditTxFlags() (tx sdk.Tx, err error) { - // parse to address - toAddr, err := commands.ParseActor(viper.GetString(FlagTo)) - if err != nil { - return tx, err - } - - amount, err := coin.ParseCoins(viper.GetString(FlagAmount)) - if err != nil { - return tx, err - } - - tx = coin.CreditTx{Debitor: toAddr, Credit: amount}.Wrap() - return -} - -func readFromAddr() (sdk.Actor, error) { - from := viper.GetString(FlagFrom) - if from == "" { - return txcmd.GetSignerAct(), nil - } - return commands.ParseActor(from) -} diff --git a/_attic/coins/genesis.go b/_attic/coins/genesis.go deleted file mode 100644 index cc0163fcf0..0000000000 --- a/_attic/coins/genesis.go +++ /dev/null @@ -1,48 +0,0 @@ -package coin - -import ( - "bytes" - - "github.com/pkg/errors" - - "github.com/cosmos/cosmos-sdk/types" - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/go-wire/data" -) - -/**** code to parse accounts from genesis docs ***/ - -// GenesisAccount - genesis account parameters -type GenesisAccount struct { - Address data.Bytes `json:"address"` - // this from types.Account (don't know how to embed this properly) - PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known. - Balance types.Coins `json:"coins"` -} - -// ToAccount - GenesisAccount struct to a basecoin Account -func (g GenesisAccount) ToAccount() Account { - return Account{ - Coins: g.Balance, - } -} - -// GetAddr - Get the address of the genesis account -func (g GenesisAccount) GetAddr() ([]byte, error) { - noAddr, noPk := len(g.Address) == 0, g.PubKey.Empty() - - if noAddr { - if noPk { - return nil, errors.New("No address given") - } - return g.PubKey.Address(), nil - } - if noPk { // but is addr... - return g.Address, nil - } - // now, we have both, make sure they check out - if bytes.Equal(g.Address, g.PubKey.Address()) { - return g.Address, nil - } - return nil, errors.New("Address and pubkey don't match") -} diff --git a/_attic/coins/handler.go b/_attic/coins/handler.go deleted file mode 100644 index a51cb4320a..0000000000 --- a/_attic/coins/handler.go +++ /dev/null @@ -1,251 +0,0 @@ -package coin - -import ( - "github.com/tendermint/go-wire/data" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - // "github.com/cosmos/cosmos-sdk/x/ibc" - // "github.com/cosmos/cosmos-sdk/stack" -) - -const ( - //NameCoin - name space of the coin module - NameCoin = "coin" - // CostSend is GasAllocation per input/output - CostSend = uint64(10) - // CostCredit is GasAllocation of a credit allocation - CostCredit = uint64(20) -) - -// Handler includes an accountant -type Handler struct { - // stack.PassInitValidate -} - -// var _ stack.Dispatchable = Handler{} - -// NewHandler - new accountant handler for the coin module -func NewHandler() Handler { - return Handler{} -} - -// Name - return name space -func (Handler) Name() string { - return NameCoin -} - -// AssertDispatcher - to fulfill Dispatchable interface -func (Handler) AssertDispatcher() {} - -// CheckTx checks if there is enough money in the account -func (h Handler) CheckTx(ctx types.Context, store store.MultiStore, - tx types.Tx, _ sdk.Checker) (res sdk.CheckResult, err error) { - - err = tx.ValidateBasic() - if err != nil { - return res, err - } - - switch t := tx.Unwrap().(type) { - case SendTx: - // price based on inputs and outputs - used := uint64(len(t.Inputs) + len(t.Outputs)) - return sdk.NewCheck(used*CostSend, ""), h.checkSendTx(ctx, store, t) - case CreditTx: - // default price of 20, constant work - return sdk.NewCheck(CostCredit, ""), h.creditTx(ctx, store, t) - } - return res, errors.ErrUnknownTxType(tx.Unwrap()) -} - -// DeliverTx moves the money -func (h Handler) DeliverTx(ctx types.Context, store store.MultiStore, - tx types.Tx, cb sdk.Deliver) (res sdk.DeliverResult, err error) { - - err = tx.ValidateBasic() - if err != nil { - return res, err - } - - switch t := tx.Unwrap().(type) { - case SendTx: - return res, h.sendTx(ctx, store, t, cb) - case CreditTx: - return res, h.creditTx(ctx, store, t) - } - return res, errors.ErrUnknownTxType(tx.Unwrap()) -} - -// InitState - sets the genesis account balance -func (h Handler) InitState(l log.Logger, store store.MultiStore, - module, key, value string, cb sdk.InitStater) (log string, err error) { - if module != NameCoin { - return "", errors.ErrUnknownModule(module) - } - switch key { - case "account": - return setAccount(store, value) - case "issuer": - return setIssuer(store, value) - } - return "", errors.ErrUnknownKey(key) -} - -func (h Handler) sendTx(ctx types.Context, store store.MultiStore, - send SendTx, cb sdk.Deliver) error { - - err := checkTx(ctx, send) - if err != nil { - return err - } - - // deduct from all input accounts - senders := sdk.Actors{} - for _, in := range send.Inputs { - _, err = ChangeCoins(store, in.Address, in.Coins.Negative()) - if err != nil { - return err - } - senders = append(senders, in.Address) - } - - // add to all output accounts - for _, out := range send.Outputs { - // TODO: cleaner way, this makes sure we don't consider - // incoming ibc packets with our chain to be remote packets - if out.Address.ChainID == ctx.ChainID() { - out.Address.ChainID = "" - } - - _, err = ChangeCoins(store, out.Address, out.Coins) - if err != nil { - return err - } - // now send ibc packet if needed... - if out.Address.ChainID != "" { - // FIXME: if there are many outputs, we need to adjust inputs - // so the amounts in and out match. how? - inputs := make([]TxInput, len(send.Inputs)) - for i := range send.Inputs { - inputs[i] = send.Inputs[i] - inputs[i].Address = inputs[i].Address.WithChain(ctx.ChainID()) - } - - outTx := NewSendTx(inputs, []TxOutput{out}) - _ = outTx - /* TODO - packet := ibc.CreatePacketTx{ - DestChain: out.Address.ChainID, - Permissions: senders, - Tx: outTx, - } - ibcCtx := ctx.WithPermissions(ibc.AllowIBC(NameCoin)) - _, err := cb.DeliverTx(ibcCtx, store, packet.Wrap()) - if err != nil { - return err - } - */ - } - } - - // a-ok! - return nil -} - -func (h Handler) creditTx(ctx types.Context, store store.MultiStore, - credit CreditTx) error { - - // first check permissions!! - info, err := loadHandlerInfo(store) - if err != nil { - return err - } - if info.Issuer.Empty() || !ctx.HasPermission(info.Issuer) { - return errors.ErrUnauthorized() - } - - // load up the account - addr := ChainAddr(credit.Debitor) - acct, err := GetAccount(store, addr) - if err != nil { - return err - } - - // make and check changes - acct.Coins = acct.Coins.Plus(credit.Credit) - if !acct.Coins.IsNonnegative() { - return ErrInsufficientFunds() - } - acct.Credit = acct.Credit.Plus(credit.Credit) - if !acct.Credit.IsNonnegative() { - return ErrInsufficientCredit() - } - - err = storeAccount(store, addr.Bytes(), acct) - return err -} - -func checkTx(ctx types.Context, send SendTx) error { - // check if all inputs have permission - for _, in := range send.Inputs { - if !ctx.HasPermission(in.Address) { - return errors.ErrUnauthorized() - } - } - return nil -} - -func (Handler) checkSendTx(ctx types.Context, store store.MultiStore, send SendTx) error { - err := checkTx(ctx, send) - if err != nil { - return err - } - // now make sure there is money - for _, in := range send.Inputs { - _, err := CheckCoins(store, in.Address, in.Coins.Negative()) - if err != nil { - return err - } - } - return nil -} - -func setAccount(store store.MultiStore, value string) (log string, err error) { - var acc GenesisAccount - err = data.FromJSON([]byte(value), &acc) - if err != nil { - return "", err - } - acc.Balance.Sort() - addr, err := acc.GetAddr() - if err != nil { - return "", ErrInvalidAddress() - } - // this sets the permission for a public key signature, use that app - actor := auth.SigPerm(addr) - err = storeAccount(store, actor.Bytes(), acc.ToAccount()) - if err != nil { - return "", err - } - return "Success", nil -} - -// setIssuer sets a permission for some super-powerful account to -// mint money -func setIssuer(store store.MultiStore, value string) (log string, err error) { - var issuer sdk.Actor - err = data.FromJSON([]byte(value), &issuer) - if err != nil { - return "", err - } - err = storeIssuer(store, issuer) - if err != nil { - return "", err - } - return "Success", nil -} diff --git a/_attic/coins/handler_test.go b/_attic/coins/handler_test.go deleted file mode 100644 index c8a8eb0937..0000000000 --- a/_attic/coins/handler_test.go +++ /dev/null @@ -1,381 +0,0 @@ -package coin - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -// this makes sure that txs are rejected with invalid data or permissions -func TestHandlerValidation(t *testing.T) { - assert := assert.New(t) - - // these are all valid, except for minusCoins - addr1 := sdk.Actor{App: "coin", Address: []byte{1, 2}} - addr2 := sdk.Actor{App: "role", Address: []byte{7, 8}} - someCoins := Coins{{"atom", 123}} - doubleCoins := Coins{{"atom", 246}} - minusCoins := Coins{{"eth", -34}} - - cases := []struct { - valid bool - tx sdk.Tx - perms []sdk.Actor - }{ - // auth works with different apps - {true, - NewSendTx( - []TxInput{NewTxInput(addr1, someCoins)}, - []TxOutput{NewTxOutput(addr2, someCoins)}), - []sdk.Actor{addr1}}, - {true, - NewSendTx( - []TxInput{NewTxInput(addr2, someCoins)}, - []TxOutput{NewTxOutput(addr1, someCoins)}), - []sdk.Actor{addr1, addr2}}, - // check multi-input with both sigs - {true, - NewSendTx( - []TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, someCoins)}, - []TxOutput{NewTxOutput(addr1, doubleCoins)}), - []sdk.Actor{addr1, addr2}}, - // wrong permissions fail - {false, - NewSendTx( - []TxInput{NewTxInput(addr1, someCoins)}, - []TxOutput{NewTxOutput(addr2, someCoins)}), - []sdk.Actor{}}, - {false, - NewSendTx( - []TxInput{NewTxInput(addr1, someCoins)}, - []TxOutput{NewTxOutput(addr2, someCoins)}), - []sdk.Actor{addr2}}, - {false, - NewSendTx( - []TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, someCoins)}, - []TxOutput{NewTxOutput(addr1, doubleCoins)}), - []sdk.Actor{addr1}}, - // invalid input fails - {false, - NewSendTx( - []TxInput{NewTxInput(addr1, minusCoins)}, - []TxOutput{NewTxOutput(addr2, minusCoins)}), - []sdk.Actor{addr2}}, - } - - for i, tc := range cases { - ctx := stack.MockContext("base-chain", 100).WithPermissions(tc.perms...) - err := checkTx(ctx, tc.tx.Unwrap().(SendTx)) - if tc.valid { - assert.Nil(err, "%d: %+v", i, err) - } else { - assert.NotNil(err, "%d", i) - } - } -} - -func TestCheckDeliverSendTx(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - // some sample settings - addr1 := sdk.Actor{App: "coin", Address: []byte{1, 2}} - addr2 := sdk.Actor{App: "role", Address: []byte{7, 8}} - addr3 := sdk.Actor{App: "coin", Address: []byte{6, 5, 4, 3}} - - someCoins := Coins{{"atom", 123}} - moreCoins := Coins{{"atom", 6487}} - diffCoins := moreCoins.Minus(someCoins) - otherCoins := Coins{{"eth", 11}} - mixedCoins := someCoins.Plus(otherCoins) - - type money struct { - addr sdk.Actor - coins Coins - } - - cases := []struct { - init []money - tx sdk.Tx - perms []sdk.Actor - final []money // nil for error - cost uint64 // gas allocated (if not error) - }{ - { - []money{{addr1, moreCoins}}, - NewSendTx( - []TxInput{NewTxInput(addr1, someCoins)}, - []TxOutput{NewTxOutput(addr2, someCoins)}), - []sdk.Actor{addr1}, - []money{{addr1, diffCoins}, {addr2, someCoins}}, - 20, - }, - // simple multi-sig 2 accounts to 1 - { - []money{{addr1, mixedCoins}, {addr2, moreCoins}}, - NewSendTx( - []TxInput{NewTxInput(addr1, otherCoins), NewTxInput(addr2, someCoins)}, - []TxOutput{NewTxOutput(addr3, mixedCoins)}), - []sdk.Actor{addr1, addr2}, - []money{{addr1, someCoins}, {addr2, diffCoins}, {addr3, mixedCoins}}, - 30, - }, - // multi-sig with one account sending many times - { - []money{{addr1, moreCoins.Plus(otherCoins)}}, - NewSendTx( - []TxInput{NewTxInput(addr1, otherCoins), NewTxInput(addr1, someCoins)}, - []TxOutput{NewTxOutput(addr2, mixedCoins)}), - []sdk.Actor{addr1}, - []money{{addr1, diffCoins}, {addr2, mixedCoins}}, - 30, - }, - // invalid send (not enough money ) - { - []money{{addr1, moreCoins}, {addr2, someCoins}}, - NewSendTx( - []TxInput{NewTxInput(addr2, moreCoins)}, - []TxOutput{NewTxOutput(addr1, moreCoins)}), - []sdk.Actor{addr1, addr2}, - nil, - 0, - }, - } - - h := NewHandler() - for i, tc := range cases { - // setup the cases.... - store := state.NewMemKVStore() - for _, m := range tc.init { - acct := Account{Coins: m.coins} - err := storeAccount(store, m.addr.Bytes(), acct) - require.Nil(err, "%d: %+v", i, err) - } - - ctx := stack.MockContext("base-chain", 100).WithPermissions(tc.perms...) - - // throw-away state for checktx - cache := store.Checkpoint() - cres, err := h.CheckTx(ctx, cache, tc.tx, nil) - // real store for delivertx - _, err2 := h.DeliverTx(ctx, store, tc.tx, nil) - - if len(tc.final) > 0 { // valid - assert.Nil(err, "%d: %+v", i, err) - assert.Nil(err2, "%d: %+v", i, err2) - // make sure proper gas is set - assert.Equal(uint64(0), cres.GasPayment, "%d", i) - assert.Equal(tc.cost, cres.GasAllocated, "%d", i) - // make sure the final balances are correct - for _, f := range tc.final { - acct, err := loadAccount(store, f.addr.Bytes()) - assert.Nil(err, "%d: %+v", i, err) - assert.Equal(f.coins, acct.Coins) - } - } else { - // both check and deliver should fail - assert.NotNil(err, "%d", i) - assert.NotNil(err2, "%d", i) - } - - } -} - -func TestInitState(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - // some sample settings - pk := crypto.GenPrivKeySecp256k1().Wrap() - addr := pk.PubKey().Address() - actor := auth.SigPerm(addr) - - someCoins := Coins{{"atom", 123}} - otherCoins := Coins{{"eth", 11}} - mixedCoins := someCoins.Plus(otherCoins) - - type money struct { - addr sdk.Actor - coins Coins - } - - cases := []struct { - init []GenesisAccount - expected []money - }{ - { - []GenesisAccount{{Address: addr, Balance: mixedCoins}}, - []money{{actor, mixedCoins}}, - }, - } - - h := NewHandler() - l := log.NewNopLogger() - for i, tc := range cases { - store := state.NewMemKVStore() - key := "account" - - // set the options - for j, gen := range tc.init { - value, err := json.Marshal(gen) - require.Nil(err, "%d,%d: %+v", i, j, err) - _, err = h.InitState(l, store, NameCoin, key, string(value), nil) - require.Nil(err) - } - - // check state is proper - for _, f := range tc.expected { - acct, err := loadAccount(store, f.addr.Bytes()) - assert.Nil(err, "%d: %+v", i, err) - assert.Equal(f.coins, acct.Coins) - } - } -} - -func TestSetIssuer(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - cases := []struct { - issuer sdk.Actor - }{ - {sdk.Actor{App: "sig", Address: []byte("gwkfgk")}}, - // and set back to empty (nil is valid, but assert.Equals doesn't match) - {sdk.Actor{}}, - {sdk.Actor{ChainID: "other", App: "role", Address: []byte("vote")}}, - } - - h := NewHandler() - l := log.NewNopLogger() - for i, tc := range cases { - store := state.NewMemKVStore() - key := "issuer" - - value, err := json.Marshal(tc.issuer) - require.Nil(err, "%d,%d: %+v", i, err) - _, err = h.InitState(l, store, NameCoin, key, string(value), nil) - require.Nil(err, "%+v", err) - - // check state is proper - info, err := loadHandlerInfo(store) - assert.Nil(err, "%d: %+v", i, err) - assert.Equal(tc.issuer, info.Issuer) - } -} - -func TestDeliverCreditTx(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - // sample coins - someCoins := Coins{{"atom", 6570}} - minusCoins := Coins{{"atom", -1234}} - lessCoins := someCoins.Plus(minusCoins) - otherCoins := Coins{{"eth", 11}} - mixedCoins := someCoins.Plus(otherCoins) - - // some sample addresses - owner := sdk.Actor{App: "foo", Address: []byte("rocks")} - addr1 := sdk.Actor{App: "coin", Address: []byte{1, 2}} - key := NewAccountWithKey(someCoins) - addr2 := key.Actor() - addr3 := sdk.Actor{ChainID: "other", App: "sigs", Address: []byte{3, 9}} - - h := NewHandler() - store := state.NewMemKVStore() - ctx := stack.MockContext("secret", 77) - - // set the owner who can issue credit - js, err := json.Marshal(owner) - require.Nil(err, "%+v", err) - _, err = h.InitState(log.NewNopLogger(), store, "coin", "issuer", string(js), nil) - require.Nil(err, "%+v", err) - - // give addr2 some coins to start - _, err = h.InitState(log.NewNopLogger(), store, "coin", "account", key.MakeOption(), nil) - require.Nil(err, "%+v", err) - - cases := []struct { - tx sdk.Tx - perm sdk.Actor - check errors.CheckErr - addr sdk.Actor - expected Account - }{ - // require permission - { - tx: NewCreditTx(addr1, someCoins), - check: errors.IsUnauthorizedErr, - }, - // add credit - { - tx: NewCreditTx(addr1, someCoins), - perm: owner, - check: errors.NoErr, - addr: addr1, - expected: Account{Coins: someCoins, Credit: someCoins}, - }, - // remove some - { - tx: NewCreditTx(addr1, minusCoins), - perm: owner, - check: errors.NoErr, - addr: addr1, - expected: Account{Coins: lessCoins, Credit: lessCoins}, - }, - // can't remove more cash than there is - { - tx: NewCreditTx(addr1, otherCoins.Negative()), - perm: owner, - check: IsInsufficientFundsErr, - }, - // cumulative with initial state - { - tx: NewCreditTx(addr2, otherCoins), - perm: owner, - check: errors.NoErr, - addr: addr2, - expected: Account{Coins: mixedCoins, Credit: otherCoins}, - }, - // Even if there is cash, credit can't go negative - { - tx: NewCreditTx(addr2, minusCoins), - perm: owner, - check: IsInsufficientCreditErr, - }, - // make sure it works for other chains - { - tx: NewCreditTx(addr3, mixedCoins), - perm: owner, - check: errors.NoErr, - addr: ChainAddr(addr3), - expected: Account{Coins: mixedCoins, Credit: mixedCoins}, - }, - } - - for i, tc := range cases { - myStore := store.Checkpoint() - - myCtx := ctx.WithPermissions(tc.perm) - _, err = h.DeliverTx(myCtx, myStore, tc.tx, nil) - assert.True(tc.check(err), "%d: %+v", i, err) - - if err == nil { - store.Commit(myStore) - acct, err := GetAccount(store, tc.addr) - require.Nil(err, "%+v", err) - assert.Equal(tc.expected, acct, "%d", i) - } - } -} diff --git a/_attic/coins/helper.go b/_attic/coins/helper.go deleted file mode 100644 index 10ec3aad42..0000000000 --- a/_attic/coins/helper.go +++ /dev/null @@ -1,57 +0,0 @@ -package coin - -import ( - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/go-wire/data" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/x/auth" -) - -// AccountWithKey is a helper for tests, that includes and account -// along with the private key to access it. -type AccountWithKey struct { - Key crypto.PrivKey - Sequence uint32 - Account -} - -// NewAccountWithKey creates an account with the given balance -// and a random private key -func NewAccountWithKey(coins Coins) *AccountWithKey { - return &AccountWithKey{ - Key: crypto.GenPrivKeyEd25519().Wrap(), - Account: Account{Coins: coins}, - } -} - -// Address returns the public key address for this account -func (a *AccountWithKey) Address() []byte { - return a.Key.PubKey().Address() -} - -// Actor returns the basecoin actor associated with this account -func (a *AccountWithKey) Actor() sdk.Actor { - return auth.SigPerm(a.Key.PubKey().Address()) -} - -// NextSequence returns the next sequence to sign with -func (a *AccountWithKey) NextSequence() uint32 { - a.Sequence++ - return a.Sequence -} - -// MakeOption returns a string to use with InitState to initialize this account -// -// This is intended for use in test cases -func (a *AccountWithKey) MakeOption() string { - info := GenesisAccount{ - Address: a.Address(), - Balance: a.Coins, - } - js, err := data.ToJSON(info) - if err != nil { - panic(err) - } - return string(js) -} diff --git a/_attic/coins/ibc_test.go b/_attic/coins/ibc_test.go deleted file mode 100644 index 4b2af16cf6..0000000000 --- a/_attic/coins/ibc_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package coin - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/ibc" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" - wire "github.com/tendermint/go-wire" -) - -// TODO: other test making sure tx is output on send, balance is updated - -// This makes sure we respond properly to posttx -// TODO: set credit limit -func TestIBCPostPacket(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - otherID := "chain-2" - ourID := "dex" - start := 200 - - // create the app and our chain - app := stack.New(). - IBC(ibc.NewMiddleware()). - Dispatch( - NewHandler(), - stack.WrapHandler(ibc.NewHandler()), - ) - ourChain := ibc.NewAppChain(app, ourID) - - // set up the other chain and register it with us - otherChain := ibc.NewMockChain(otherID, 7) - registerTx := otherChain.GetRegistrationTx(start).Wrap() - _, err := ourChain.DeliverTx(registerTx) - require.Nil(err, "%+v", err) - - // set up a rich guy on this chain - wealth := Coins{{"btc", 300}, {"eth", 2000}, {"ltc", 5000}} - rich := NewAccountWithKey(wealth) - _, err = ourChain.InitState("coin", "account", rich.MakeOption()) - require.Nil(err, "%+v", err) - - // sends money to another guy on a different chain, now other chain has credit - buddy := sdk.Actor{ChainID: otherID, App: auth.NameSigs, Address: []byte("dude")} - outTx := NewSendOneTx(rich.Actor(), buddy, wealth) - _, err = ourChain.DeliverTx(outTx, rich.Actor()) - require.Nil(err, "%+v", err) - - // make sure the money moved to the other chain... - cstore := ourChain.GetStore(NameCoin) - acct, err := GetAccount(cstore, ChainAddr(buddy)) - require.Nil(err, "%+v", err) - require.Equal(wealth, acct.Coins) - - // make sure there is a proper packet for this.... - istore := ourChain.GetStore(ibc.NameIBC) - assertPacket(t, istore, otherID, wealth) - - // these are the people for testing incoming ibc from the other chain - recipient := sdk.Actor{ChainID: ourID, App: auth.NameSigs, Address: []byte("bar")} - sender := sdk.Actor{ChainID: otherID, App: auth.NameSigs, Address: []byte("foo")} - payment := Coins{{"eth", 100}, {"ltc", 300}} - coinTx := NewSendOneTx(sender, recipient, payment) - wrongCoin := NewSendOneTx(sender, recipient, Coins{{"missing", 20}}) - - p0 := ibc.NewPacket(coinTx, ourID, 0, sender) - packet0, update0 := otherChain.MakePostPacket(p0, start+5) - require.Nil(ourChain.Update(update0)) - - p1 := ibc.NewPacket(coinTx, ourID, 1, sender) - packet1, update1 := otherChain.MakePostPacket(p1, start+25) - require.Nil(ourChain.Update(update1)) - - p2 := ibc.NewPacket(wrongCoin, ourID, 2, sender) - packet2, update2 := otherChain.MakePostPacket(p2, start+50) - require.Nil(ourChain.Update(update2)) - - ibcPerm := sdk.Actors{ibc.AllowIBC(NameCoin)} - cases := []struct { - packet ibc.PostPacketTx - permissions sdk.Actors - checker errors.CheckErr - }{ - // out of order -> error - {packet1, ibcPerm, ibc.IsPacketOutOfOrderErr}, - - // all good -> execute tx - {packet0, ibcPerm, errors.NoErr}, - - // all good -> execute tx (even if earlier attempt failed) - {packet1, ibcPerm, errors.NoErr}, - - // packet 2 attempts to spend money this chain doesn't have - {packet2, ibcPerm, IsInsufficientFundsErr}, - } - - for i, tc := range cases { - _, err := ourChain.DeliverTx(tc.packet.Wrap(), tc.permissions...) - assert.True(tc.checker(err), "%d: %+v", i, err) - } - - // now, make sure the recipient got credited for the 2 successful sendtx - cstore = ourChain.GetStore(NameCoin) - // FIXME: we need to strip off this when it is local chain-id... - // think this throw and handle this better - local := recipient.WithChain("") - acct, err = GetAccount(cstore, local) - require.Nil(err, "%+v", err) - assert.Equal(payment.Plus(payment), acct.Coins) - -} - -func assertPacket(t *testing.T, istore state.SimpleDB, destID string, amount Coins) { - assert := assert.New(t) - require := require.New(t) - - iq := ibc.InputQueue(istore, destID) - require.Equal(0, iq.Size()) - - q := ibc.OutputQueue(istore, destID) - require.Equal(1, q.Size()) - d := q.Item(0) - var res ibc.Packet - err := wire.ReadBinaryBytes(d, &res) - require.Nil(err, "%+v", err) - assert.Equal(destID, res.DestChain) - assert.EqualValues(0, res.Sequence) - stx, ok := res.Tx.Unwrap().(SendTx) - if assert.True(ok) { - assert.Equal(1, len(stx.Outputs)) - assert.Equal(amount, stx.Outputs[0].Coins) - } -} diff --git a/_attic/coins/rest/handlers.go b/_attic/coins/rest/handlers.go deleted file mode 100644 index f6a9f18b32..0000000000 --- a/_attic/coins/rest/handlers.go +++ /dev/null @@ -1,166 +0,0 @@ -package rest - -import ( - "fmt" - "net/http" - "strconv" - "strings" - - "github.com/gorilla/mux" - "github.com/spf13/viper" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/query" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/base" - "github.com/cosmos/cosmos-sdk/x/coin" - "github.com/cosmos/cosmos-sdk/x/fee" - "github.com/cosmos/cosmos-sdk/x/nonce" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/tendermint/tmlibs/common" -) - -// SendInput is the request to send an amount from one actor to another. -// Note: Not using the `validator:""` tags here because SendInput has -// many fields so it would be nice to figure out all the invalid -// inputs and report them back to the caller, in one shot. -type SendInput struct { - Fees *coin.Coin `json:"fees"` - Multi bool `json:"multi,omitempty"` - Sequence uint32 `json:"sequence"` - - To *sdk.Actor `json:"to"` - From *sdk.Actor `json:"from"` - Amount coin.Coins `json:"amount"` -} - -// doQueryAccount is the HTTP handlerfunc to query an account -// It expects a query string with -func doQueryAccount(w http.ResponseWriter, r *http.Request) { - args := mux.Vars(r) - signature := args["signature"] - actor, err := commands.ParseActor(signature) - if err != nil { - common.WriteError(w, err) - return - } - - var h int - qHeight := r.URL.Query().Get("height") - if qHeight != "" { - h, err = strconv.Atoi(qHeight) - if err != nil { - common.WriteError(w, err) - return - } - } - - actor = coin.ChainAddr(actor) - key := stack.PrefixedKey(coin.NameCoin, actor.Bytes()) - account := new(coin.Account) - prove := !viper.GetBool(commands.FlagTrustNode) - height, err := query.GetParsed(key, account, h, prove) - if client.IsNoDataErr(err) { - err := fmt.Errorf("account bytes are empty for address: %q", signature) - common.WriteError(w, err) - return - } else if err != nil { - common.WriteError(w, err) - return - } - - if err := query.FoutputProof(w, account, height); err != nil { - common.WriteError(w, err) - } -} - -func PrepareSendTx(si *SendInput) sdk.Tx { - tx := coin.NewSendOneTx(*si.From, *si.To, si.Amount) - // fees are optional - if si.Fees != nil && !si.Fees.IsZero() { - tx = fee.NewFee(tx, *si.Fees, *si.From) - } - // only add the actual signer to the nonce - signers := []sdk.Actor{*si.From} - tx = nonce.NewTx(si.Sequence, signers, tx) - tx = base.NewChainTx(commands.GetChainID(), 0, tx) - - if si.Multi { - tx = auth.NewMulti(tx).Wrap() - } else { - tx = auth.NewSig(tx).Wrap() - } - return tx -} - -func doSend(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - si := new(SendInput) - if err := common.ParseRequestAndValidateJSON(r, si); err != nil { - common.WriteError(w, err) - return - } - - var errsList []string - if si.From == nil { - errsList = append(errsList, `"from" cannot be nil`) - } - if si.Sequence <= 0 { - errsList = append(errsList, `"sequence" must be > 0`) - } - if si.To == nil { - errsList = append(errsList, `"to" cannot be nil`) - } - if len(si.Amount) == 0 { - errsList = append(errsList, `"amount" cannot be empty`) - } - if len(errsList) > 0 { - code := http.StatusBadRequest - err := &common.ErrorResponse{ - Err: strings.Join(errsList, ", "), - Code: code, - } - common.WriteCode(w, err, code) - return - } - - tx := PrepareSendTx(si) - common.WriteSuccess(w, tx) -} - -// mux.Router registrars - -// RegisterCoinSend is a mux.Router handler that exposes -// POST method access on route /build/send to create a -// transaction for sending money from one account to another. -func RegisterCoinSend(r *mux.Router) error { - r.HandleFunc("/build/send", doSend).Methods("POST") - return nil -} - -// RegisterQueryAccount is a mux.Router handler that exposes GET -// method access on route /query/account/{signature} to query accounts -func RegisterQueryAccount(r *mux.Router) error { - r.HandleFunc("/query/account/{signature}", doQueryAccount).Methods("GET") - return nil -} - -// RegisterAll is a convenience function to -// register all the handlers in this package. -func RegisterAll(r *mux.Router) error { - funcs := []func(*mux.Router) error{ - RegisterCoinSend, - RegisterQueryAccount, - } - - for _, fn := range funcs { - if err := fn(r); err != nil { - return err - } - } - return nil -} - -// End of mux.Router registrars diff --git a/_attic/coins/store.go b/_attic/coins/store.go deleted file mode 100644 index fd7c8ea069..0000000000 --- a/_attic/coins/store.go +++ /dev/null @@ -1,145 +0,0 @@ -package coin - -import ( - "fmt" - - wire "github.com/tendermint/go-wire" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/store" -) - -// GetAccount - Get account from store and address -func GetAccount(store store.MultiStore, addr sdk.Actor) (Account, error) { - // if the actor is another chain, we use one address for the chain.... - addr = ChainAddr(addr) - acct, err := loadAccount(store, addr.Bytes()) - - // for empty accounts, don't return an error, but rather an empty account - if IsNoAccountErr(err) { - err = nil - } - return acct, err -} - -// CheckCoins makes sure there are funds, but doesn't change anything -func CheckCoins(store store.MultiStore, addr sdk.Actor, coins Coins) (Coins, error) { - // if the actor is another chain, we use one address for the chain.... - addr = ChainAddr(addr) - - acct, err := updateCoins(store, addr, coins) - return acct.Coins, err -} - -// ChangeCoins changes the money, returns error if it would be negative -func ChangeCoins(store store.MultiStore, addr sdk.Actor, coins Coins) (Coins, error) { - // if the actor is another chain, we use one address for the chain.... - addr = ChainAddr(addr) - - acct, err := updateCoins(store, addr, coins) - if err != nil { - return acct.Coins, err - } - - err = storeAccount(store, addr.Bytes(), acct) - return acct.Coins, err -} - -// ChainAddr collapses all addresses from another chain into one, so we can -// keep an over-all balance -// -// TODO: is there a better way to do this? -func ChainAddr(addr sdk.Actor) sdk.Actor { - if addr.ChainID == "" { - return addr - } - addr.App = "" - addr.Address = nil - return addr -} - -// updateCoins will load the account, make all checks, and return the updated account. -// -// it doesn't save anything, that is up to you to decide (Check/Change Coins) -func updateCoins(store store.MultiStore, addr sdk.Actor, coins Coins) (acct Account, err error) { - acct, err = loadAccount(store, addr.Bytes()) - // we can increase an empty account... - if IsNoAccountErr(err) && coins.IsPositive() { - err = nil - } - if err != nil { - return acct, err - } - - // check amount - final := acct.Coins.Plus(coins) - if !final.IsNonnegative() { - return acct, ErrInsufficientFunds() - } - - acct.Coins = final - return acct, nil -} - -// Account - coin account structure -type Account struct { - // Coins is how much is on the account - Coins Coins `json:"coins"` - // Credit is how much has been "fronted" to the account - // (this is usually 0 except for trusted chains) - Credit Coins `json:"credit"` -} - -func loadAccount(store store.MultiStore, key []byte) (acct Account, err error) { - // fmt.Printf("load: %X\n", key) - data := store.Get(key) - if len(data) == 0 { - return acct, ErrNoAccount() - } - err = wire.ReadBinaryBytes(data, &acct) - if err != nil { - msg := fmt.Sprintf("Error reading account %X", key) - return acct, errors.ErrInternal(msg) - } - return acct, nil -} - -func storeAccount(store store.MultiStore, key []byte, acct Account) error { - // fmt.Printf("store: %X\n", key) - bin := wire.BinaryBytes(acct) - store.Set(key, bin) - return nil // real stores can return error... -} - -// HandlerInfo - this is global info on the coin handler -type HandlerInfo struct { - Issuer sdk.Actor `json:"issuer"` -} - -// TODO: where to store these special pieces?? -var handlerKey = []byte{12, 34} - -func loadHandlerInfo(store store.KVStore) (info HandlerInfo, err error) { - data := store.Get(handlerKey) - if len(data) == 0 { - return info, nil - } - err = wire.ReadBinaryBytes(data, &info) - if err != nil { - msg := "Error reading handler info" - return info, errors.ErrInternal(msg) - } - return info, nil -} - -func storeIssuer(store store.KVStore, issuer sdk.Actor) error { - info, err := loadHandlerInfo(store) - if err != nil { - return err - } - info.Issuer = issuer - d := wire.BinaryBytes(info) - store.Set(handlerKey, d) - return nil // real stores can return error... -} diff --git a/_attic/examples/basecoin/Makefile b/_attic/examples/basecoin/Makefile deleted file mode 100644 index 78dd637e89..0000000000 --- a/_attic/examples/basecoin/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -LINKER_FLAGS:="-X github.com/cosmos/cosmos-sdk/client/commands.CommitHash=`git rev-parse --short HEAD`" - -install: - @go install -ldflags $(LINKER_FLAGS) ./cmd/... - -test: test_unit test_cli - -test_unit: - @go test `glide novendor` - -test_cli: - ./tests/cli/keys.sh - ./tests/cli/rpc.sh - ./tests/cli/init.sh - ./tests/cli/init-server.sh - ./tests/cli/basictx.sh - ./tests/cli/roles.sh - ./tests/cli/restart.sh - ./tests/cli/rest.sh - ./tests/cli/ibc.sh - -.PHONY: install test test_unit test_cli diff --git a/_attic/examples/basecoin/app/handler.go b/_attic/examples/basecoin/app/handler.go deleted file mode 100644 index 69fd171a94..0000000000 --- a/_attic/examples/basecoin/app/handler.go +++ /dev/null @@ -1,73 +0,0 @@ -// XXX Rename AppHandler to DefaultAppHandler. -// XXX Register with a sdk.BaseApp instance to create Basecoin. -// XXX Create TxParser in anotehr file. - -package app - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/store" -) - -// AppHandler has no state for now, a more complex app could store state here -type AppHandler struct{} - -func NewAppHandler() sdk.Handler { - return AppHandler{} -} - -// DeliverTx applies the tx -func (h Handler) DeliverTx(ctx sdk.Context, store store.MultiStore, - msg interface{}) (res sdk.DeliverResult, err error) { - - db := store.Get("main").(sdk.KVStore) - - // Here we switch on which implementation of tx we use, - // and then take the appropriate action. - switch tx := tx.(type) { - case SendTx: - err = tx.ValidateBasic() - if err != nil { - break - } - db.Set(tx.Key, tx.Value) - res.Data = tx.Key - case RemoveTx: - err = tx.ValidateBasic() - if err != nil { - break - } - db.Remove(tx.Key) - res.Data = tx.Key - default: - err = errors.ErrInvalidFormat(TxWrapper{}, msg) - } - - return -} - -// CheckTx verifies if it is legit and returns info on how -// to prioritize it in the mempool -func (h Handler) CheckTx(ctx sdk.Context, store store.MultiStore, - msg interface{}) (res sdk.CheckResult, err error) { - - // If we wanted to use the store, - // it would look the same (as DeliverTx) - // db := store.Get("main").(sdk.KVStore) - - // Make sure it is something valid - tx, ok := msg.(Tx) - if !ok { - return res, errors.ErrInvalidFormat(TxWrapper{}, msg) - } - err = tx.ValidateBasic() - if err != nil { - return - } - - // Now return the costs (these should have meaning in your app) - return sdk.CheckResult{ - GasAllocated: 50, - GasPayment: 10, - } -} diff --git a/_attic/examples/basecoin/cmd/basecli/LIGHT_NODE.md b/_attic/examples/basecoin/cmd/basecli/LIGHT_NODE.md deleted file mode 100644 index 002c96cdf7..0000000000 --- a/_attic/examples/basecoin/cmd/basecli/LIGHT_NODE.md +++ /dev/null @@ -1,58 +0,0 @@ -# Run your own (super) lightweight node - -In addition to providing command-line tooling that goes cryptographic verification -on all the data your receive from the node, we have implemented a proxy mode, that -allows you to run a super lightweight node. It does not follow the chain on -every block or even every header, but only as needed. But still providing the -same security as running a full non-validator node on your local machine. - -Basically, it runs as a proxy that exposes the same rpc interface as the full node -and connects to a (potentially untrusted) full node. Every response is cryptographically -verified before being passed through, returning an error if it doesn't match. - -You can expect 2 rpc calls for every query plus <= 1 query for each validator set -change. Going offline for a while allows you to verify multiple validator set changes -with one call. Cuz at 1 block/sec and 1000 tx/block, it just doesn't make sense -to run a full node just to get security - -## Setup - -Just initialize your client with the proper validator set as in the [README](README.md) - -``` -$ export BCHOME=~/.lightnode -$ basecli init --node tcp://: --chain-id -``` - -## Running - -``` -$ basecli proxy --serve tcp://localhost:7890 -... -curl localhost:7890/status -curl localhost:7890/block\?height=20 -``` - -You can even subscribe to events over websockets and they are all verified -before passing them though. Though if you want every block, you might as -well run a full (nonvalidating) node. - -## Seeds - -Every time the validator set changes, the light node verifies if it is legal, -and then creates a seed at that point. These "seeds" are verified checkpoints -that we can trace any proof back to, starting with one on `init`. - -To make sure you are based on the most recent header, you can run: - -``` -basecli seeds update -basecli seeds show -``` - -## Feedback - -This is the first release of basecli and the light-weight proxy. It is secure, but -may not be useful for your workflow. Please try it out and open github issues -for any enhancements or bugs you find. I am aiming to make this a very useful -tool by tendermint 0.11, for which I need community feedback. diff --git a/_attic/examples/basecoin/cmd/basecli/README.md b/_attic/examples/basecoin/cmd/basecli/README.md deleted file mode 100644 index 2443c92ae5..0000000000 --- a/_attic/examples/basecoin/cmd/basecli/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Basic run through of using basecli.... - -To keep things clear, let's have two shells... - -`$` is for basecoin (server), `%` is for basecli (client) - -## Set up your basecli with a new key - -``` -% export BCHOME=~/.democli -% basecli keys new demo -% basecli keys get demo -o json -``` - -And set up a few more keys for fun... - -``` -% basecli keys new buddy -% basecli keys list -% ME=$(basecli keys get demo | awk '{print $2}') -% YOU=$(basecli keys get buddy | awk '{print $2}') -``` - -## Set up a clean basecoin, initialized with your account - -``` -$ export BCHOME=~/.demoserve -$ basecoin init $ME -$ basecoin start -``` - -## Connect your basecli the first time - -``` -% basecli init --chain-id test_chain_id --node tcp://localhost:46657 -``` - -## Check your balances... - -``` -% basecli query account $ME -% basecli query account $YOU -``` - -## Send the money - -``` -% basecli tx send --name demo --amount 1000mycoin --sequence 1 --to $YOU --> copy hash to HASH -% basecli query tx $HASH -% basecli query account $YOU -``` - diff --git a/_attic/examples/basecoin/cmd/basecli/main.go b/_attic/examples/basecoin/cmd/basecli/main.go deleted file mode 100644 index 107890a75e..0000000000 --- a/_attic/examples/basecoin/cmd/basecli/main.go +++ /dev/null @@ -1,91 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - - "github.com/tendermint/tmlibs/cli" - - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/auto" - "github.com/cosmos/cosmos-sdk/client/commands/commits" - "github.com/cosmos/cosmos-sdk/client/commands/keys" - "github.com/cosmos/cosmos-sdk/client/commands/proxy" - "github.com/cosmos/cosmos-sdk/client/commands/query" - rpccmd "github.com/cosmos/cosmos-sdk/client/commands/rpc" - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - authcmd "github.com/cosmos/cosmos-sdk/modules/auth/commands" - basecmd "github.com/cosmos/cosmos-sdk/modules/base/commands" - coincmd "github.com/cosmos/cosmos-sdk/modules/coin/commands" - feecmd "github.com/cosmos/cosmos-sdk/modules/fee/commands" - ibccmd "github.com/cosmos/cosmos-sdk/modules/ibc/commands" - noncecmd "github.com/cosmos/cosmos-sdk/modules/nonce/commands" - rolecmd "github.com/cosmos/cosmos-sdk/modules/roles/commands" -) - -// BaseCli - main basecoin client command -var BaseCli = &cobra.Command{ - Use: "basecli", - Short: "Light client for Tendermint", - Long: `Basecli is a certifying light client for the basecoin abci app. - -It leverages the power of the tendermint consensus algorithm get full -cryptographic proof of all queries while only syncing a fraction of the -block headers.`, -} - -func main() { - commands.AddBasicFlags(BaseCli) - - // Prepare queries - query.RootCmd.AddCommand( - // These are default parsers, but optional in your app (you can remove key) - query.TxQueryCmd, - query.KeyQueryCmd, - coincmd.AccountQueryCmd, - noncecmd.NonceQueryCmd, - rolecmd.RoleQueryCmd, - ibccmd.IBCQueryCmd, - ) - - // set up the middleware - txcmd.Middleware = txcmd.Wrappers{ - feecmd.FeeWrapper{}, - rolecmd.RoleWrapper{}, - noncecmd.NonceWrapper{}, - basecmd.ChainWrapper{}, - authcmd.SigWrapper{}, - } - txcmd.Middleware.Register(txcmd.RootCmd.PersistentFlags()) - - // you will always want this for the base send command - txcmd.RootCmd.AddCommand( - // This is the default transaction, optional in your app - coincmd.SendTxCmd, - coincmd.CreditTxCmd, - // this enables creating roles - rolecmd.CreateRoleTxCmd, - // these are for handling ibc - ibccmd.RegisterChainTxCmd, - ibccmd.UpdateChainTxCmd, - ibccmd.PostPacketTxCmd, - ) - - // Set up the various commands to use - BaseCli.AddCommand( - commands.InitCmd, - commands.ResetCmd, - keys.RootCmd, - commits.RootCmd, - rpccmd.RootCmd, - query.RootCmd, - txcmd.RootCmd, - proxy.RootCmd, - commands.VersionCmd, - auto.AutoCompleteCmd, - ) - - cmd := cli.PrepareMainCmd(BaseCli, "BC", os.ExpandEnv("$HOME/.basecli")) - cmd.Execute() -} diff --git a/_attic/examples/basecoin/cmd/basecoin/main.go b/_attic/examples/basecoin/cmd/basecoin/main.go deleted file mode 100644 index af31e2fe80..0000000000 --- a/_attic/examples/basecoin/cmd/basecoin/main.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - "github.com/tendermint/tmlibs/cli" - - sdk "github.com/cosmos/cosmos-sdk" - client "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/base" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/modules/eyes" - "github.com/cosmos/cosmos-sdk/modules/fee" - "github.com/cosmos/cosmos-sdk/modules/ibc" - "github.com/cosmos/cosmos-sdk/modules/nonce" - "github.com/cosmos/cosmos-sdk/modules/roles" - "github.com/cosmos/cosmos-sdk/server/commands" - "github.com/cosmos/cosmos-sdk/stack" -) - -// RootCmd is the entry point for this binary -var RootCmd = &cobra.Command{ - Use: "basecoin", - Short: "A cryptocurrency framework in Golang based on Tendermint-Core", -} - -// BuildApp constructs the stack we want to use for this app -func BuildApp(feeDenom string) sdk.Handler { - return stack.New( - base.Logger{}, - stack.Recovery{}, - auth.Signatures{}, - base.Chain{}, - stack.Checkpoint{OnCheck: true}, - nonce.ReplayCheck{}, - ). - IBC(ibc.NewMiddleware()). - Apps( - roles.NewMiddleware(), - fee.NewSimpleFeeMiddleware(coin.Coin{feeDenom, 0}, fee.Bank), - stack.Checkpoint{OnDeliver: true}, - ). - Dispatch( - coin.NewHandler(), - stack.WrapHandler(roles.NewHandler()), - stack.WrapHandler(ibc.NewHandler()), - // and just for run, add eyes as well - stack.WrapHandler(eyes.NewHandler()), - ) -} - -func main() { - // require all fees in mycoin - change this in your app! - commands.Handler = BuildApp("mycoin") - - RootCmd.AddCommand( - commands.InitCmd, - commands.StartCmd, - //commands.RelayCmd, - commands.UnsafeResetAllCmd, - client.VersionCmd, - ) - commands.SetUpRoot(RootCmd) - - cmd := cli.PrepareMainCmd(RootCmd, "BC", os.ExpandEnv("$HOME/.basecoin")) - cmd.Execute() -} diff --git a/_attic/examples/basecoin/cmd/baseserver/README.md b/_attic/examples/basecoin/cmd/baseserver/README.md deleted file mode 100644 index a45e160b68..0000000000 --- a/_attic/examples/basecoin/cmd/baseserver/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# baseserver - -baseserver is the REST counterpart to basecli - -## Compiling and running it -```shell -$ go get -u -v github.com/tendermint/basecoin/cmd/baseserver -$ baseserver init -$ baseserver serve --port 8888 -``` - -to run the server at localhost:8888, otherwise if you don't specify --port, -by default the server will be run on port 8998. - -## Supported routes -Route | Method | Completed | Description ----|---|---|--- -/keys|GET|✔️|Lists all keys -/keys|POST|✔️|Generate a new key. It expects fields: "name", "algo", "passphrase" -/keys/{name}|GET|✔️|Retrieves the specific key -/keys/{name}|POST/PUT|✔️|Updates the named key -/keys/{name}|DELETE|✔️|Deletes the named key -/build/send|POST|✔️|Send a transaction -/sign|POST|✔️|Sign a transaction -/tx|POST|✖️|Post a transaction to the blockchain -/seeds/status|GET|✖️|Returns the information on the last seed -/build/create_role|POST|✔️|Creates a role. Please note that the role MUST be valid hex for example instead of sending "role", send its hex encoded equivalent "726f6c65" - -## Preamble: -In the examples below, we assume that URL is set to `http://localhost:8889` -which can be set for example -URL=http://localhost:8889 - -## Sample usage -- Generate a key -```shell -$ curl -X POST $URL/keys --data '{"algo": "ed25519", "name": "SampleX", "passphrase": "Say no more"}' -``` - -```json -{ - "key": { - "name": "SampleX", - "address": "603EE63C41E322FC7A247864A9CD0181282EB458", - "pubkey": { - "type": "ed25519", - "data": "C050948CFC087F5E1068C7E244DDC30E03702621CC9442A28E6C9EDA7771AA0C" - } - }, - "seed_phrase": "border almost future parade speak soccer bulk orange real brisk caution body river chapter" -} -``` - -- Sign a key -```shell -$ curl -X POST $URL/sign --data '{ - "name": "matt", - "password": "Say no more", - "tx": { - "type": "sigs/multi", - "data": { - "tx": {"type":"coin/send","data":{"inputs":[{"address":{"chain":"","app":"role","addr":"62616E6B32"},"coins":[{"denom":"mycoin","amount":900000}]}],"outputs":[{"address":{"chain":"","app":"sigs","addr":"BDADF167E6CF2CDF2D621E590FF1FED2787A40E0"},"coins":[{"denom":"mycoin","amount":900000}]}]}}, - "signatures": null - } - } -}' -``` - -```json -{ - "type": "sigs/multi", - "data": { - "tx": { - "type": "coin/send", - "data": { - "inputs": [ - { - "address": { - "chain": "", - "app": "role", - "addr": "62616E6B32" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 900000 - } - ] - } - ], - "outputs": [ - { - "address": { - "chain": "", - "app": "sigs", - "addr": "BDADF167E6CF2CDF2D621E590FF1FED2787A40E0" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 900000 - } - ] - } - ] - } - }, - "signatures": [ - { - "Sig": { - "type": "ed25519", - "data": "F6FE3053F1E6C236F886A0D525C1AF840F7831B6E50F7E1108C345AA524303920F09945DA110AD5184B3F45717D7114E368B12AFE027FECECC2FC193D4906A0C" - }, - "Pubkey": { - "type": "ed25519", - "data": "0D8D19E527BAE9D1256A3D03009E2708171CDCB71CCDEDA2DC52DD9AD23AEE25" - } - } - ] - } -} -``` - -- Create a role -```shell -$ curl -X POST $URL/build/create_role --data \ -'{ - "role": "deadbeef", - "signers": [{ - "addr": "4FF759D47C81754D8F553DCCAC8651D0AF74C7F9", - "app": "role" - }], - "min_sigs": 1, - "seq": 1 -}' -``` - -```json -{ - "type": "chain/tx", - "data": { - "chain_id": "test_chain_id", - "expires_at": 0, - "tx": { - "type": "role/create", - "data": { - "role": "DEADBEEF", - "min_sigs": 1, - "signers": [ - { - "chain": "", - "app": "role", - "addr": "4FF759D47C81754D8F553DCCAC8651D0AF74C7F9" - } - ] - } - } - } -} -``` diff --git a/_attic/examples/basecoin/cmd/baseserver/main.go b/_attic/examples/basecoin/cmd/baseserver/main.go deleted file mode 100644 index a92e8edd01..0000000000 --- a/_attic/examples/basecoin/cmd/baseserver/main.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" - "os" - - "github.com/gorilla/mux" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/commands" - rest "github.com/cosmos/cosmos-sdk/client/rest" - coinrest "github.com/cosmos/cosmos-sdk/modules/coin/rest" - noncerest "github.com/cosmos/cosmos-sdk/modules/nonce/rest" - rolerest "github.com/cosmos/cosmos-sdk/modules/roles/rest" - "github.com/tendermint/tmlibs/cli" -) - -var srvCli = &cobra.Command{ - Use: "baseserver", - Short: "Light REST client for tendermint", - Long: `Baseserver presents a nice (not raw hex) interface to the basecoin blockchain structure.`, -} - -var serveCmd = &cobra.Command{ - Use: "serve", - Short: "Serve the light REST client for tendermint", - Long: "Access basecoin via REST", - RunE: serve, -} - -const ( - envPortFlag = "port" - defaultAlgo = "ed25519" -) - -func init() { - _ = serveCmd.PersistentFlags().Int(envPortFlag, 8998, "the port to run the server on") -} - -func serve(cmd *cobra.Command, args []string) error { - router := mux.NewRouter() - - routeRegistrars := []func(*mux.Router) error{ - // rest.Keys handlers - rest.NewDefaultKeysManager(defaultAlgo).RegisterAllCRUD, - - // Coin send handler - coinrest.RegisterCoinSend, - // Coin query account handler - coinrest.RegisterQueryAccount, - - // Roles createRole handler - rolerest.RegisterCreateRole, - - // Basecoin sign transactions handler - rest.RegisterSignTx, - // Basecoin post transaction handler - rest.RegisterPostTx, - - // Nonce query handler - noncerest.RegisterQueryNonce, - } - - for _, routeRegistrar := range routeRegistrars { - if err := routeRegistrar(router); err != nil { - log.Fatal(err) - } - } - - port := viper.GetInt(envPortFlag) - addr := fmt.Sprintf(":%d", port) - - log.Printf("Serving on %q", addr) - return http.ListenAndServe(addr, router) -} - -func main() { - commands.AddBasicFlags(srvCli) - - srvCli.AddCommand( - commands.InitCmd, - commands.VersionCmd, - serveCmd, - ) - - // this should share the dir with basecli, so you can use the cli and - // the api interchangeably - cmd := cli.PrepareMainCmd(srvCli, "BC", os.ExpandEnv("$HOME/.basecli")) - if err := cmd.Execute(); err != nil { - log.Fatal(err) - } -} diff --git a/_attic/examples/basecoin/tests/cli/basictx.sh b/_attic/examples/basecoin/tests/cli/basictx.sh deleted file mode 100755 index 853aab4b48..0000000000 --- a/_attic/examples/basecoin/tests/cli/basictx.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash - -# These global variables are required for common.sh -SERVER_EXE=basecoin -CLIENT_EXE=basecli -ACCOUNTS=(jae ethan bucky rigel igor) -RICH=${ACCOUNTS[0]} -POOR=${ACCOUNTS[4]} - -oneTimeSetUp() { - if ! quickSetup .basecoin_test_basictx basictx-chain; then - exit 1; - fi -} - -oneTimeTearDown() { - quickTearDown -} - -test00GetAccount() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - assertFalse "line=${LINENO}, requires arg" "${CLIENT_EXE} query account" - - checkAccount $SENDER "9007199254740992" - - ACCT2=$(${CLIENT_EXE} query account $RECV 2>/dev/null) - assertFalse "line=${LINENO}, has no genesis account" $? -} - -test01SendTx() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - assertFalse "line=${LINENO}, missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1" - assertFalse "line=${LINENO}, bad password" "echo foo | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH" - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH) - txSucceeded $? "$TX" "$RECV" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - checkAccount $SENDER "9007199254740000" "$TX_HEIGHT" - # make sure 0x prefix also works - checkAccount "0x$SENDER" "9007199254740000" "$TX_HEIGHT" - checkAccount $RECV "992" "$TX_HEIGHT" - - # Make sure tx is indexed - checkSendTx $HASH $TX_HEIGHT $SENDER "992" -} - -test02SendTxWithFee() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - # Test to see if the auto-sequencing works, the sequence here should be calculated to be 2 - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=90mycoin --fee=10mycoin --to=$RECV --name=$RICH) - txSucceeded $? "$TX" "$RECV" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - # deduct 100 from sender, add 90 to receiver... fees "vanish" - checkAccount $SENDER "9007199254739900" "$TX_HEIGHT" - checkAccount $RECV "1082" "$TX_HEIGHT" - - # Make sure tx is indexed - checkSendFeeTx $HASH $TX_HEIGHT $SENDER "90" "10" - - # assert replay protection - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=90mycoin --fee=10mycoin --sequence=2 --to=$RECV --name=$RICH 2>/dev/null) - assertFalse "line=${LINENO}, replay: $TX" $? - - # checking normally - checkAccount $SENDER "9007199254739900" "$TX_HEIGHT" - checkAccount $RECV "1082" "$TX_HEIGHT" - - # make sure we can query the proper nonce - NONCE=$(${CLIENT_EXE} query nonce $SENDER) - if [ -n "$DEBUG" ]; then echo $NONCE; echo; fi - # TODO: note that cobra returns error code 0 on parse failure, - # so currently this check passes even if there is no nonce query command - if assertTrue "line=${LINENO}, no nonce query" $?; then - assertEquals "line=${LINENO}, proper nonce" "2" $(echo $NONCE | jq .data) - fi - - # make sure this works without trust also - OLD_BC_HOME=$BC_HOME - export BC_HOME=/foo - export BC_TRUST_NODE=1 - export BC_NODE=localhost:46657 - checkSendFeeTx $HASH $TX_HEIGHT $SENDER "90" "10" - checkAccount $SENDER "9007199254739900" "$TX_HEIGHT" - checkAccount $RECV "1082" "$TX_HEIGHT" - unset BC_TRUST_NODE - unset BC_NODE - export BC_HOME=$OLD_BC_HOME -} - - -test03CreditTx() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - # make sure we are controlled by permissions (only rich can issue credit) - assertFalse "line=${LINENO}, bad password" "echo qwertyuiop | ${CLIENT_EXE} tx credit --amount=1000mycoin --sequence=1 --to=$RECV --name=$POOR" - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx credit --amount=1000mycoin --sequence=3 --to=$RECV --name=$RICH) - txSucceeded $? "$TX" "$RECV" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - # receiver got cash, sender didn't lose any (1000 more than last check) - checkAccount $RECV "2082" "$TX_HEIGHT" - checkAccount $SENDER "9007199254739900" "$TX_HEIGHT" -} - - -# Load common then run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 diff --git a/_attic/examples/basecoin/tests/cli/ibc.sh b/_attic/examples/basecoin/tests/cli/ibc.sh deleted file mode 100755 index ed8a277d96..0000000000 --- a/_attic/examples/basecoin/tests/cli/ibc.sh +++ /dev/null @@ -1,284 +0,0 @@ -#!/bin/bash - -#!/bin/bash - -# These global variables are required for common.sh -SERVER_EXE=basecoin -CLIENT_EXE=basecli -ACCOUNTS=(jae ethan bucky rigel igor) -RICH=${ACCOUNTS[0]} -POOR=${ACCOUNTS[4]} - -# For full stack traces in error output, run -# BC_TRACE=1 ./ibc.sh - -oneTimeSetUp() { - # These are passed in as args - BASE_DIR_1=$HOME/.basecoin_test_ibc/chain1 - CHAIN_ID_1=test-chain-1 - CLIENT_1=${BASE_DIR_1}/client - PREFIX_1=1234 - PORT_1=${PREFIX_1}7 - - BASE_DIR_2=$HOME/.basecoin_test_ibc/chain2 - CHAIN_ID_2=test-chain-2 - CLIENT_2=${BASE_DIR_2}/client - PREFIX_2=2345 - PORT_2=${PREFIX_2}7 - - # Clean up and create the test dirs - rm -rf $BASE_DIR_1 $BASE_DIR_2 2>/dev/null - mkdir -p $BASE_DIR_1 $BASE_DIR_2 - - # Set up client for chain 1- make sure you use the proper prefix if you set - # a custom CLIENT_EXE - BC_HOME=${CLIENT_1} prepareClient - BC_HOME=${CLIENT_2} prepareClient - - # Start basecoin server, giving money to the key in the first client - BC_HOME=${CLIENT_1} initServer $BASE_DIR_1 $CHAIN_ID_1 $PREFIX_1 - if [ $? != 0 ]; then exit 1; fi - PID_SERVER_1=$PID_SERVER - - # Start second basecoin server, giving money to the key in the second client - BC_HOME=${CLIENT_2} initServer $BASE_DIR_2 $CHAIN_ID_2 $PREFIX_2 - if [ $? != 0 ]; then exit 1; fi - PID_SERVER_2=$PID_SERVER - - # Connect both clients - BC_HOME=${CLIENT_1} initClient $CHAIN_ID_1 $PORT_1 - if [ $? != 0 ]; then exit 1; fi - BC_HOME=${CLIENT_2} initClient $CHAIN_ID_2 $PORT_2 - if [ $? != 0 ]; then exit 1; fi - - printf "...Testing may begin!\n\n\n" -} - -oneTimeTearDown() { - printf "\n\nstopping both $SERVER_EXE test servers... $PID_SERVER_1 $PID_SERVER_2" - kill -9 $PID_SERVER_1 - kill -9 $PID_SERVER_2 - sleep 1 -} - -test00GetAccount() { - export BC_HOME=${CLIENT_1} - SENDER_1=$(getAddr $RICH) - RECV_1=$(getAddr $POOR) - - assertFalse "line=${LINENO}, requires arg" "${CLIENT_EXE} query account 2>/dev/null" - assertFalse "line=${LINENO}, has no genesis account" "${CLIENT_EXE} query account $RECV_1 2>/dev/null" - checkAccount $SENDER_1 "9007199254740992" - - export BC_HOME=${CLIENT_2} - SENDER_2=$(getAddr $RICH) - RECV_2=$(getAddr $POOR) - - assertFalse "line=${LINENO}, requires arg" "${CLIENT_EXE} query account 2>/dev/null" - assertFalse "line=${LINENO}, has no genesis account" "${CLIENT_EXE} query account $RECV_2 2>/dev/null" - checkAccount $SENDER_2 "9007199254740992" - - # Make sure that they have different addresses on both chains (they are random keys) - assertNotEquals "line=${LINENO}, sender keys must be different" "$SENDER_1" "$SENDER_2" - assertNotEquals "line=${LINENO}, recipient keys must be different" "$RECV_1" "$RECV_2" -} - -test01RegisterChains() { - # let's get the root commits to cross-register them - ROOT_1="$BASE_DIR_1/root_commit.json" - ${CLIENT_EXE} commits export $ROOT_1 --home=${CLIENT_1} - assertTrue "line=${LINENO}, export commit failed" $? - - ROOT_2="$BASE_DIR_2/root_commit.json" - ${CLIENT_EXE} commits export $ROOT_2 --home=${CLIENT_2} - assertTrue "line=${LINENO}, export commit failed" $? - - # register chain2 on chain1 - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-register \ - --sequence=1 --commit=${ROOT_2} --name=$POOR --home=${CLIENT_1}) - txSucceeded $? "$TX" "register chain2 on chain 1" - # an example to quit early if there is no point in more tests - if [ $? != 0 ]; then echo "aborting!"; return 1; fi - # this is used later to check data - REG_HEIGHT=$(echo $TX | jq .height) - - # register chain1 on chain2 (no money needed... yet) - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-register \ - --sequence=1 --commit=${ROOT_1} --name=$POOR --home=${CLIENT_2}) - txSucceeded $? "$TX" "register chain1 on chain 2" - # an example to quit early if there is no point in more tests - if [ $? != 0 ]; then echo "aborting!"; return 1; fi -} - -test02UpdateChains() { - # let's get the root commits to cross-register them - UPDATE_1="$BASE_DIR_1/seed_1.json" - ${CLIENT_EXE} commits update --home=${CLIENT_1} > /dev/null - ${CLIENT_EXE} commits export $UPDATE_1 --home=${CLIENT_1} - assertTrue "line=${LINENO}, export commit failed" $? - # make sure it is newer than the other.... - assertNewHeight "line=${LINENO}" $ROOT_1 $UPDATE_1 - - UPDATE_2="$BASE_DIR_2/seed_2.json" - ${CLIENT_EXE} commits update --home=${CLIENT_2} > /dev/null - ${CLIENT_EXE} commits export $UPDATE_2 --home=${CLIENT_2} - assertTrue "line=${LINENO}, export commit failed" $? - assertNewHeight "line=${LINENO}" $ROOT_2 $UPDATE_2 - # this is used later to check query data - REGISTER_2_HEIGHT=$(cat $ROOT_2 | jq .commit.header.height) - UPDATE_2_HEIGHT=$(cat $UPDATE_2 | jq .commit.header.height) - - # update chain2 on chain1 - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-update \ - --sequence=2 --commit=${UPDATE_2} --name=$POOR --home=${CLIENT_1}) - txSucceeded $? "$TX" "update chain2 on chain 1" - # an example to quit early if there is no point in more tests - if [ $? != 0 ]; then echo "aborting!"; return 1; fi - - # update chain1 on chain2 (no money needed... yet) - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-update \ - --sequence=2 --commit=${UPDATE_1} --name=$POOR --home=${CLIENT_2}) - txSucceeded $? "$TX" "update chain1 on chain 2" - # an example to quit early if there is no point in more tests - if [ $? != 0 ]; then echo "aborting!"; return 1; fi -} - -# make sure all query commands about ibc work... -test03QueryIBC() { - # just test on one chain, as they are all symetrical - export BC_HOME=${CLIENT_1} - - # make sure we can list all chains - CHAINS=$(${CLIENT_EXE} query ibc chains) - assertTrue "line=${LINENO}, cannot query chains" $? - assertEquals "1" $(echo $CHAINS | jq '.data | length') - assertEquals "line=${LINENO}" "\"$CHAIN_ID_2\"" $(echo $CHAINS | jq '.data[0]') - - # error on unknown chain, data on proper chain - assertFalse "line=${LINENO}, unknown chain" "${CLIENT_EXE} query ibc chain random 2>/dev/null" - CHAIN_INFO=$(${CLIENT_EXE} query ibc chain $CHAIN_ID_2) - assertTrue "line=${LINENO}, cannot query chain $CHAIN_ID_2" $? - assertEquals "line=${LINENO}, register height" $REG_HEIGHT $(echo $CHAIN_INFO | jq .data.registered_at) - assertEquals "line=${LINENO}, tracked height" $UPDATE_2_HEIGHT $(echo $CHAIN_INFO | jq .data.remote_block) -} - -# Trigger a cross-chain sendTx... from RICH on chain1 to POOR on chain2 -# we make sure the money was reduced, but nothing arrived -test04SendIBCPacket() { - export BC_HOME=${CLIENT_1} - - # make sure there are no packets yet - PACKETS=$(${CLIENT_EXE} query ibc packets --to=$CHAIN_ID_2 2>/dev/null) - assertFalse "line=${LINENO}, packet query" $? - - SENDER=$(getAddr $RICH) - RECV=$(BC_HOME=${CLIENT_2} getAddr $POOR) - - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20002mycoin \ - --to=${CHAIN_ID_2}::${RECV} --name=$RICH) - txSucceeded $? "$TX" "${CHAIN_ID_2}::${RECV}" - # quit early if there is no point in more tests - if [ $? != 0 ]; then echo "aborting!"; return 1; fi - - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - # Make sure balance went down and tx is indexed - checkAccount $SENDER "9007199254720990" "$TX_HEIGHT" - checkSendTx $HASH $TX_HEIGHT $SENDER "20002" - - # look, we wrote a packet - PACKETS=$(${CLIENT_EXE} query ibc packets --to=$CHAIN_ID_2 --height=$TX_HEIGHT) - assertTrue "line=${LINENO}, packets query" $? - assertEquals "line=${LINENO}, packet count" 1 $(echo $PACKETS | jq .data) - - # and look at the packet itself - PACKET=$(${CLIENT_EXE} query ibc packet --to=$CHAIN_ID_2 --sequence=0 --height=$TX_HEIGHT) - assertTrue "line=${LINENO}, packet query" $? - assertEquals "line=${LINENO}, proper src" "\"$CHAIN_ID_1\"" $(echo $PACKET | jq .src_chain) - assertEquals "line=${LINENO}, proper dest" "\"$CHAIN_ID_2\"" $(echo $PACKET | jq .packet.dest_chain) - assertEquals "line=${LINENO}, proper sequence" "0" $(echo $PACKET | jq .packet.sequence) - if [ -n "$DEBUG" ]; then echo $PACKET; echo; fi - - # nothing arrived - ARRIVED=$(${CLIENT_EXE} query ibc packets --from=$CHAIN_ID_1 --home=$CLIENT_2 2>/dev/null) - assertFalse "line=${LINENO}, packet query" $? - assertFalse "line=${LINENO}, no relay running" "BC_HOME=${CLIENT_2} ${CLIENT_EXE} query account $RECV" -} - -test05ReceiveIBCPacket() { - export BC_HOME=${CLIENT_2} - RECV=$(getAddr $POOR) - - # make some credit, so we can accept the packet - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx credit --amount=60006mycoin --to=$CHAIN_ID_1:: --name=$RICH) - txSucceeded $? "$TX" "${CHAIN_ID_1}::" - TX_HEIGHT=$(echo $TX | jq .height) - - # make sure there is enough credit - checkAccount $CHAIN_ID_1:: "60006" "$TX_HEIGHT" - # and the poor guy doesn't have a penny to his name - ACCT2=$(${CLIENT_EXE} query account $RECV 2>/dev/null) - assertFalse "line=${LINENO}, has no genesis account" $? - - - # now, we try to post it.... (this is PACKET from last test) - - # get the commit with the proof and post it - SRC_HEIGHT=$(echo $PACKET | jq .src_height) - PROOF_HEIGHT=$(expr $SRC_HEIGHT + 1) - # FIXME: this should auto-update on proofs... - ${CLIENT_EXE} commits update --height=$PROOF_HEIGHT --home=${CLIENT_1} > /dev/null - assertTrue "line=${LINENO}, update commit failed" $? - - PACKET_COMMIT="$BASE_DIR_1/packet_commit.json" - ${CLIENT_EXE} commits export $PACKET_COMMIT --home=${CLIENT_1} --height=$PROOF_HEIGHT - assertTrue "line=${LINENO}, export commit failed" $? - if [ -n "$DEBUG" ]; then - echo "**** SEED ****" - cat $PACKET_COMMIT | jq .commit.header - echo - fi - - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-update \ - --commit=${PACKET_COMMIT} --name=$POOR --sequence=3) - txSucceeded $? "$TX" "prepare packet chain1 on chain 2" - # an example to quit early if there is no point in more tests - if [ $? != 0 ]; then echo "aborting!"; return 1; fi - TX_HEIGHT=$(echo $TX | jq .height) - - # write the packet to the file - POST_PACKET="$BASE_DIR_1/post_packet.json" - echo $PACKET > $POST_PACKET - - # post it as a tx (cross-fingers) - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-post \ - --packet=${POST_PACKET} --name=$POOR --sequence=4) - txSucceeded $? "$TX" "post packet from chain1 on chain 2" - TX_HEIGHT=$(echo $TX | jq .height) - - # ensure $POOR balance was incremented, and credit for CHAIN_1 decremented - checkAccount $CHAIN_ID_1:: "40004" "$TX_HEIGHT" - checkAccount $RECV "20002" "$TX_HEIGHT" - - # look, we wrote a packet - PACKETS=$(${CLIENT_EXE} query ibc packets --height=$TX_HEIGHT --from=$CHAIN_ID_1) - assertTrue "line=${LINENO}, packets query" $? - assertEquals "line=${LINENO}, packet count" 1 $(echo $PACKETS | jq .data) -} - -# XXX Ex Usage: assertNewHeight $MSG $SEED_1 $SEED_2 -# Desc: Asserts that seed2 has a higher block height than commit 1 -assertNewHeight() { - H1=$(cat $2 | jq .commit.header.height) - H2=$(cat $3 | jq .commit.header.height) - assertTrue "$1" "test $H2 -gt $H1" - return $? -} - -# Load common then run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 diff --git a/_attic/examples/basecoin/tests/cli/init-server.sh b/_attic/examples/basecoin/tests/cli/init-server.sh deleted file mode 100755 index 9923540819..0000000000 --- a/_attic/examples/basecoin/tests/cli/init-server.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -CLIENT_EXE=basecli -SERVER_EXE=basecoin - -test01initOption() { - BASE=~/.bc_init_test - rm -rf "$BASE" - mkdir -p "$BASE" - - SERVE_DIR="${BASE}/server" - GENESIS_FILE=${SERVE_DIR}/genesis.json - HEX="deadbeef1234deadbeef1234deadbeef1234aaaa" - - ${SERVER_EXE} init ${HEX} --home="$SERVE_DIR" -p=eyes/key1/val1 -p='"eyes/key2/{""name"": ""joe"", ""age"": ""100""}"' >/dev/null - if ! assertTrue "line=${LINENO}" $?; then return 1; fi - - OPTION1KEY=$(cat ${GENESIS_FILE} | jq '.app_options.plugin_options[2]') - OPTION1VAL=$(cat ${GENESIS_FILE} | jq '.app_options.plugin_options[3]') - OPTION2KEY=$(cat ${GENESIS_FILE} | jq '.app_options.plugin_options[4]') - OPTION2VAL=$(cat ${GENESIS_FILE} | jq '.app_options.plugin_options[5]') - OPTION2VALEXPECTED=$(echo '{"name": "joe", "age": "100"}' | jq '.') - - assertEquals "line=${LINENO}" '"eyes/key1"' $OPTION1KEY - assertEquals "line=${LINENO}" '"val1"' $OPTION1VAL - assertEquals "line=${LINENO}" '"eyes/key2"' $OPTION2KEY - assertEquals "line=${LINENO}" "$OPTION2VALEXPECTED" "$OPTION2VAL" -} - -test02runServer() { - # Attempt to begin the server with the custom genesis - SERVER_LOG=$BASE/${SERVER_EXE}.log - startServer $SERVE_DIR $SERVER_LOG -} - -oneTimeTearDown() { - quickTearDown -} - -# load and run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 diff --git a/_attic/examples/basecoin/tests/cli/init.sh b/_attic/examples/basecoin/tests/cli/init.sh deleted file mode 100755 index 4735832221..0000000000 --- a/_attic/examples/basecoin/tests/cli/init.sh +++ /dev/null @@ -1,110 +0,0 @@ -#!/bin/bash - -CLIENT_EXE=basecli -SERVER_EXE=basecoin - -oneTimeSetUp() { - BASE=~/.bc_init_test - rm -rf "$BASE" - mkdir -p "$BASE" - - SERVER="${BASE}/server" - SERVER_LOG="${BASE}/${SERVER_EXE}.log" - - HEX="deadbeef1234deadbeef1234deadbeef1234aaaa" - ${SERVER_EXE} init ${HEX} --home="$SERVER" >> "$SERVER_LOG" - if ! assertTrue "line=${LINENO}" $?; then return 1; fi - - GENESIS_FILE=${SERVER}/genesis.json - CHAIN_ID=$(cat ${GENESIS_FILE} | jq .chain_id | tr -d \") - - printf "starting ${SERVER_EXE}...\n" - ${SERVER_EXE} start --home="$SERVER" >> "$SERVER_LOG" 2>&1 & - sleep 5 - PID_SERVER=$! - disown - if ! ps $PID_SERVER >/dev/null; then - echo "**STARTUP FAILED**" - cat $SERVER_LOG - return 1 - fi -} - -oneTimeTearDown() { - printf "\nstopping ${SERVER_EXE}..." - kill -9 $PID_SERVER >/dev/null 2>&1 - sleep 1 -} - -test01goodInit() { - export BCHOME=${BASE}/client-01 - assertFalse "line=${LINENO}" "ls ${BCHOME} 2>/dev/null >&2" - - echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null - assertTrue "line=${LINENO}, initialized light-client" $? - checkDir $BCHOME 3 -} - -test02badInit() { - export BCHOME=${BASE}/client-02 - assertFalse "line=${LINENO}" "ls ${BCHOME} 2>/dev/null >&2" - - # no node where we go - echo y | ${CLIENT_EXE} init --node=tcp://localhost:9999 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 - assertFalse "line=${LINENO}, invalid init" $? - # dir there, but empty... - checkDir $BCHOME 0 - - # try with invalid chain id - echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="bad-chain-id" > /dev/null 2>&1 - assertFalse "line=${LINENO}, invalid init" $? - checkDir $BCHOME 0 - - # reject the response - echo n | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 - assertFalse "line=${LINENO}, invalid init" $? - checkDir $BCHOME 0 -} - -test03noDoubleInit() { - export BCHOME=${BASE}/client-03 - assertFalse "line=${LINENO}" "ls ${BCHOME} 2>/dev/null >&2" - - # init properly - echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 - assertTrue "line=${LINENO}, initialized light-client" $? - checkDir $BCHOME 3 - - # try again, and we get an error - echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 - assertFalse "line=${LINENO}, warning on re-init" $? - checkDir $BCHOME 3 - - # unless we --force-reset - echo y | ${CLIENT_EXE} init --force-reset --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 - assertTrue "line=${LINENO}, re-initialized light-client" $? - checkDir $BCHOME 3 -} - -test04acceptGenesisFile() { - export BCHOME=${BASE}/client-04 - assertFalse "line=${LINENO}" "ls ${BCHOME} 2>/dev/null >&2" - - # init properly - ${CLIENT_EXE} init --node=tcp://localhost:46657 --genesis=${GENESIS_FILE} > /dev/null 2>&1 - assertTrue "line=${LINENO}, initialized light-client" $? - checkDir $BCHOME 3 -} - -# XXX Ex: checkDir $DIR $FILES -# Makes sure directory exists and has the given number of files -checkDir() { - assertTrue "line=${LINENO}" "ls ${1} 2>/dev/null >&2" - assertEquals "line=${LINENO}, no files created" "$2" $(ls $1 | wc -l) -} - -# load and run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/shunit2 diff --git a/_attic/examples/basecoin/tests/cli/keys.sh b/_attic/examples/basecoin/tests/cli/keys.sh deleted file mode 100755 index a7253a57af..0000000000 --- a/_attic/examples/basecoin/tests/cli/keys.sh +++ /dev/null @@ -1,146 +0,0 @@ -#!/bin/bash -EXE=basecli - - -oneTimeSetUp() { - PASS=qwertyuiop - export BCHOME=$HOME/.bc_keys_test - ${EXE} reset_all - assertTrue "line ${LINENO}" $? -} - -newKey(){ - assertNotNull "keyname required" "$1" - KEYPASS=${2:-qwertyuiop} - KEY=$(echo $KEYPASS | ${EXE} keys new $1 -o json) - if ! assertTrue "line ${LINENO}: created $1" $?; then return 1; fi - assertEquals "$1" $(echo $KEY | jq .key.name | tr -d \") - return $? -} - -# updateKey -updateKey() { - (echo $2; echo $3) | ${EXE} keys update $1 > /dev/null - return $? -} - -test00MakeKeys() { - USER=demouser - assertFalse "line ${LINENO}: already user $USER" "${EXE} keys get $USER" - newKey $USER - assertTrue "line ${LINENO}: no user $USER" "${EXE} keys get $USER" - # make sure bad password not accepted - assertFalse "accepts short password" "echo 123 | ${EXE} keys new badpass" -} - -test01ListKeys() { - # one line plus the number of keys - assertEquals "2" $(${EXE} keys list | wc -l) - newKey foobar - assertEquals "3" $(${EXE} keys list | wc -l) - # we got the proper name here... - assertEquals "foobar" $(${EXE} keys list -o json | jq .[1].name | tr -d \" ) - # we get all names in normal output - EXPECTEDNAMES=$(echo demouser; echo foobar) - TEXTNAMES=$(${EXE} keys list | tail -n +2 | cut -f1) - assertEquals "$EXPECTEDNAMES" "$TEXTNAMES" - # let's make sure the addresses match! - assertEquals "line ${LINENO}: text and json addresses don't match" $(${EXE} keys list | tail -1 | cut -f3) $(${EXE} keys list -o json | jq .[1].address | tr -d \") -} - -test02updateKeys() { - USER=changer - PASS1=awsedrftgyhu - PASS2=S4H.9j.D9S7hso - PASS3=h8ybO7GY6d2 - - newKey $USER $PASS1 - assertFalse "line ${LINENO}: accepts invalid pass" "updateKey $USER $PASS2 $PASS2" - assertTrue "line ${LINENO}: doesn't update" "updateKey $USER $PASS1 $PASS2" - assertTrue "line ${LINENO}: takes new key after update" "updateKey $USER $PASS2 $PASS3" -} - -test03recoverKeys() { - USER=sleepy - PASS1=S4H.9j.D9S7hso - - USER2=easy - PASS2=1234567890 - - # make a user and check they exist - KEY=$(echo $PASS1 | ${EXE} keys new $USER -o json) - if ! assertTrue "created $USER" $?; then return 1; fi - if [ -n "$DEBUG" ]; then echo $KEY; echo; fi - - SEED=$(echo $KEY | jq .seed | tr -d \") - ADDR=$(echo $KEY | jq .key.address | tr -d \") - PUBKEY=$(echo $KEY | jq .key.pubkey | tr -d \") - assertTrue "line ${LINENO}" "${EXE} keys get $USER > /dev/null" - - # let's delete this key - assertFalse "line ${LINENO}" "echo foo | ${EXE} keys delete $USER > /dev/null" - assertTrue "line ${LINENO}" "echo $PASS1 | ${EXE} keys delete $USER > /dev/null" - assertFalse "line ${LINENO}" "${EXE} keys get $USER > /dev/null" - - # fails on short password - assertFalse "line ${LINENO}" "echo foo; echo $SEED | ${EXE} keys recover $USER2 -o json > /dev/null" - # fails on bad seed - assertFalse "line ${LINENO}" "echo $PASS2; echo \"silly white whale tower bongo\" | ${EXE} keys recover $USER2 -o json > /dev/null" - # now we got it - KEY2=$((echo $PASS2; echo $SEED) | ${EXE} keys recover $USER2 -o json) - if ! assertTrue "recovery failed: $KEY2" $?; then return 1; fi - if [ -n "$DEBUG" ]; then echo $KEY2; echo; fi - - # make sure it looks the same - NAME2=$(echo $KEY2 | jq .name | tr -d \") - ADDR2=$(echo $KEY2 | jq .address | tr -d \") - PUBKEY2=$(echo $KEY2 | jq .pubkey | tr -d \") - assertEquals "line ${LINENO}: wrong username" "$USER2" "$NAME2" - assertEquals "line ${LINENO}: address doesn't match" "$ADDR" "$ADDR2" - assertEquals "line ${LINENO}: pubkey doesn't match" "$PUBKEY" "$PUBKEY2" - - # and we can find the info - assertTrue "line ${LINENO}" "${EXE} keys get $USER2 > /dev/null" -} - -# try recovery with secp256k1 keys -test03recoverSecp() { - USER=dings - PASS1=Sbub-U9byS7hso - - USER2=booms - PASS2=1234567890 - - KEY=$(echo $PASS1 | ${EXE} keys new $USER -o json -t secp256k1) - if ! assertTrue "created $USER" $?; then return 1; fi - if [ -n "$DEBUG" ]; then echo $KEY; echo; fi - - SEED=$(echo $KEY | jq .seed | tr -d \") - ADDR=$(echo $KEY | jq .key.address | tr -d \") - PUBKEY=$(echo $KEY | jq .key.pubkey | tr -d \") - assertTrue "line ${LINENO}" "${EXE} keys get $USER > /dev/null" - - # now we got it - KEY2=$((echo $PASS2; echo $SEED) | ${EXE} keys recover $USER2 -o json) - if ! assertTrue "recovery failed: $KEY2" $?; then return 1; fi - if [ -n "$DEBUG" ]; then echo $KEY2; echo; fi - - # make sure it looks the same - NAME2=$(echo $KEY2 | jq .name | tr -d \") - ADDR2=$(echo $KEY2 | jq .address | tr -d \") - PUBKEY2=$(echo $KEY2 | jq .pubkey | tr -d \") - assertEquals "line ${LINENO}: wrong username" "$USER2" "$NAME2" - assertEquals "line ${LINENO}: address doesn't match" "$ADDR" "$ADDR2" - assertEquals "line ${LINENO}: pubkey doesn't match" "$PUBKEY" "$PUBKEY2" - - # and we can find the info - assertTrue "line ${LINENO}" "${EXE} keys get $USER2 > /dev/null" -} - -# load and run these tests with shunit2! - -# load and run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/shunit2 diff --git a/_attic/examples/basecoin/tests/cli/rest.sh b/_attic/examples/basecoin/tests/cli/rest.sh deleted file mode 100755 index 076e08e3e4..0000000000 --- a/_attic/examples/basecoin/tests/cli/rest.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash - -# These global variables are required for common.sh -SERVER_EXE=basecoin -CLIENT_EXE=basecli -ACCOUNTS=(jae ethan bucky rigel igor) -RICH=${ACCOUNTS[0]} -POOR=${ACCOUNTS[4]} - -BPORT=7000 -URL="localhost:${BPORT}" - -oneTimeSetUp() { - if ! quickSetup .basecoin_test_rest rest-chain; then - exit 1; - fi - baseserver serve --port $BPORT >/dev/null & - sleep 0.1 # for startup - PID_PROXY=$! - disown -} - -oneTimeTearDown() { - quickTearDown - kill -9 $PID_PROXY -} - -# XXX Ex Usage: restAddr $NAME -# Desc: Gets the address for a key name via rest -restAddr() { - assertNotNull "line=${LINENO}, keyname required" "$1" - ADDR=$(curl ${URL}/keys/${1} 2>/dev/null | jq .address | tr -d \") - assertNotEquals "line=${LINENO}, null key" "null" "$ADDR" - assertNotEquals "line=${LINENO}, no key" "" "$ADDR" - echo $ADDR -} - -# XXX Ex Usage: restAccount $ADDR $AMOUNT [$HEIGHT] -# Desc: Assumes just one coin, checks the balance of first coin in any case -restAccount() { - assertNotNull "line=${LINENO}, address required" "$1" - QUERY=${URL}/query/account/sigs:$1 - if [ -n "$3" ]; then - QUERY="${QUERY}?height=${3}" - fi - ACCT=$(curl ${QUERY} 2>/dev/null) - if [ -n "$DEBUG" ]; then echo $QUERY; echo $ACCT; echo; fi - assertEquals "line=${LINENO}, proper money" "$2" $(echo $ACCT | jq .data.coins[0].amount) - return $? -} - -restNoAccount() { - ERROR=$(curl ${URL}/query/account/sigs:$1 2>/dev/null) - assertEquals "line=${LINENO}, should error" 400 $(echo $ERROR | jq .code) -} - -test00GetAccount() { - RECV=$(restAddr $POOR) - SENDER=$(restAddr $RICH) - - restNoAccount $RECV - restAccount $SENDER "9007199254740992" -} - -test01SendTx() { - SENDER=$(restAddr $RICH) - RECV=$(restAddr $POOR) - - CMD="{\"from\": {\"app\": \"sigs\", \"addr\": \"$SENDER\"}, \"to\": {\"app\": \"sigs\", \"addr\": \"$RECV\"}, \"amount\": [{\"denom\": \"mycoin\", \"amount\": 992}], \"sequence\": 1}" - - UNSIGNED=$(curl -XPOST ${URL}/build/send -d "$CMD" 2>/dev/null) - if [ -n "$DEBUG" ]; then echo $UNSIGNED; echo; fi - - TOSIGN="{\"name\": \"$RICH\", \"password\": \"qwertyuiop\", \"tx\": $UNSIGNED}" - SIGNED=$(curl -XPOST ${URL}/sign -d "$TOSIGN" 2>/dev/null) - TX=$(curl -XPOST ${URL}/tx -d "$SIGNED" 2>/dev/null) - if [ -n "$DEBUG" ]; then echo $TX; echo; fi - - txSucceeded $? "$TX" "$RECV" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - restAccount $SENDER "9007199254740000" "$TX_HEIGHT" - restAccount $RECV "992" "$TX_HEIGHT" - - # Make sure tx is indexed - checkSendTx $HASH $TX_HEIGHT $SENDER "992" -} - - -# XXX Ex Usage: restCreateRole $PAYLOAD $EXPECTED -# Desc: Tests that the first returned signer.addr matches the expected -restCreateRole() { - assertNotNull "line=${LINENO}, data required" "$1" - ROLE=$(curl ${URL}/build/create_role --data "$1" 2>/dev/null) - if [ -n "$DEBUG" ]; then echo -e "$ROLE\n"; fi - assertEquals "line=${LINENO}, role required" "$2" $(echo $ROLE | jq .data.tx.data.signers[0].addr) - return $? -} - -test03CreateRole() { - DATA="{\"role\": \"726f6c65\", \"seq\": 1, \"min_sigs\": 1, \"signers\": [{\"addr\": \"4FF759D47C81754D8F553DCCAC8651D0AF74C7F9\", \"app\": \"role\"}]}" - restCreateRole "$DATA" \""4FF759D47C81754D8F553DCCAC8651D0AF74C7F9"\" -} - -test04CreateRoleInvalid() { - ERROR=$(curl ${URL}/build/create_role --data '{}' 2>/dev/null) - assertEquals "line=${LINENO}, should report validation failed" 0 $(echo $ERROR | grep "failed" > /dev/null && echo 0 || echo 1) - - ERROR=$(curl ${URL}/build/create_role --data '{"role": "foo"}' 2>/dev/null) - assertEquals "line=${LINENO}, should report validation failed" 0 $(echo $ERROR | grep "failed" > /dev/null && echo 0 || echo 1) - - ERROR=$(curl ${URL}/build/create_role --data '{"min_sigs": 2, "role": "abcdef"}' 2>/dev/null) - assertEquals "line=${LINENO}, should report validation failed" 0 $(echo $ERROR | grep "failed" > /dev/null && echo 0 || echo 1) - - ## Non-hex roles should be rejected - ERROR=$(curl ${URL}/build/create_role --data "{\"role\": \"foobar\", \"seq\": 2, \"signers\": [{\"addr\": \"4FF759D47C81754D8F553DCCAC8651D0AF74C7F9\", \"app\": \"role\"}], \"min_sigs\": 1}" 2>/dev/null) - assertEquals "line=${LINENO}, should report validation failed" 0 $(echo $ERROR | grep "invalid hex" > /dev/null && echo 0 || echo 1) -} - - -# test02SendTxWithFee() { -# SENDER=$(getAddr $RICH) -# RECV=$(getAddr $POOR) - -# # Test to see if the auto-sequencing works, the sequence here should be calculated to be 2 -# TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=90mycoin --fee=10mycoin --to=$RECV --name=$RICH) -# txSucceeded $? "$TX" "$RECV" -# HASH=$(echo $TX | jq .hash | tr -d \") -# TX_HEIGHT=$(echo $TX | jq .height) - -# # deduct 100 from sender, add 90 to receiver... fees "vanish" -# checkAccount $SENDER "9007199254739900" "$TX_HEIGHT" -# checkAccount $RECV "1082" "$TX_HEIGHT" - -# # Make sure tx is indexed -# checkSendFeeTx $HASH $TX_HEIGHT $SENDER "90" "10" - -# # assert replay protection -# TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=90mycoin --fee=10mycoin --sequence=2 --to=$RECV --name=$RICH 2>/dev/null) -# assertFalse "line=${LINENO}, replay: $TX" $? -# checkAccount $SENDER "9007199254739900" "$TX_HEIGHT" -# checkAccount $RECV "1082" "$TX_HEIGHT" - -# # make sure we can query the proper nonce -# NONCE=$(${CLIENT_EXE} query nonce $SENDER) -# if [ -n "$DEBUG" ]; then echo $NONCE; echo; fi -# # TODO: note that cobra returns error code 0 on parse failure, -# # so currently this check passes even if there is no nonce query command -# if assertTrue "line=${LINENO}, no nonce query" $?; then -# assertEquals "line=${LINENO}, proper nonce" "2" $(echo $NONCE | jq .data) -# fi -# } - - -# Load common then run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 diff --git a/_attic/examples/basecoin/tests/cli/restart.sh b/_attic/examples/basecoin/tests/cli/restart.sh deleted file mode 100755 index 1d85f94ccc..0000000000 --- a/_attic/examples/basecoin/tests/cli/restart.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -# these are two globals to control all scripts (can use eg. counter instead) -SERVER_EXE=basecoin -CLIENT_EXE=basecli -ACCOUNTS=(jae ethan bucky rigel igor) -RICH=${ACCOUNTS[0]} -POOR=${ACCOUNTS[4]} - -oneTimeSetUp() { - if ! quickSetup .basecoin_test_restart restart-chain; then - exit 1; - fi -} - -oneTimeTearDown() { - quickTearDown -} - -test00PreRestart() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH) - txSucceeded $? "$TX" "$RECV" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - checkAccount $SENDER "9007199254740000" "$TX_HEIGHT" - checkAccount $RECV "992" "$TX_HEIGHT" - - # make sure tx is indexed - checkSendTx $HASH $TX_HEIGHT $SENDER "992" - -} - -test01OnRestart() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=10000mycoin --sequence=2 --to=$RECV --name=$RICH) - txSucceeded $? "$TX" "$RECV" - if [ $? != 0 ]; then echo "can't make tx!"; return 1; fi - - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - # wait til we have quite a few blocks... like at least 20, - # so the query command won't just wait for the next eg. 7 blocks to verify the result - echo "waiting to generate lots of blocks..." - sleep 5 - echo "done waiting!" - - # last minute tx just at the block cut-off... - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20000mycoin --sequence=3 --to=$RECV --name=$RICH) - txSucceeded $? "$TX" "$RECV" - if [ $? != 0 ]; then echo "can't make second tx!"; return 1; fi - - # now we do a restart... - quickTearDown - startServer $BASE_DIR/server $BASE_DIR/${SERVER_EXE}.log - if [ $? != 0 ]; then echo "can't restart server!"; return 1; fi - - # make sure queries still work properly, with all 3 tx now executed - echo "Checking state after restart..." - checkAccount $SENDER "9007199254710000" - checkAccount $RECV "30992" - - # make sure tx is indexed - checkSendTx $HASH $TX_HEIGHT $SENDER "10000" - - # for double-check of logs - if [ -n "$DEBUG" ]; then - cat $BASE_DIR/${SERVER_EXE}.log; - fi -} - - -# Load common then run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 - diff --git a/_attic/examples/basecoin/tests/cli/roles.sh b/_attic/examples/basecoin/tests/cli/roles.sh deleted file mode 100755 index 77d5f169d1..0000000000 --- a/_attic/examples/basecoin/tests/cli/roles.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash - -# These global variables are required for common.sh -SERVER_EXE=basecoin -CLIENT_EXE=basecli -ACCOUNTS=(jae ethan bucky rigel igor) -RICH=${ACCOUNTS[0]} -POOR=${ACCOUNTS[4]} -DUDE=${ACCOUNTS[2]} -ROLE="10CAFE4E" - -oneTimeSetUp() { - if ! quickSetup .basecoin_test_roles roles-chain; then - exit 1; - fi -} - -oneTimeTearDown() { - quickTearDown -} - -test01SetupRole() { - ONE=$(getAddr $RICH) - TWO=$(getAddr $POOR) - THREE=$(getAddr $DUDE) - MEMBERS=${ONE},${TWO},${THREE} - - SIGS=2 - - assertFalse "line=${LINENO}, missing min-sigs" "echo qwertyuiop | ${CLIENT_EXE} tx create-role --role=${ROLE} --members=${MEMBERS} --sequence=1 --name=$RICH" - assertFalse "line=${LINENO}, missing members" "echo qwertyuiop | ${CLIENT_EXE} tx create-role --role=${ROLE} --min-sigs=2 --sequence=1 --name=$RICH" - assertFalse "line=${LINENO}, missing role" "echo qwertyuiop | ${CLIENT_EXE} tx create-role --min-sigs=2 --members=${MEMBERS} --sequence=1 --name=$RICH" - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx create-role --role=${ROLE} --min-sigs=$SIGS --members=${MEMBERS} --sequence=1 --name=$RICH) - txSucceeded $? "$TX" "${ROLE}" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - checkRole "${ROLE}" $SIGS 3 "$TX_HEIGHT" - - # Make sure tx is indexed - checkRoleTx $HASH $TX_HEIGHT "${ROLE}" 3 -} - -test02SendTxToRole() { - SENDER=$(getAddr $RICH) - RECV=role:${ROLE} - - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --fee=90mycoin --amount=10000mycoin --to=$RECV --sequence=2 --name=$RICH) - txSucceeded $? "$TX" "${ROLE}" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - # reduce by 10090 - checkAccount $SENDER "9007199254730902" "$TX_HEIGHT" - checkAccount $RECV "10000" "$TX_HEIGHT" - - checkSendFeeTx $HASH $TX_HEIGHT $SENDER "10000" "90" -} - -test03SendMultiFromRole() { - ONE=$(getAddr $RICH) - TWO=$(getAddr $POOR) - THREE=$(getAddr $DUDE) - BANK=role:${ROLE} - - # no money to start mr. poor... - assertFalse "line=${LINENO}, has no money yet" "${CLIENT_EXE} query account $TWO 2>/dev/null" - - # let's try to send money from the role directly without multisig - FAIL=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=6000mycoin --from=$BANK --to=$TWO --sequence=1 --name=$POOR 2>/dev/null) - assertFalse "need to assume role" $? - FAIL=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=6000mycoin --from=$BANK --to=$TWO --sequence=2 --assume-role=${ROLE} --name=$POOR 2>/dev/null) - assertFalse "need two signatures" $? - - # okay, begin a multisig transaction mr. poor... - TX_FILE=$BASE_DIR/tx.json - echo qwertyuiop | ${CLIENT_EXE} tx send --amount=6000mycoin --from=$BANK --to=$TWO --sequence=1 --assume-role=${ROLE} --name=$POOR --multi --prepare=$TX_FILE - assertTrue "line=${LINENO}, successfully prepare tx" $? - # and get some dude to sign it - # FAIL=$(echo qwertyuiop | ${CLIENT_EXE} tx --in=$TX_FILE --name=$POOR 2>/dev/null) - # assertFalse "line=${LINENO}, double signing doesn't get bank" $? - # and get some dude to sign it for the full access - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx --in=$TX_FILE --name=$DUDE) - txSucceeded $? "$TX" "multi-bank" - TX_HEIGHT=$(echo $TX | jq .height) - - checkAccount $TWO "6000" "$TX_HEIGHT" - checkAccount $BANK "4000" "$TX_HEIGHT" -} - - -# Load common then run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 diff --git a/_attic/examples/basecoin/tests/cli/rpc.sh b/_attic/examples/basecoin/tests/cli/rpc.sh deleted file mode 100755 index 5ab6022d9b..0000000000 --- a/_attic/examples/basecoin/tests/cli/rpc.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -CLIENT_EXE=basecli -SERVER_EXE=basecoin - -oneTimeSetUp() { - BASE=~/.bc_init_test - rm -rf "$BASE" - mkdir -p "$BASE" - - SERVER="${BASE}/server" - SERVER_LOG="${BASE}/${SERVER_EXE}.log" - - HEX="deadbeef1234deadbeef1234deadbeef1234aaaa" - ${SERVER_EXE} init ${HEX} --home="$SERVER" >> "$SERVER_LOG" - if ! assertTrue "line=${LINENO}" $?; then return 1; fi - - GENESIS_FILE=${SERVER}/genesis.json - CHAIN_ID=$(cat ${GENESIS_FILE} | jq .chain_id | tr -d \") - - printf "starting ${SERVER_EXE}...\n" - ${SERVER_EXE} start --home="$SERVER" >> "$SERVER_LOG" 2>&1 & - sleep 5 - PID_SERVER=$! - disown - if ! ps $PID_SERVER >/dev/null; then - echo "**STARTUP FAILED**" - cat $SERVER_LOG - return 1 - fi - - # this sets the base for all client queries in the tests - export BCHOME=${BASE}/client - ${CLIENT_EXE} init --node=tcp://localhost:46657 --genesis=${GENESIS_FILE} > /dev/null 2>&1 - if ! assertTrue "line=${LINENO}, initialized light-client" "$?"; then - return 1 - fi -} - -oneTimeTearDown() { - printf "\nstopping ${SERVER_EXE}..." - kill -9 $PID_SERVER >/dev/null 2>&1 - sleep 1 -} - -test01GetInsecure() { - GENESIS=$(${CLIENT_EXE} rpc genesis) - assertTrue "line=${LINENO}, get genesis" "$?" - MYCHAIN=$(echo ${GENESIS} | jq .genesis.chain_id | tr -d \") - assertEquals "line=${LINENO}, genesis chain matches" "${CHAIN_ID}" "${MYCHAIN}" - - STATUS=$(${CLIENT_EXE} rpc status) - assertTrue "line=${LINENO}, get status" "$?" - SHEIGHT=$(echo ${STATUS} | jq .latest_block_height) - assertTrue "line=${LINENO}, parsed status" "$?" - assertNotNull "line=${LINENO}, has a height" "${SHEIGHT}" - - VALS=$(${CLIENT_EXE} rpc validators) - assertTrue "line=${LINENO}, get validators" "$?" - VHEIGHT=$(echo ${VALS} | jq .block_height) - assertTrue "line=${LINENO}, parsed validators" "$?" - assertTrue "line=${LINENO}, sensible heights: $SHEIGHT / $VHEIGHT" "test $VHEIGHT -ge $SHEIGHT" - VCNT=$(echo ${VALS} | jq '.validators | length') - assertEquals "line=${LINENO}, one validator" "1" "$VCNT" - - INFO=$(${CLIENT_EXE} rpc info) - assertTrue "line=${LINENO}, get info" "$?" - DATA=$(echo $INFO | jq .response.data) - assertEquals "line=${LINENO}, basecoin info" '"basecoin v0.7.1"' "$DATA" -} - -test02GetSecure() { - HEIGHT=$(${CLIENT_EXE} rpc status | jq .latest_block_height) - assertTrue "line=${LINENO}, get status" "$?" - - # check block produces something reasonable - assertFalse "line=${LINENO}, missing height" "${CLIENT_EXE} rpc block" - BLOCK=$(${CLIENT_EXE} rpc block --height=$HEIGHT) - assertTrue "line=${LINENO}, get block" "$?" - MHEIGHT=$(echo $BLOCK | jq .block_meta.header.height) - assertEquals "line=${LINENO}, meta height" "${HEIGHT}" "${MHEIGHT}" - BHEIGHT=$(echo $BLOCK | jq .block.header.height) - assertEquals "line=${LINENO}, meta height" "${HEIGHT}" "${BHEIGHT}" - - # check commit produces something reasonable - assertFalse "line=${LINENO}, missing height" "${CLIENT_EXE} rpc commit" - let "CHEIGHT = $HEIGHT - 1" - COMMIT=$(${CLIENT_EXE} rpc commit --height=$CHEIGHT) - assertTrue "line=${LINENO}, get commit" "$?" - HHEIGHT=$(echo $COMMIT | jq .header.height) - assertEquals "line=${LINENO}, commit height" "${CHEIGHT}" "${HHEIGHT}" - assertEquals "line=${LINENO}, canonical" "true" $(echo $COMMIT | jq .canonical) - BSIG=$(echo $BLOCK | jq .block.last_commit) - CSIG=$(echo $COMMIT | jq .commit) - assertEquals "line=${LINENO}, block and commit" "$BSIG" "$CSIG" - - # now let's get some headers - # assertFalse "missing height" "${CLIENT_EXE} rpc headers" - HEADERS=$(${CLIENT_EXE} rpc headers --min=$CHEIGHT --max=$HEIGHT) - assertTrue "line=${LINENO}, get headers" "$?" - assertEquals "line=${LINENO}, proper height" "$HEIGHT" $(echo $HEADERS | jq '.block_metas[0].header.height') - assertEquals "line=${LINENO}, two headers" "2" $(echo $HEADERS | jq '.block_metas | length') - # should we check these headers? - CHEAD=$(echo $COMMIT | jq .header) - # most recent first, so the commit header is second.... - HHEAD=$(echo $HEADERS | jq .block_metas[1].header) - assertEquals "line=${LINENO}, commit and header" "$CHEAD" "$HHEAD" -} - -test03Waiting() { - START=$(${CLIENT_EXE} rpc status | jq .latest_block_height) - assertTrue "line=${LINENO}, get status" "$?" - - let "NEXT = $START + 5" - assertFalse "line=${LINENO}, no args" "${CLIENT_EXE} rpc wait" - assertFalse "line=${LINENO}, too long" "${CLIENT_EXE} rpc wait --height=1234" - assertTrue "line=${LINENO}, normal wait" "${CLIENT_EXE} rpc wait --height=$NEXT" - - STEP=$(${CLIENT_EXE} rpc status | jq .latest_block_height) - assertEquals "line=${LINENO}, wait until height" "$NEXT" "$STEP" - - let "NEXT = $STEP + 3" - assertTrue "line=${LINENO}, ${CLIENT_EXE} rpc wait --delta=3" - STEP=$(${CLIENT_EXE} rpc status | jq .latest_block_height) - assertEquals "line=${LINENO}, wait for delta" "$NEXT" "$STEP" -} - -# load and run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/shunit2 diff --git a/_attic/examples/counter/Makefile b/_attic/examples/counter/Makefile deleted file mode 100644 index 9fd61be897..0000000000 --- a/_attic/examples/counter/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -LINKER_FLAGS:="-X github.com/cosmos/cosmos-sdk/client/commands.CommitHash=`git rev-parse --short HEAD`" - -install: - @go install -ldflags $(LINKER_FLAGS) ./cmd/... - -test: test_unit test_cli - -test_unit: - @go test `glide novendor` - -test_cli: - ./tests/cli/counter.sh - -.PHONY: install test test_unit test_cli diff --git a/_attic/examples/counter/cmd/counter/main.go b/_attic/examples/counter/cmd/counter/main.go deleted file mode 100644 index b747e3be0d..0000000000 --- a/_attic/examples/counter/cmd/counter/main.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - - "github.com/tendermint/tmlibs/cli" - - client "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/examples/counter/plugins/counter" - "github.com/cosmos/cosmos-sdk/server/commands" -) - -// RootCmd is the entry point for this binary -var RootCmd = &cobra.Command{ - Use: "counter", - Short: "demo application for cosmos sdk", -} - -func main() { - - // TODO: register the counter here - commands.Handler = counter.NewHandler("mycoin") - - RootCmd.AddCommand( - commands.InitCmd, - commands.StartCmd, - commands.UnsafeResetAllCmd, - client.VersionCmd, - ) - commands.SetUpRoot(RootCmd) - - cmd := cli.PrepareMainCmd(RootCmd, "CT", os.ExpandEnv("$HOME/.counter")) - cmd.Execute() -} diff --git a/_attic/examples/counter/cmd/countercli/commands/counter.go b/_attic/examples/counter/cmd/countercli/commands/counter.go deleted file mode 100644 index cb22cdb502..0000000000 --- a/_attic/examples/counter/cmd/countercli/commands/counter.go +++ /dev/null @@ -1,52 +0,0 @@ -package commands - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - - sdk "github.com/cosmos/cosmos-sdk" - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - "github.com/cosmos/cosmos-sdk/examples/counter/plugins/counter" - "github.com/cosmos/cosmos-sdk/modules/coin" -) - -//CounterTxCmd is the CLI command to execute the counter -// through the appTx Command -var CounterTxCmd = &cobra.Command{ - Use: "counter", - Short: "add a vote to the counter", - Long: `Add a vote to the counter. - -You must pass --valid for it to count and the countfee will be added to the counter.`, - RunE: counterTx, -} - -// nolint - flags names -const ( - FlagCountFee = "countfee" - FlagValid = "valid" -) - -func init() { - fs := CounterTxCmd.Flags() - fs.String(FlagCountFee, "", "Coins to send in the format ,...") - fs.Bool(FlagValid, false, "Is count valid?") -} - -func counterTx(cmd *cobra.Command, args []string) error { - tx, err := readCounterTxFlags() - if err != nil { - return err - } - return txcmd.DoTx(tx) -} - -func readCounterTxFlags() (tx sdk.Tx, err error) { - feeCoins, err := coin.ParseCoins(viper.GetString(FlagCountFee)) - if err != nil { - return tx, err - } - - tx = counter.NewTx(viper.GetBool(FlagValid), feeCoins) - return tx, nil -} diff --git a/_attic/examples/counter/cmd/countercli/commands/query.go b/_attic/examples/counter/cmd/countercli/commands/query.go deleted file mode 100644 index 40a42df725..0000000000 --- a/_attic/examples/counter/cmd/countercli/commands/query.go +++ /dev/null @@ -1,32 +0,0 @@ -package commands - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/query" - - "github.com/cosmos/cosmos-sdk/examples/counter/plugins/counter" - "github.com/cosmos/cosmos-sdk/stack" -) - -//CounterQueryCmd - CLI command to query the counter state -var CounterQueryCmd = &cobra.Command{ - Use: "counter", - Short: "Query counter state, with proof", - RunE: counterQueryCmd, -} - -func counterQueryCmd(cmd *cobra.Command, args []string) error { - var cp counter.State - - prove := !viper.GetBool(commands.FlagTrustNode) - key := stack.PrefixedKey(counter.NameCounter, counter.StateKey()) - h, err := query.GetParsed(key, &cp, query.GetHeight(), prove) - if err != nil { - return err - } - - return query.OutputProof(cp, h) -} diff --git a/_attic/examples/counter/cmd/countercli/main.go b/_attic/examples/counter/cmd/countercli/main.go deleted file mode 100644 index d2845aefc9..0000000000 --- a/_attic/examples/counter/cmd/countercli/main.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - - "github.com/tendermint/tmlibs/cli" - - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/commits" - "github.com/cosmos/cosmos-sdk/client/commands/keys" - "github.com/cosmos/cosmos-sdk/client/commands/proxy" - "github.com/cosmos/cosmos-sdk/client/commands/query" - - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - bcount "github.com/cosmos/cosmos-sdk/examples/counter/cmd/countercli/commands" - authcmd "github.com/cosmos/cosmos-sdk/modules/auth/commands" - basecmd "github.com/cosmos/cosmos-sdk/modules/base/commands" - coincmd "github.com/cosmos/cosmos-sdk/modules/coin/commands" - feecmd "github.com/cosmos/cosmos-sdk/modules/fee/commands" - noncecmd "github.com/cosmos/cosmos-sdk/modules/nonce/commands" -) - -// CounterCli represents the base command when called without any subcommands -var CounterCli = &cobra.Command{ - Use: "countercli", - Short: "Example app built using the Cosmos SDK", - Long: `Countercli is a demo app that includes custom logic to -present a formatted interface to a custom blockchain structure. - -This is a useful tool and also serves to demonstrate how to configure -the Cosmos SDK to work for any custom ABCI app, see: - -`, -} - -func main() { - commands.AddBasicFlags(CounterCli) - - // Prepare queries - query.RootCmd.AddCommand( - // These are default parsers, optional in your app - query.TxQueryCmd, - query.KeyQueryCmd, - coincmd.AccountQueryCmd, - noncecmd.NonceQueryCmd, - - // XXX IMPORTANT: here is how you add custom query commands in your app - bcount.CounterQueryCmd, - ) - - // set up the middleware - txcmd.Middleware = txcmd.Wrappers{ - feecmd.FeeWrapper{}, - noncecmd.NonceWrapper{}, - basecmd.ChainWrapper{}, - authcmd.SigWrapper{}, - } - txcmd.Middleware.Register(txcmd.RootCmd.PersistentFlags()) - - // Prepare transactions - txcmd.RootCmd.AddCommand( - // This is the default transaction, optional in your app - coincmd.SendTxCmd, - - // XXX IMPORTANT: here is how you add custom tx construction for your app - bcount.CounterTxCmd, - ) - - // Set up the various commands to use - CounterCli.AddCommand( - commands.InitCmd, - commands.ResetCmd, - commands.VersionCmd, - keys.RootCmd, - commits.RootCmd, - query.RootCmd, - txcmd.RootCmd, - proxy.RootCmd, - ) - - cmd := cli.PrepareMainCmd(CounterCli, "CTL", os.ExpandEnv("$HOME/.countercli")) - cmd.Execute() -} diff --git a/_attic/examples/counter/plugins/counter/counter.go b/_attic/examples/counter/plugins/counter/counter.go deleted file mode 100644 index 7ce08761db..0000000000 --- a/_attic/examples/counter/plugins/counter/counter.go +++ /dev/null @@ -1,226 +0,0 @@ -package counter - -import ( - "fmt" - - abci "github.com/tendermint/abci/types" - "github.com/tendermint/go-wire" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/base" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/modules/fee" - "github.com/cosmos/cosmos-sdk/modules/ibc" - "github.com/cosmos/cosmos-sdk/modules/nonce" - "github.com/cosmos/cosmos-sdk/modules/roles" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -// Tx -//-------------------------------------------------------------------------------- - -// register the tx type with it's validation logic -// make sure to use the name of the handler as the prefix in the tx type, -// so it gets routed properly -const ( - NameCounter = "cntr" - ByteTx = 0x2F //TODO What does this byte represent should use typebytes probably - TypeTx = NameCounter + "/count" -) - -func init() { - sdk.TxMapper.RegisterImplementation(Tx{}, TypeTx, ByteTx) -} - -// Tx - struct for all counter transactions -type Tx struct { - Valid bool `json:"valid"` - Fee coin.Coins `json:"fee"` -} - -// NewTx - return a new counter transaction struct wrapped as a basecoin transaction -func NewTx(valid bool, fee coin.Coins) sdk.Tx { - return Tx{ - Valid: valid, - Fee: fee, - }.Wrap() -} - -// Wrap - Wrap a Tx as a Basecoin Tx, used to satisfy the XXX interface -func (c Tx) Wrap() sdk.Tx { - return sdk.Tx{TxInner: c} -} - -// ValidateBasic just makes sure the Fee is a valid, non-negative value -func (c Tx) ValidateBasic() error { - if !c.Fee.IsValid() { - return coin.ErrInvalidCoins() - } - if !c.Fee.IsNonnegative() { - return coin.ErrInvalidCoins() - } - return nil -} - -// Custom errors -//-------------------------------------------------------------------------------- - -var ( - errInvalidCounter = fmt.Errorf("Counter Tx marked invalid") -) - -// ErrInvalidCounter - custom error class -func ErrInvalidCounter() error { - return errors.WithCode(errInvalidCounter, abci.CodeType_BaseInvalidInput) -} - -// IsInvalidCounterErr - custom error class check -func IsInvalidCounterErr(err error) bool { - return errors.IsSameError(errInvalidCounter, err) -} - -// ErrDecoding - This is just a helper function to return a generic "internal error" -func ErrDecoding() error { - return errors.ErrInternal("Error decoding state") -} - -// Counter Handler -//-------------------------------------------------------------------------------- - -// NewHandler returns a new counter transaction processing handler -func NewHandler(feeDenom string) sdk.Handler { - return stack.New( - base.Logger{}, - stack.Recovery{}, - auth.Signatures{}, - base.Chain{}, - stack.Checkpoint{OnCheck: true}, - nonce.ReplayCheck{}, - ). - IBC(ibc.NewMiddleware()). - Apps( - roles.NewMiddleware(), - fee.NewSimpleFeeMiddleware(coin.Coin{feeDenom, 0}, fee.Bank), - stack.Checkpoint{OnDeliver: true}, - ). - Dispatch( - coin.NewHandler(), - Handler{}, - ) -} - -// Handler the counter transaction processing handler -type Handler struct { - stack.PassInitState - stack.PassInitValidate -} - -var _ stack.Dispatchable = Handler{} - -// Name - return counter namespace -func (Handler) Name() string { - return NameCounter -} - -// AssertDispatcher - placeholder to satisfy XXX -func (Handler) AssertDispatcher() {} - -// CheckTx checks if the tx is properly structured -func (h Handler) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, _ sdk.Checker) (res sdk.CheckResult, err error) { - _, err = checkTx(ctx, tx) - return -} - -// DeliverTx executes the tx if valid -func (h Handler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, dispatch sdk.Deliver) (res sdk.DeliverResult, err error) { - ctr, err := checkTx(ctx, tx) - if err != nil { - return res, err - } - // note that we don't assert this on CheckTx (ValidateBasic), - // as we allow them to be writen to the chain - if !ctr.Valid { - return res, ErrInvalidCounter() - } - - // handle coin movement.... like, actually decrement the other account - if !ctr.Fee.IsZero() { - // take the coins and put them in out account! - senders := ctx.GetPermissions("", auth.NameSigs) - if len(senders) == 0 { - return res, errors.ErrMissingSignature() - } - in := []coin.TxInput{{Address: senders[0], Coins: ctr.Fee}} - out := []coin.TxOutput{{Address: StoreActor(), Coins: ctr.Fee}} - send := coin.NewSendTx(in, out) - // if the deduction fails (too high), abort the command - _, err = dispatch.DeliverTx(ctx, store, send) - if err != nil { - return res, err - } - } - - // update the counter - state, err := LoadState(store) - if err != nil { - return res, err - } - state.Counter++ - state.TotalFees = state.TotalFees.Plus(ctr.Fee) - err = SaveState(store, state) - - return res, err -} - -func checkTx(ctx sdk.Context, tx sdk.Tx) (ctr Tx, err error) { - ctr, ok := tx.Unwrap().(Tx) - if !ok { - return ctr, errors.ErrInvalidFormat(TypeTx, tx) - } - err = ctr.ValidateBasic() - if err != nil { - return ctr, err - } - return ctr, nil -} - -// CounterStore -//-------------------------------------------------------------------------------- - -// StoreActor - return the basecoin actor for the account -func StoreActor() sdk.Actor { - return sdk.Actor{App: NameCounter, Address: []byte{0x04, 0x20}} //XXX what do these bytes represent? - should use typebyte variables -} - -// State - state of the counter applicaton -type State struct { - Counter int `json:"counter"` - TotalFees coin.Coins `json:"total_fees"` -} - -// StateKey - store key for the counter state -func StateKey() []byte { - return []byte("state") -} - -// LoadState - retrieve the counter state from the store -func LoadState(store state.SimpleDB) (state State, err error) { - bytes := store.Get(StateKey()) - if len(bytes) > 0 { - err = wire.ReadBinaryBytes(bytes, &state) - if err != nil { - return state, errors.ErrDecoding() - } - } - return state, nil -} - -// SaveState - save the counter state to the provided store -func SaveState(store state.SimpleDB, state State) error { - bytes := wire.BinaryBytes(state) - store.Set(StateKey(), bytes) - return nil -} diff --git a/_attic/examples/counter/plugins/counter/counter_test.go b/_attic/examples/counter/plugins/counter/counter_test.go deleted file mode 100644 index 5c1ef254a2..0000000000 --- a/_attic/examples/counter/plugins/counter/counter_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package counter - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/abci/types" - "github.com/tendermint/go-wire" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/app" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/base" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/modules/nonce" -) - -func TestCounterPlugin(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - // Basecoin initialization - chainID := "test_chain_id" - logger := log.TestingLogger() - // logger := log.NewTracingLogger(log.NewTMLogger(os.Stdout)) - - h := NewHandler("gold") - store, err := app.MockStoreApp("counter", logger) - require.Nil(err, "%+v", err) - bcApp := app.NewBaseApp(store, h, nil) - err = bcApp.InitState("base", "chain_id", chainID) - require.Nil(err, "%+v", err) - - // Account initialization - bal := coin.Coins{{"", 1000}, {"gold", 1000}} - acct := coin.NewAccountWithKey(bal) - err = bcApp.InitState("coin", "account", acct.MakeOption()) - require.Nil(err, "%+v", err) - - // Deliver a CounterTx - DeliverCounterTx := func(valid bool, counterFee coin.Coins, sequence uint32) abci.Result { - tx := NewTx(valid, counterFee) - tx = nonce.NewTx(sequence, []sdk.Actor{acct.Actor()}, tx) - tx = base.NewChainTx(chainID, 0, tx) - stx := auth.NewSig(tx) - auth.Sign(stx, acct.Key) - txBytes := wire.BinaryBytes(stx.Wrap()) - return bcApp.DeliverTx(txBytes) - } - - // Test a basic send, no fee - res := DeliverCounterTx(true, nil, 1) - assert.True(res.IsOK(), res.String()) - - // Test an invalid send, no fee - res = DeliverCounterTx(false, nil, 2) - assert.True(res.IsErr(), res.String()) - - // Test an invalid sequence - res = DeliverCounterTx(true, nil, 2) - assert.True(res.IsErr(), res.String()) - - // Test an valid send, with supported fee - res = DeliverCounterTx(true, coin.Coins{{"gold", 100}}, 3) - assert.True(res.IsOK(), res.String()) - - // Test unsupported fee - res = DeliverCounterTx(true, coin.Coins{{"silver", 100}}, 4) - assert.True(res.IsErr(), res.String()) -} diff --git a/_attic/examples/counter/tests/cli/counter.sh b/_attic/examples/counter/tests/cli/counter.sh deleted file mode 100755 index f1c9a4c05d..0000000000 --- a/_attic/examples/counter/tests/cli/counter.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/bash - -# These global variables are required for common.sh -SERVER_EXE=counter -CLIENT_EXE=countercli -ACCOUNTS=(jae ethan bucky rigel igor) -RICH=${ACCOUNTS[0]} -POOR=${ACCOUNTS[4]} - -oneTimeSetUp() { - if ! quickSetup .basecoin_test_counter counter-chain; then - exit 1; - fi -} - -oneTimeTearDown() { - quickTearDown -} - -test00GetAccount() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - assertFalse "Line=${LINENO}, requires arg" "${CLIENT_EXE} query account" - - checkAccount $SENDER "9007199254740992" - - ACCT2=$(${CLIENT_EXE} query account $RECV 2>/dev/null) - assertFalse "Line=${LINENO}, has no genesis account" $? -} - -test01SendTx() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - # sequence should work well for first time also - assertFalse "Line=${LINENO}, missing dest" "${CLIENT_EXE} tx send --amount=992mycoin 2>/dev/null" - assertFalse "Line=${LINENO}, bad password" "echo foo | ${CLIENT_EXE} tx send --amount=992mycoin --to=$RECV --name=$RICH 2>/dev/null" - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --to=$RECV --name=$RICH) - txSucceeded $? "$TX" "$RECV" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - checkAccount $SENDER "9007199254740000" "$TX_HEIGHT" - checkAccount $RECV "992" "$TX_HEIGHT" - - # make sure tx is indexed - checkSendTx $HASH $TX_HEIGHT $SENDER "992" -} - -test02GetCounter() { - COUNT=$(${CLIENT_EXE} query counter 2>/dev/null) - assertFalse "Line=${LINENO}, no default count" $? -} - -# checkCounter $COUNT $BALANCE [$HEIGHT] -# Assumes just one coin, checks the balance of first coin in any case -# pass optional height to query which block to query -checkCounter() { - # default height of 0, but accept an argument - HEIGHT=${3:-0} - - # make sure sender goes down - ACCT=$(${CLIENT_EXE} query counter --height=$HEIGHT) - if assertTrue "Line=${LINENO}, count is set" $?; then - assertEquals "Line=${LINENO}, proper count" "$1" $(echo $ACCT | jq .data.counter) - assertEquals "Line=${LINENO}, proper money" "$2" $(echo $ACCT | jq .data.total_fees[0].amount) - fi -} - -test03AddCount() { - SENDER=$(getAddr $RICH) - assertFalse "Line=${LINENO}, bad password" "echo hi | ${CLIENT_EXE} tx counter --countfee=100mycoin --sequence=2 --name=${RICH} 2>/dev/null" - - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --countfee=10mycoin --sequence=2 --name=${RICH} --valid) - txSucceeded $? "$TX" "counter" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - # make sure the counter was updated - checkCounter "1" "10" "$TX_HEIGHT" - - # make sure the account was debited - checkAccount $SENDER "9007199254739990" "$TX_HEIGHT" - - # make sure tx is indexed - TX=$(${CLIENT_EXE} query tx $HASH --trace) - if assertTrue "Line=${LINENO}, found tx" $?; then - assertEquals "Line=${LINENO}, proper height" $TX_HEIGHT $(echo $TX | jq .height) - assertEquals "Line=${LINENO}, type=sigs/one" '"sigs/one"' $(echo $TX | jq .data.type) - CTX=$(echo $TX | jq .data.data.tx) - assertEquals "Line=${LINENO}, type=chain/tx" '"chain/tx"' $(echo $CTX | jq .type) - NTX=$(echo $CTX | jq .data.tx) - assertEquals "line=${LINENO}, type=nonce" '"nonce"' $(echo $NTX | jq .type) - CNTX=$(echo $NTX | jq .data.tx) - assertEquals "Line=${LINENO}, type=cntr/count" '"cntr/count"' $(echo $CNTX | jq .type) - assertEquals "Line=${LINENO}, proper fee" "10" $(echo $CNTX | jq .data.fee[0].amount) - fi - - # test again with fees... - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --countfee=7mycoin --fee=4mycoin --sequence=3 --name=${RICH} --valid) - txSucceeded $? "$TX" "counter" - TX_HEIGHT=$(echo $TX | jq .height) - - # make sure the counter was updated, added 7 - checkCounter "2" "17" "$TX_HEIGHT" - # make sure the account was debited 11 - checkAccount $SENDER "9007199254739979" "$TX_HEIGHT" - - # make sure we cannot replay the counter, no state change - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --countfee=10mycoin --sequence=2 --name=${RICH} --valid 2>/dev/null) - assertFalse "line=${LINENO}, replay: $TX" $? - TX_HEIGHT=$(echo $TX | jq .height) - - checkCounter "2" "17" "$TX_HEIGHT" - checkAccount $SENDER "9007199254739979" "$TX_HEIGHT" -} - -# Load common then run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 diff --git a/_attic/examples/eyes/Makefile b/_attic/examples/eyes/Makefile deleted file mode 100644 index e543a4ccf0..0000000000 --- a/_attic/examples/eyes/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -LINKER_FLAGS:="-X github.com/cosmos/cosmos-sdk/client/commands.CommitHash=`git rev-parse --short HEAD`" - -install: - @go install -ldflags $(LINKER_FLAGS) ./cmd/... - -test: test_unit test_cli - -test_unit: - @go test `glide novendor` - -test_cli: - ./tests/cli/eyes.sh - -.PHONY: install test test_unit test_cli diff --git a/_attic/examples/eyes/cmd/eyes/init.go b/_attic/examples/eyes/cmd/eyes/init.go deleted file mode 100644 index 29e682193b..0000000000 --- a/_attic/examples/eyes/cmd/eyes/init.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - - "github.com/cosmos/cosmos-sdk/server/commands" -) - -// InitCmd - node initialization command -var InitCmd = &cobra.Command{ - Use: "init", - Short: "Initialize eyes abci server", - RunE: initCmd, -} - -//nolint - flags -var ( - FlagChainID = "chain-id" //TODO group with other flags or remove? is this already a flag here? -) - -func init() { - InitCmd.Flags().String(FlagChainID, "eyes_test_id", "Chain ID") -} - -func initCmd(cmd *cobra.Command, args []string) error { - // this will ensure that config.toml is there if not yet created, and create dir - cfg, err := tcmd.ParseConfig() - if err != nil { - return err - } - - genesis := getGenesisJSON(viper.GetString(commands.FlagChainID)) - return commands.CreateGenesisValidatorFiles(cfg, genesis, commands.StaticPrivValJSON, cmd.Root().Name()) -} - -// TODO: better, auto-generate validator... -func getGenesisJSON(chainID string) string { - return fmt.Sprintf(`{ - "app_hash": "", - "chain_id": "%s", - "genesis_time": "0001-01-01T00:00:00.000Z", - "validators": [ - { - "power": 10, - "name": "", - "pub_key": { - "type": "ed25519", - "data": "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30" - } - } - ] -}`, chainID) -} diff --git a/_attic/examples/eyes/cmd/eyes/main.go b/_attic/examples/eyes/cmd/eyes/main.go deleted file mode 100644 index df30fc9213..0000000000 --- a/_attic/examples/eyes/cmd/eyes/main.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - "github.com/tendermint/tmlibs/cli" - - sdk "github.com/cosmos/cosmos-sdk" - client "github.com/cosmos/cosmos-sdk/client/commands" - eyesmod "github.com/cosmos/cosmos-sdk/modules/eyes" - "github.com/cosmos/cosmos-sdk/server/commands" - "github.com/cosmos/cosmos-sdk/util" - - "github.com/cosmos/cosmos-sdk/examples/eyes" -) - -// RootCmd is the entry point for this binary -var RootCmd = &cobra.Command{ - Use: "eyes", - Short: "key-value store", - Long: "A demo app to show key-value store with proofs over abci", -} - -// BuildApp constructs the stack we want to use for this app -func BuildApp() sdk.Handler { - return sdk.ChainDecorators( - util.Logger{}, - util.Recovery{}, - eyes.Parser{}, - util.Chain{}, - ).WithHandler( - eyesmod.NewHandler(), - ) -} - -func main() { - commands.Handler = BuildApp() - - RootCmd.AddCommand( - // out own init command to not require argument - InitCmd, - commands.StartCmd, - commands.UnsafeResetAllCmd, - client.VersionCmd, - ) - commands.SetUpRoot(RootCmd) - - cmd := cli.PrepareMainCmd(RootCmd, "EYE", os.ExpandEnv("$HOME/.eyes")) - cmd.Execute() -} diff --git a/_attic/examples/eyes/cmd/eyescli/main.go b/_attic/examples/eyes/cmd/eyescli/main.go deleted file mode 100644 index d23a0e8dc3..0000000000 --- a/_attic/examples/eyes/cmd/eyescli/main.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - - "github.com/tendermint/tmlibs/cli" - - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/auto" - "github.com/cosmos/cosmos-sdk/client/commands/commits" - "github.com/cosmos/cosmos-sdk/client/commands/query" - rpccmd "github.com/cosmos/cosmos-sdk/client/commands/rpc" - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - eyescmd "github.com/cosmos/cosmos-sdk/modules/eyes/commands" -) - -// EyesCli - main basecoin client command -var EyesCli = &cobra.Command{ - Use: "eyescli", - Short: "Light client for Tendermint", - Long: `EyesCli is the light client for a merkle key-value store (eyes)`, -} - -func main() { - commands.AddBasicFlags(EyesCli) - - // Prepare queries - query.RootCmd.AddCommand( - // These are default parsers, but optional in your app (you can remove key) - query.TxQueryCmd, - query.KeyQueryCmd, - // this is our custom parser - eyescmd.EyesQueryCmd, - ) - - // no middleware wrapers - txcmd.Middleware = txcmd.Wrappers{} - // txcmd.Middleware.Register(txcmd.RootCmd.PersistentFlags()) - - // just the etc commands - txcmd.RootCmd.AddCommand( - eyescmd.SetTxCmd, - eyescmd.RemoveTxCmd, - ) - - // Set up the various commands to use - EyesCli.AddCommand( - // we use out own init command to not require address arg - commands.InitCmd, - commands.ResetCmd, - commits.RootCmd, - rpccmd.RootCmd, - query.RootCmd, - txcmd.RootCmd, - commands.VersionCmd, - auto.AutoCompleteCmd, - ) - - cmd := cli.PrepareMainCmd(EyesCli, "EYE", os.ExpandEnv("$HOME/.eyescli")) - cmd.Execute() -} diff --git a/_attic/examples/eyes/parser.go b/_attic/examples/eyes/parser.go deleted file mode 100644 index b8dd908ebe..0000000000 --- a/_attic/examples/eyes/parser.go +++ /dev/null @@ -1,32 +0,0 @@ -package eyes - -import sdk "github.com/cosmos/cosmos-sdk" - -// Parser converts bytes into a tx struct -type Parser struct{} - -var _ sdk.Decorator = Parser{} - -// CheckTx makes sure we are on the proper chain -// - fulfills Decorator interface -func (c Parser) CheckTx(ctx sdk.Context, store sdk.SimpleDB, - txBytes interface{}, next sdk.Checker) (res sdk.CheckResult, err error) { - - tx, err := LoadTx(txBytes.([]byte)) - if err != nil { - return res, err - } - return next.CheckTx(ctx, store, tx) -} - -// DeliverTx makes sure we are on the proper chain -// - fulfills Decorator interface -func (c Parser) DeliverTx(ctx sdk.Context, store sdk.SimpleDB, - txBytes interface{}, next sdk.Deliverer) (res sdk.DeliverResult, err error) { - - tx, err := LoadTx(txBytes.([]byte)) - if err != nil { - return res, err - } - return next.DeliverTx(ctx, store, tx) -} diff --git a/_attic/examples/eyes/tests/cli/eyes.sh b/_attic/examples/eyes/tests/cli/eyes.sh deleted file mode 100755 index bd3b0dc7fa..0000000000 --- a/_attic/examples/eyes/tests/cli/eyes.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -# These global variables are required for common.sh -SERVER_EXE=eyes -CLIENT_EXE=eyescli - -oneTimeSetUp() { - # These are passed in as args - BASE_DIR=$HOME/.test_eyes - CHAIN_ID="eyes-cli-test" - - rm -rf $BASE_DIR 2>/dev/null - mkdir -p $BASE_DIR - - echo "Setting up genesis..." - SERVE_DIR=${BASE_DIR}/server - SERVER_LOG=${BASE_DIR}/${SERVER_EXE}.log - - echo "Starting ${SERVER_EXE} server..." - export EYE_HOME=${SERVE_DIR} - ${SERVER_EXE} init --chain-id=$CHAIN_ID >>$SERVER_LOG - startServer $SERVE_DIR $SERVER_LOG - [ $? = 0 ] || return 1 - - # Set up client - make sure you use the proper prefix if you set - # a custom CLIENT_EXE - export EYE_HOME=${BASE_DIR}/client - - initClient $CHAIN_ID - [ $? = 0 ] || return 1 - - printf "...Testing may begin!\n\n\n" -} - -oneTimeTearDown() { - quickTearDown -} - -test00SetGetRemove() { - KEY="CAFE6000" - VALUE="F00D4200" - - assertFalse "line=${LINENO} data present" "${CLIENT_EXE} query eyes ${KEY}" - - # set data - TXRES=$(${CLIENT_EXE} tx set --key=${KEY} --value=${VALUE}) - txSucceeded $? "$TXRES" "set cafe" - HASH=$(echo $TXRES | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TXRES | jq .height) - - # make sure it is set - DATA=$(${CLIENT_EXE} query eyes ${KEY} --height=$TX_HEIGHT) - assertTrue "line=${LINENO} data not set" $? - assertEquals "line=${LINENO}" "\"${VALUE}\"" $(echo $DATA | jq .data.value) - - # query the tx - TX=$(${CLIENT_EXE} query tx $HASH) - assertTrue "line=${LINENO}, found tx" $? - if [ -n "$DEBUG" ]; then echo $TX; echo; fi - - assertEquals "line=${LINENO}, proper type" "\"eyes/set\"" $(echo $TX | jq .data.type) - assertEquals "line=${LINENO}, proper key" "\"${KEY}\"" $(echo $TX | jq .data.data.key) - assertEquals "line=${LINENO}, proper value" "\"${VALUE}\"" $(echo $TX | jq .data.data.value) -} - - -# Load common then run these tests with shunit2! -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory -CLI_DIR=$GOPATH/src/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 - diff --git a/_attic/examples/eyes/tx.go b/_attic/examples/eyes/tx.go deleted file mode 100644 index 41db195042..0000000000 --- a/_attic/examples/eyes/tx.go +++ /dev/null @@ -1,33 +0,0 @@ -package eyes - -import ( - wire "github.com/tendermint/go-wire" - - eyesmod "github.com/cosmos/cosmos-sdk/modules/eyes" - "github.com/cosmos/cosmos-sdk/util" -) - -// Tx is what is submitted to the chain. -// This embeds the tx data along with any info we want for -// decorators (just chain for now to demo) -type Tx struct { - Tx eyesmod.EyesTx `json:"tx"` - Chain util.ChainData `json:"chain"` -} - -// GetTx gets the tx info -func (e Tx) GetTx() interface{} { - return e.Tx -} - -// GetChain gets the chain we wish to perform the tx on -// (info for decorators) -func (e Tx) GetChain() util.ChainData { - return e.Chain -} - -// LoadTx parses the input data into our blockchain tx structure -func LoadTx(data []byte) (tx Tx, err error) { - err = wire.ReadBinaryBytes(data, &tx) - return -} diff --git a/_attic/genesis/doc.go b/_attic/genesis/doc.go deleted file mode 100644 index 40636fc078..0000000000 --- a/_attic/genesis/doc.go +++ /dev/null @@ -1,61 +0,0 @@ -/* -Package genesis provides some utility functions for parsing -a standard genesis file to initialize your abci application. - -We wish to support using one genesis file to initialize both -tendermint and the application, so this file format is designed -to be embedable in the tendermint genesis.json file. We reuse -the same chain_id field for tendermint, ignore the other fields, -and add a special app_options field that contains information just -for the abci app (and ignored by tendermint). - -The use of this file format for your application is not required by -the sdk and is only used by default in the start command, if you wish -to write your own start command, you can use any other method to -store and parse options for your abci application. The important part is -that the same data is available on every node. - -Example file format: - - { - "chain_id": "foo_bar_chain", - "app_options": { - "accounts": [{ - "address": "C471FB670E44D219EE6DF2FC284BE38793ACBCE1", - "pub_key": { - "type": "ed25519", - "data": "6880DB93598E283A67C4D88FC67A8858AA2DE70F713FE94A5109E29C137100C2" - }, - "coins": [ - { - "denom": "ETH", - "amount": 654321 - } - ] - }], - "plugin_options": [ - "plugin1/key1", "value1", - "profile/set", {"name": "john", age: 37} - ] - } - } - -Note that there are two subfields under app_options. The first one "accounts" -is a special case for the coin module, which is assumed to be used by most -applications. It is simply a list of accounts with an identifier and their -initial balance. The account must be identified by EITHER an address -(20 bytes in hex) or a pubkey (in the go-crypto json format), not both as in -this example. "coins" defines the initial balance of the account. - -Configuration options for every other module should be placed under -"plugin_options" as key value pairs (there must be an even number of items). -The first value must be "/" to define the option to be set. -The second value is parsed as raw json and is the value to pass to the -application. This may be a string, an array, a map or any other valid json -structure that the module can parse. - -Note that we don't use a map for plugin_options, as we will often wish -to have many values for the same key, to run this setup many times, -just as we support setting many accounts. -*/ -package genesis diff --git a/_attic/genesis/parse.go b/_attic/genesis/parse.go deleted file mode 100644 index e447ac0bc4..0000000000 --- a/_attic/genesis/parse.go +++ /dev/null @@ -1,153 +0,0 @@ -package genesis - -import ( - "encoding/json" - "strings" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/pkg/errors" - - cmn "github.com/tendermint/tmlibs/common" -) - -// KeyDelimiter is used to separate module and key in -// the options -const KeyDelimiter = "/" - -// Option just holds module/key/value triples from -// parsing the genesis file -type Option struct { - Module string - Key string - Value string -} - -// InitStater is anything that can handle app options -// from genesis file. Setting the merkle store, config options, -// or anything else -type InitStater interface { - InitState(module, key, value string) error -} - -// Load parses the genesis file and sets the initial -// state based on that -func Load(app InitStater, filePath string) error { - opts, err := GetOptions(filePath) - if err != nil { - return err - } - - // execute all the genesis init options - // abort on any error - for _, opt := range opts { - err = app.InitState(opt.Module, opt.Key, opt.Value) - if err != nil { - return err - } - } - return nil -} - -// GetOptions parses the genesis file in a format -// that can easily be handed into InitStaters -func GetOptions(path string) ([]Option, error) { - genDoc, err := load(path) - if err != nil { - return nil, err - } - - opts := genDoc.AppOptions - cnt := 1 + len(opts.Accounts) + len(opts.pluginOptions) - res := make([]Option, 0, cnt) - res = append(res, Option{sdk.ModuleNameBase, sdk.ChainKey, genDoc.ChainID}) - - // set accounts - for _, acct := range opts.Accounts { - res = append(res, Option{"coin", "account", string(acct)}) - } - - // set plugin options - for _, kv := range opts.pluginOptions { - module, key := splitKey(kv.Key) - res = append(res, Option{module, key, kv.Value}) - } - - return res, nil -} - -type keyValue struct { - Key string `json:"key"` - Value string `json:"value"` -} - -// FullDoc - includes tendermint (in the json, we ignore here) -type FullDoc struct { - ChainID string `json:"chain_id"` - AppOptions *Doc `json:"app_options"` -} - -// Doc - All genesis values -type Doc struct { - Accounts []json.RawMessage `json:"accounts"` - PluginOptions []json.RawMessage `json:"plugin_options"` - - pluginOptions []keyValue // unmarshaled rawmessages -} - -func load(filePath string) (*FullDoc, error) { - bytes, err := cmn.ReadFile(filePath) - if err != nil { - return nil, errors.Wrap(err, "loading genesis file") - } - - // the basecoin genesis go-wire/data :) - genDoc := new(FullDoc) - err = json.Unmarshal(bytes, genDoc) - if err != nil { - return nil, errors.Wrap(err, "unmarshaling genesis file") - } - - if genDoc.AppOptions == nil { - genDoc.AppOptions = new(Doc) - } - - pluginOpts, err := parseList(genDoc.AppOptions.PluginOptions) - if err != nil { - return nil, err - } - genDoc.AppOptions.pluginOptions = pluginOpts - return genDoc, nil -} - -func parseList(kvzIn []json.RawMessage) (kvz []keyValue, err error) { - if len(kvzIn)%2 != 0 { - return nil, errors.New("genesis cannot have an odd number of items. Format = [key1, value1, key2, value2, ...]") - } - - for i := 0; i < len(kvzIn); i += 2 { - kv := keyValue{} - rawK := []byte(kvzIn[i]) - err := json.Unmarshal(rawK, &(kv.Key)) - if err != nil { - return nil, errors.Errorf("Non-string key: %s", string(rawK)) - } - // convert value to string if possible (otherwise raw json) - rawV := kvzIn[i+1] - err = json.Unmarshal(rawV, &(kv.Value)) - if err != nil { - kv.Value = string(rawV) - } - kvz = append(kvz, kv) - } - return kvz, nil -} - -// Splits the string at the first '/'. -// if there are none, assign default module ("base"). -func splitKey(key string) (string, string) { - if strings.Contains(key, KeyDelimiter) { - keyParts := strings.SplitN(key, KeyDelimiter, 2) - return keyParts[0], keyParts[1] - } - return sdk.ModuleNameBase, key -} diff --git a/_attic/genesis/parse_test.go b/_attic/genesis/parse_test.go deleted file mode 100644 index 822e2630ac..0000000000 --- a/_attic/genesis/parse_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package genesis - -import ( - "encoding/json" - "testing" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - cmn "github.com/tendermint/tmlibs/common" -) - -const genesisFilepath = "./testdata/genesis.json" - -func TestParseList(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - bytes, err := cmn.ReadFile(genesisFilepath) - require.Nil(err, "loading genesis file %+v", err) - - // the basecoin genesis go-wire/data :) - genDoc := new(FullDoc) - err = json.Unmarshal(bytes, genDoc) - require.Nil(err, "unmarshaling genesis file %+v", err) - - pluginOpts, err := parseList(genDoc.AppOptions.PluginOptions) - require.Nil(err, "%+v", err) - genDoc.AppOptions.pluginOptions = pluginOpts - - assert.Equal(genDoc.AppOptions.pluginOptions[0].Key, "plugin1/key1") - assert.Equal(genDoc.AppOptions.pluginOptions[1].Key, "plugin1/key2") - assert.Equal(genDoc.AppOptions.pluginOptions[0].Value, "value1") - assert.Equal(genDoc.AppOptions.pluginOptions[1].Value, "value2") -} - -func TestGetOptions(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - opts, err := GetOptions(genesisFilepath) - require.Nil(err, "loading genesis file %+v", err) - - require.Equal(4, len(opts)) - chain := opts[0] - assert.Equal(sdk.ModuleNameBase, chain.Module) - assert.Equal(sdk.ChainKey, chain.Key) - assert.Equal("foo_bar_chain", chain.Value) - - acct := opts[1] - assert.Equal("coin", acct.Module) - assert.Equal("account", acct.Key) - - p1 := opts[2] - assert.Equal("plugin1", p1.Module) - assert.Equal("key1", p1.Key) - assert.Equal("value1", p1.Value) - - p2 := opts[3] - assert.Equal("plugin1", p2.Module) - assert.Equal("key2", p2.Key) - assert.Equal("value2", p2.Value) -} - -func TestSplitKey(t *testing.T) { - assert := assert.New(t) - prefix, suffix := splitKey("foo/bar") - assert.EqualValues("foo", prefix) - assert.EqualValues("bar", suffix) - - prefix, suffix = splitKey("foobar") - assert.EqualValues("base", prefix) - assert.EqualValues("foobar", suffix) - - prefix, suffix = splitKey("some/complex/issue") - assert.EqualValues("some", prefix) - assert.EqualValues("complex/issue", suffix) - -} diff --git a/_attic/genesis/testdata/genesis.json b/_attic/genesis/testdata/genesis.json deleted file mode 100644 index ee8879fd28..0000000000 --- a/_attic/genesis/testdata/genesis.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "chain_id": "foo_bar_chain", - "app_options": { - "accounts": [{ - "pub_key": { - "type": "ed25519", - "data": "6880db93598e283a67c4d88fc67a8858aa2de70f713fe94a5109e29c137100c2" - }, - "coins": [ - { - "denom": "blank", - "amount": 12345 - }, - { - "denom": "ETH", - "amount": 654321 - } - ] - }], - "plugin_options": ["plugin1/key1", "value1", "plugin1/key2", "value2"] - } -} diff --git a/_attic/modules/app/app_test.go b/_attic/modules/app/app_test.go deleted file mode 100644 index 13f21bab89..0000000000 --- a/_attic/modules/app/app_test.go +++ /dev/null @@ -1,292 +0,0 @@ -package app - -// import ( -// "encoding/hex" -// "testing" - -// "github.com/stretchr/testify/assert" -// "github.com/stretchr/testify/require" - -// sdk "github.com/cosmos/cosmos-sdk" -// "github.com/cosmos/cosmos-sdk/modules/auth" -// "github.com/cosmos/cosmos-sdk/modules/base" -// "github.com/cosmos/cosmos-sdk/modules/coin" -// "github.com/cosmos/cosmos-sdk/modules/fee" -// "github.com/cosmos/cosmos-sdk/modules/nonce" -// "github.com/cosmos/cosmos-sdk/stack" -// "github.com/cosmos/cosmos-sdk/state" -// "github.com/cosmos/cosmos-sdk/util" -// abci "github.com/tendermint/abci/types" -// wire "github.com/tendermint/go-wire" -// "github.com/tendermint/tmlibs/log" -// ) - -// // DefaultHandler for the tests (coin, roles, ibc) -// func DefaultHandler(feeDenom string) sdk.Handler { -// // use the default stack -// // r := roles.NewHandler() -// // i := ibc.NewHandler() - -// return sdk.ChainDecorators( -// util.Logger{}, -// util.Recovery{}, -// auth.Signatures{}, -// util.Chain{}, -// // stack.Checkpoint{OnCheck: true}, -// // nonce.ReplayCheck{}, -// ). -// // IBC(ibc.NewMiddleware()). -// // Apps( -// // roles.NewMiddleware(), -// // fee.NewSimpleFeeMiddleware(coin.Coin{feeDenom, 0}, fee.Bank), -// // stack.Checkpoint{OnDeliver: true}, -// // ). -// WithHandler( -// coin.NewHandler(), -// // stack.WrapHandler(r), -// // stack.WrapHandler(i), -// ) -// } - -// //-------------------------------------------------------- -// // test environment is a list of input and output accounts - -// type appTest struct { -// t *testing.T -// chainID string -// app *BaseApp -// acctIn *coin.AccountWithKey -// acctOut *coin.AccountWithKey -// } - -// func newAppTest(t *testing.T) *appTest { -// at := &appTest{ -// t: t, -// chainID: "test_chain_id", -// } -// at.reset() -// return at -// } - -// // baseTx is the -// func (at *appTest) baseTx(coins coin.Coins) sdk.Tx { -// in := []coin.TxInput{{Address: at.acctIn.Actor(), Coins: coins}} -// out := []coin.TxOutput{{Address: at.acctOut.Actor(), Coins: coins}} -// tx := coin.NewSendTx(in, out) -// return tx -// } - -// func (at *appTest) signTx(tx sdk.Tx) sdk.Tx { -// stx := auth.NewMulti(tx) -// auth.Sign(stx, at.acctIn.Key) -// return stx.Wrap() -// } - -// func (at *appTest) getTx(coins coin.Coins, sequence uint32) sdk.Tx { -// tx := at.baseTx(coins) -// tx = nonce.NewTx(sequence, []sdk.Actor{at.acctIn.Actor()}, tx) -// tx = base.NewChainTx(at.chainID, 0, tx) -// return at.signTx(tx) -// } - -// func (at *appTest) feeTx(coins coin.Coins, toll coin.Coin, sequence uint32) sdk.Tx { -// tx := at.baseTx(coins) -// tx = fee.NewFee(tx, toll, at.acctIn.Actor()) -// tx = nonce.NewTx(sequence, []sdk.Actor{at.acctIn.Actor()}, tx) -// tx = base.NewChainTx(at.chainID, 0, tx) -// return at.signTx(tx) -// } - -// // set the account on the app through InitState -// func (at *appTest) initAccount(acct *coin.AccountWithKey) { -// err := at.app.InitState("coin", "account", acct.MakeOption()) -// require.Nil(at.t, err, "%+v", err) -// } - -// // reset the in and out accs to be one account each with 7mycoin -// func (at *appTest) reset() { -// at.acctIn = coin.NewAccountWithKey(coin.Coins{{"mycoin", 7}}) -// at.acctOut = coin.NewAccountWithKey(coin.Coins{{"mycoin", 7}}) - -// // Note: switch logger if you want to get more info -// logger := log.TestingLogger() -// // logger := log.NewTracingLogger(log.NewTMLogger(os.Stdout)) - -// store, err := NewStoreApp("app-test", "", 0, logger) -// require.Nil(at.t, err, "%+v", err) -// at.app = NewBaseApp(store, DefaultHandler("mycoin"), nil) - -// err = at.app.InitState("base", "chain_id", at.chainID) -// require.Nil(at.t, err, "%+v", err) - -// at.initAccount(at.acctIn) -// at.initAccount(at.acctOut) - -// resabci := at.app.Commit() -// require.True(at.t, resabci.IsOK(), resabci) -// } - -// func getBalance(key sdk.Actor, store state.SimpleDB) (coin.Coins, error) { -// cspace := stack.PrefixedStore(coin.NameCoin, store) -// acct, err := coin.GetAccount(cspace, key) -// return acct.Coins, err -// } - -// func getAddr(addr []byte, state state.SimpleDB) (coin.Coins, error) { -// actor := auth.SigPerm(addr) -// return getBalance(actor, state) -// } - -// // returns the final balance and expected balance for input and output accounts -// func (at *appTest) exec(t *testing.T, tx sdk.Tx, checkTx bool) (res abci.Result, diffIn, diffOut coin.Coins) { -// require := require.New(t) - -// initBalIn, err := getBalance(at.acctIn.Actor(), at.app.Append()) -// require.Nil(err, "%+v", err) -// initBalOut, err := getBalance(at.acctOut.Actor(), at.app.Append()) -// require.Nil(err, "%+v", err) - -// txBytes := wire.BinaryBytes(tx) -// if checkTx { -// res = at.app.CheckTx(txBytes) -// } else { -// res = at.app.DeliverTx(txBytes) -// } - -// endBalIn, err := getBalance(at.acctIn.Actor(), at.app.Append()) -// require.Nil(err, "%+v", err) -// endBalOut, err := getBalance(at.acctOut.Actor(), at.app.Append()) -// require.Nil(err, "%+v", err) -// return res, endBalIn.Minus(initBalIn), endBalOut.Minus(initBalOut) -// } - -// //-------------------------------------------------------- - -// func TestInitState(t *testing.T) { -// assert := assert.New(t) -// require := require.New(t) - -// logger := log.TestingLogger() -// store, err := NewStoreApp("app-test", "", 0, logger) -// require.Nil(err, "%+v", err) -// app := NewBaseApp(store, DefaultHandler("atom"), nil) - -// //testing ChainID -// chainID := "testChain" -// err = app.InitState("base", "chain_id", chainID) -// require.Nil(err, "%+v", err) -// assert.EqualValues(app.GetChainID(), chainID) - -// // make a nice account... -// bal := coin.Coins{{"atom", 77}, {"eth", 12}} -// acct := coin.NewAccountWithKey(bal) -// err = app.InitState("coin", "account", acct.MakeOption()) -// require.Nil(err, "%+v", err) - -// // make sure it is set correctly, with some balance -// coins, err := getBalance(acct.Actor(), app.Append()) -// require.Nil(err) -// assert.Equal(bal, coins) - -// // let's parse an account with badly sorted coins... -// unsortAddr, err := hex.DecodeString("C471FB670E44D219EE6DF2FC284BE38793ACBCE1") -// require.Nil(err) -// unsortCoins := coin.Coins{{"BTC", 789}, {"eth", 123}} -// unsortAcc := `{ -// "pub_key": { -// "type": "ed25519", -// "data": "AD084F0572C116D618B36F2EB08240D1BAB4B51716CCE0E7734B89C8936DCE9A" -// }, -// "coins": [ -// { -// "denom": "eth", -// "amount": 123 -// }, -// { -// "denom": "BTC", -// "amount": 789 -// } -// ] -// }` -// err = app.InitState("coin", "account", unsortAcc) -// require.Nil(err, "%+v", err) - -// coins, err = getAddr(unsortAddr, app.Append()) -// require.Nil(err) -// assert.True(coins.IsValid()) -// assert.Equal(unsortCoins, coins) - -// err = app.InitState("base", "dslfkgjdas", "") -// require.Error(err) - -// err = app.InitState("", "dslfkgjdas", "") -// require.Error(err) - -// err = app.InitState("dslfkgjdas", "szfdjzs", "") -// require.Error(err) -// } - -// // Test CheckTx and DeliverTx with insufficient and sufficient balance -// func TestTx(t *testing.T) { -// assert := assert.New(t) -// at := newAppTest(t) - -// //Bad Balance -// at.acctIn.Coins = coin.Coins{{"mycoin", 2}} -// at.initAccount(at.acctIn) -// at.app.Commit() - -// res, _, _ := at.exec(t, at.getTx(coin.Coins{{"mycoin", 5}}, 1), true) -// assert.True(res.IsErr(), "ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res) -// res, diffIn, diffOut := at.exec(t, at.getTx(coin.Coins{{"mycoin", 5}}, 1), false) -// assert.True(res.IsErr(), "ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res) -// assert.True(diffIn.IsZero()) -// assert.True(diffOut.IsZero()) - -// //Regular CheckTx -// at.reset() -// res, _, _ = at.exec(t, at.getTx(coin.Coins{{"mycoin", 5}}, 1), true) -// assert.True(res.IsOK(), "ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res) - -// //Regular DeliverTx -// at.reset() -// amt := coin.Coins{{"mycoin", 3}} -// res, diffIn, diffOut = at.exec(t, at.getTx(amt, 1), false) -// assert.True(res.IsOK(), "ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res) -// assert.Equal(amt.Negative(), diffIn) -// assert.Equal(amt, diffOut) - -// //DeliverTx with fee.... 4 get to recipient, 1 extra taxed -// at.reset() -// amt = coin.Coins{{"mycoin", 4}} -// toll := coin.Coin{"mycoin", 1} -// res, diffIn, diffOut = at.exec(t, at.feeTx(amt, toll, 1), false) -// assert.True(res.IsOK(), "ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res) -// payment := amt.Plus(coin.Coins{toll}).Negative() -// assert.Equal(payment, diffIn) -// assert.Equal(amt, diffOut) - -// } - -// func TestQuery(t *testing.T) { -// assert := assert.New(t) -// at := newAppTest(t) - -// res, _, _ := at.exec(t, at.getTx(coin.Coins{{"mycoin", 5}}, 1), false) -// assert.True(res.IsOK(), "Commit, DeliverTx: Expected OK return from DeliverTx, Error: %v", res) - -// resQueryPreCommit := at.app.Query(abci.RequestQuery{ -// Path: "/account", -// Data: at.acctIn.Address(), -// }) - -// res = at.app.Commit() -// assert.True(res.IsOK(), res) - -// key := stack.PrefixedKey(coin.NameCoin, at.acctIn.Address()) -// resQueryPostCommit := at.app.Query(abci.RequestQuery{ -// Path: "/key", -// Data: key, -// }) -// assert.NotEqual(resQueryPreCommit, resQueryPostCommit, "Query should change before/after commit") -// } diff --git a/_attic/modules/app/genesis_test.go b/_attic/modules/app/genesis_test.go deleted file mode 100644 index a519bc9982..0000000000 --- a/_attic/modules/app/genesis_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package app - -import ( - "encoding/hex" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/tendermint/tmlibs/log" - - "github.com/cosmos/cosmos-sdk/genesis" - "github.com/cosmos/cosmos-sdk/modules/coin" -) - -const genesisFilepath = "./testdata/genesis.json" -const genesisAcctFilepath = "./testdata/genesis2.json" - -// 2b is just like 2, but add carl who has inconsistent -// pubkey and address -const genesisBadAcctFilepath = "./testdata/genesis2b.json" - -func TestLoadGenesisDoNotFailIfAppOptionsAreMissing(t *testing.T) { - logger := log.TestingLogger() - store, err := MockStoreApp("genesis", logger) - require.Nil(t, err, "%+v", err) - app := NewBaseApp(store, DefaultHandler("mycoin"), nil) - - err = genesis.Load(app, "./testdata/genesis3.json") - require.Nil(t, err, "%+v", err) -} - -func TestLoadGenesisFailsWithUnknownOptions(t *testing.T) { - require := require.New(t) - - logger := log.TestingLogger() - store, err := MockStoreApp("genesis", logger) - require.Nil(err, "%+v", err) - - app := NewBaseApp(store, DefaultHandler("mycoin"), nil) - err = genesis.Load(app, genesisFilepath) - require.NotNil(err, "%+v", err) -} - -// Fix for issue #89, change the parse format for accounts in genesis.json -func TestLoadGenesisAccountAddress(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - logger := log.TestingLogger() - store, err := MockStoreApp("genesis", logger) - require.Nil(err, "%+v", err) - app := NewBaseApp(store, DefaultHandler("mycoin"), nil) - - err = genesis.Load(app, genesisAcctFilepath) - require.Nil(err, "%+v", err) - - // check the chain id - assert.Equal("addr_accounts_chain", app.GetChainID()) - - // make sure the accounts were set properly - cases := []struct { - addr string - exists bool - hasPubkey bool - coins coin.Coins - }{ - // this comes from a public key, should be stored proper (alice) - {"62035D628DE7543332544AA60D90D3693B6AD51B", true, true, coin.Coins{{"one", 111}}}, - // this comes from an address, should be stored proper (bob) - {"C471FB670E44D219EE6DF2FC284BE38793ACBCE1", true, false, coin.Coins{{"two", 222}}}, - // this comes from a secp256k1 public key, should be stored proper (sam) - {"979F080B1DD046C452C2A8A250D18646C6B669D4", true, true, coin.Coins{{"four", 444}}}, - } - - for i, tc := range cases { - addr, err := hex.DecodeString(tc.addr) - require.Nil(err, tc.addr) - coins, err := getAddr(addr, app.Append()) - require.Nil(err, "%+v", err) - if !tc.exists { - assert.True(coins.IsZero(), "%d", i) - } else if assert.False(coins.IsZero(), "%d", i) { - // it should and does exist... - assert.True(coins.IsValid()) - assert.Equal(tc.coins, coins) - } - } -} - -// When you define an account in genesis with address -// and pubkey that don't match -func TestLoadGenesisAccountInconsistentAddress(t *testing.T) { - require := require.New(t) - - logger := log.TestingLogger() - store, err := MockStoreApp("genesis", logger) - require.Nil(err, "%+v", err) - app := NewBaseApp(store, DefaultHandler("mycoin"), nil) - err = genesis.Load(app, genesisBadAcctFilepath) - require.NotNil(err) -} diff --git a/_attic/modules/bonus/doc.go b/_attic/modules/bonus/doc.go deleted file mode 100644 index 2cb05260dc..0000000000 --- a/_attic/modules/bonus/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -/** -Package bonus is a temporary home for various functionalities -that were removed for complexity, but may be added back in -later. -**/ -package bonus diff --git a/_attic/modules/bonus/helpers.go b/_attic/modules/bonus/helpers.go deleted file mode 100644 index fdd3825f77..0000000000 --- a/_attic/modules/bonus/helpers.go +++ /dev/null @@ -1,118 +0,0 @@ -package bonus - -import ( - abci "github.com/tendermint/abci/types" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -//nolint -const ( - NameVal = "val" - NamePrice = "price" - - TypeValChange = NameVal + "/change" - ByteValChange = 0xfe - - TypePriceShow = NamePrice + "/show" - BytePriceShow = 0xfd -) - -func init() { - sdk.TxMapper. - RegisterImplementation(ValChangeTx{}, TypeValChange, ByteValChange). - RegisterImplementation(PriceShowTx{}, TypePriceShow, BytePriceShow) -} - -//-------------------------------- -// Setup tx and handler for validation test cases - -type ValSetHandler struct { - sdk.NopCheck - sdk.NopInitState - sdk.NopInitValidate -} - -var _ sdk.Handler = ValSetHandler{} - -func (ValSetHandler) Name() string { - return NameVal -} - -func (ValSetHandler) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx) (res sdk.DeliverResult, err error) { - change, ok := tx.Unwrap().(ValChangeTx) - if !ok { - return res, errors.ErrUnknownTxType(tx) - } - res.Diff = change.Diff - return -} - -type ValChangeTx struct { - Diff []*abci.Validator -} - -func (v ValChangeTx) Wrap() sdk.Tx { - return sdk.Tx{v} -} - -func (v ValChangeTx) ValidateBasic() error { return nil } - -//-------------------------------- -// Setup tx and handler for testing checktx fees/gas - -// PriceData is the data we ping back -var PriceData = []byte{0xCA, 0xFE} - -// PriceHandler returns checktx results based on the input -type PriceHandler struct { - sdk.NopInitState - sdk.NopInitValidate -} - -var _ sdk.Handler = PriceHandler{} - -func (PriceHandler) Name() string { - return NamePrice -} - -func (PriceHandler) CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx) (res sdk.CheckResult, err error) { - price, ok := tx.Unwrap().(PriceShowTx) - if !ok { - return res, errors.ErrUnknownTxType(tx) - } - res.GasAllocated = price.GasAllocated - res.GasPayment = price.GasPayment - res.Data = PriceData - return -} - -func (PriceHandler) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx) (res sdk.DeliverResult, err error) { - _, ok := tx.Unwrap().(PriceShowTx) - if !ok { - return res, errors.ErrUnknownTxType(tx) - } - res.Data = PriceData - return -} - -// PriceShowTx lets us bounce back a given fee/gas on CheckTx -type PriceShowTx struct { - GasAllocated uint64 - GasPayment uint64 -} - -func NewPriceShowTx(gasAllocated, gasPayment uint64) sdk.Tx { - return PriceShowTx{GasAllocated: gasAllocated, GasPayment: gasPayment}.Wrap() -} - -func (p PriceShowTx) Wrap() sdk.Tx { - return sdk.Tx{p} -} - -func (v PriceShowTx) ValidateBasic() error { return nil } diff --git a/_attic/modules/bonus/multiplexer.go b/_attic/modules/bonus/multiplexer.go deleted file mode 100644 index 8f82abd1c7..0000000000 --- a/_attic/modules/bonus/multiplexer.go +++ /dev/null @@ -1,116 +0,0 @@ -package bonus - -import ( - "strings" - - abci "github.com/tendermint/abci/types" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/go-wire/data" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -//nolint -const ( - NameMultiplexer = "mplx" -) - -// Multiplexer grabs a MultiTx and sends them sequentially down the line -type Multiplexer struct { - stack.PassInitState - stack.PassInitValidate -} - -// Name of the module - fulfills Middleware interface -func (Multiplexer) Name() string { - return NameMultiplexer -} - -var _ stack.Middleware = Multiplexer{} - -// CheckTx splits the input tx and checks them all - fulfills Middlware interface -func (Multiplexer) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) { - if mtx, ok := tx.Unwrap().(MultiTx); ok { - return runAllChecks(ctx, store, mtx.Txs, next) - } - return next.CheckTx(ctx, store, tx) -} - -// DeliverTx splits the input tx and checks them all - fulfills Middlware interface -func (Multiplexer) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) { - if mtx, ok := tx.Unwrap().(MultiTx); ok { - return runAllDelivers(ctx, store, mtx.Txs, next) - } - return next.DeliverTx(ctx, store, tx) -} - -func runAllChecks(ctx sdk.Context, store state.SimpleDB, txs []sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) { - // store all results, unless anything errors - rs := make([]sdk.CheckResult, len(txs)) - for i, stx := range txs { - rs[i], err = next.CheckTx(ctx, store, stx) - if err != nil { - return - } - } - // now combine the results into one... - return combineChecks(rs), nil -} - -func runAllDelivers(ctx sdk.Context, store state.SimpleDB, txs []sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) { - // store all results, unless anything errors - rs := make([]sdk.DeliverResult, len(txs)) - for i, stx := range txs { - rs[i], err = next.DeliverTx(ctx, store, stx) - if err != nil { - return - } - } - // now combine the results into one... - return combineDelivers(rs), nil -} - -// combines all data bytes as a go-wire array. -// joins all log messages with \n -func combineChecks(all []sdk.CheckResult) sdk.CheckResult { - datas := make([]data.Bytes, len(all)) - logs := make([]string, len(all)) - var allocated, payments uint64 - for i, r := range all { - datas[i] = r.Data - logs[i] = r.Log - allocated += r.GasAllocated - payments += r.GasPayment - } - return sdk.CheckResult{ - Data: wire.BinaryBytes(datas), - Log: strings.Join(logs, "\n"), - GasAllocated: allocated, - GasPayment: payments, - } -} - -// combines all data bytes as a go-wire array. -// joins all log messages with \n -func combineDelivers(all []sdk.DeliverResult) sdk.DeliverResult { - datas := make([]data.Bytes, len(all)) - logs := make([]string, len(all)) - var used uint64 - var diffs []*abci.Validator - for i, r := range all { - datas[i] = r.Data - logs[i] = r.Log - used += r.GasUsed - if len(r.Diff) > 0 { - diffs = append(diffs, r.Diff...) - } - } - return sdk.DeliverResult{ - Data: wire.BinaryBytes(datas), - Log: strings.Join(logs, "\n"), - GasUsed: used, - Diff: diffs, - } -} diff --git a/_attic/modules/bonus/multiplexer_test.go b/_attic/modules/bonus/multiplexer_test.go deleted file mode 100644 index bf448a492b..0000000000 --- a/_attic/modules/bonus/multiplexer_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package bonus - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" - "github.com/stretchr/testify/assert" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/go-wire/data" - "github.com/tendermint/tmlibs/log" -) - -func TestMultiplexer(t *testing.T) { - assert := assert.New(t) - msg := "diddly" - chainID := "multi-verse" - height := uint64(100) - - // Generic args here... - store := state.NewMemKVStore() - ctx := stack.NewContext(chainID, height, log.NewNopLogger()) - - // Build the stack - app := stack. - New(Multiplexer{}). - Dispatch( - stack.WrapHandler(stack.OKHandler{Log: msg}), - stack.WrapHandler(PriceHandler{}), - ) - - raw := stack.NewRawTx([]byte{1, 2, 3, 4}) - fail := stack.NewFailTx() - price1 := NewPriceShowTx(123, 456) - price2 := NewPriceShowTx(1000, 2000) - price3 := NewPriceShowTx(11, 0) - - join := func(data ...[]byte) []byte { - return wire.BinaryBytes(data) - } - - cases := [...]struct { - tx sdk.Tx - valid bool - gasAllocated uint64 - gasPayment uint64 - log string - data data.Bytes - }{ - // test the components without multiplexer (no effect) - 0: {raw, true, 0, 0, msg, nil}, - 1: {price1, true, 123, 456, "", PriceData}, - 2: {fail, false, 0, 0, "", nil}, - // test multiplexer on error - 3: {NewMultiTx(raw, fail, price1), false, 0, 0, "", nil}, - // test combining info on multiplexer - 4: {NewMultiTx(price1, raw), true, 123, 456, "\n" + msg, join(PriceData, nil)}, - // add lots of prices - 5: {NewMultiTx(price1, price2, price3), true, 1134, 2456, "\n\n", join(PriceData, PriceData, PriceData)}, - // combine multiple logs - 6: {NewMultiTx(raw, price3, raw), true, 11, 0, msg + "\n\n" + msg, join(nil, PriceData, nil)}, - } - - for i, tc := range cases { - cres, err := app.CheckTx(ctx, store, tc.tx) - if tc.valid { - assert.Nil(err, "%d: %+v", i, err) - assert.Equal(tc.log, cres.Log, "%d", i) - assert.Equal(tc.data, cres.Data, "%d", i) - assert.Equal(tc.gasAllocated, cres.GasAllocated, "%d", i) - assert.Equal(tc.gasPayment, cres.GasPayment, "%d", i) - } else { - assert.NotNil(err, "%d", i) - } - - // make sure deliver returns error, not a panic crash - dres, err := app.DeliverTx(ctx, store, tc.tx) - if tc.valid { - assert.Nil(err, "%d: %+v", i, err) - assert.Equal(tc.log, dres.Log, "%d", i) - assert.Equal(tc.data, dres.Data, "%d", i) - } else { - assert.NotNil(err, "%d", i) - } - } -} diff --git a/_attic/modules/docs/Makefile b/_attic/modules/docs/Makefile deleted file mode 100644 index f4bccf3bd3..0000000000 --- a/_attic/modules/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = python -msphinx -SPHINXPROJ = Cosmos-SDK -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/_attic/modules/docs/architecture/API.md b/_attic/modules/docs/architecture/API.md deleted file mode 100644 index de4abd0614..0000000000 --- a/_attic/modules/docs/architecture/API.md +++ /dev/null @@ -1,249 +0,0 @@ -# API - -In order to allow for quick client development, with the security -of the light-client and ease of use the cli (embedding go-wire and -go-crypto), we will provide a REST API, which can run on localhost -as part of `basecli`, securely managing your keys, signing transactions, -and validating queries. It will be exposed for a locally deployed -application to make use of (eg. electron app, web server...) - -By default we will serve on `http://localhost:2024`. CORS will be disabled by default. Potentially we can add a flag to enable it for one domain. - -## MVP - -The MVP will allow us to move around money. This involves the -following functions: - -## Construct an unsigned transaction - -`POST /build/send` - -Input: -``` -{ - "to": {"app": "role", "addr": "62616E6B32" }, - "from": {"app": "sigs", "addr": "BDADF167E6CF2CDF2D621E590FF1FED2787A40E0" }, - "amount": { "denom": "mycoin", "amount": 900000 }, - "sequence": 1, - "multi": true, -} -``` - -Output (a json encoding of basecoin.Tx): - -`basecli tx send --to=role:62616E6B32 --from=sigs:91C959ADE03D8973E8F2FBA9FD2EED327DCE2B0A --amount=900000mycoin --sequence=1 --multi --prepare=- --no-sign` - - -``` -{ - "type": "sigs/multi", - "data": { - "tx": { - "type": "chain/tx", - "data": { - "chain_id": "lakeshore", - "expires_at": 0, - "tx": { - "type": "nonce", - "data": { - "sequence": 1, - "signers": [ - { - "chain": "", - "app": "sigs", - "addr": "91C959ADE03D8973E8F2FBA9FD2EED327DCE2B0A" - } - ], - "tx": { - "type": "coin/send", - "data": { - "inputs": [ - { - "address": { - "chain": "", - "app": "role", - "addr": "62616E6B32" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 900000 - } - ] - } - ], - "outputs": [ - { - "address": { - "chain": "", - "app": "sigs", - "addr": "BDADF167E6CF2CDF2D621E590FF1FED2787A40E0" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 900000 - } - ] - } - ] - } - } - } - } - } - }, - "signatures": null - } -} -``` - -## Sign a Tx - -Once you construct a proper json-encoded `basecoin.Tx`, you can sign it once, or (if you constructed it with `multi=true`), multiple times. - - -`POST /sign` - -Input: - -``` -{ - "name": "matt", - "password": "1234567890", - "tx": { - "type": "sigs/multi", - "data": { - "tx": // see output of /build/send, - "signatures": nil, - } - } -} -``` - -Output: - -`basecli tx send --to=role:62616E6B32 --from=sigs:91C959ADE03D8973E8F2FBA9FD2EED327DCE2B0A --amount=900000mycoin --sequence=1 --multi --no-sign --prepare=unsigned.json` - -`echo 1234567890 | basecli tx --in=unsigned.json --prepare=- --name=matt` - -``` -{ - "type": "sigs/multi", - "data": { - "tx": // see output of /build/send, - "signatures": [ - { - "Sig": { - "type": "ed25519", - "data": "436188FAC4668DDF6729022454AFBA5DA0B44E516C4EC7013C6B00BD877F255CDE0355F3FBFE9CCF88C9F519C192D498BF087AFE0D531351813432A100857803" - }, - "Pubkey": { - "type": "ed25519", - "data": "B01508EB073C0823E2CE6ABF4538BA02EAEC39B02113290BBFCEC7E1B07F575A" - } - } - ] - } -} -``` - -## Send Tx to the Blockchain - -This will encode the transaction as binary and post it to the tendermint node, waiting until it is committed to the blockchain. -(TODO: make this async? return when recevied, notify when committed?) - -`POST /tx` - -Input: - -Signed tx as json, directly copy output of `/sign` - -Output: - - -`echo 1234567890 | basecli tx send --to=role:62616E6B32 --from=sigs:91C959ADE03D8973E8F2FBA9FD2EED327DCE2B0A --amount=900000mycoin --sequence=1 --multi --name=matt --prepare=signed.json` - -`basecli tx --in=signed.json --no-sign` - -``` -{ - "check_tx": { - "code": 0, - "data": "", - "log": "" - }, - "deliver_tx": { - "code": 0, - "data": "", - "log": "" - }, - "hash": "4D0EB7853E71AB6E3021990CF733F70F4CC2E001", - "height": 1494 -} -``` - -## Query account balance - -`GET /query/account/sigs:BDADF167E6CF2CDF2D621E590FF1FED2787A40E0` - -``` -{ - "height": 1170, - "data": { - "coins": [ - { - "denom": "mycoin", - "amount": 12345 - } - ] - } -} -``` - -## Other stuff for MVP - -You must run `basecli init` int he cli to set things up. - -When you run `basecli serve`, it will start the local rest api server, with the above endpoints. - -Also, support keys endpoints from go-crypto as they currently are and mount them under `/keys`. - -## Future Stuff - -proxy mounted as well under `/tendermint` - -`/tendermint/status` -`/tendermint/block` - -info about self... - -`/` - -``` -{ - "app": "basecli", - "version": "0.7.1", // of client, server???? - "modules": { - "chain": "0.1.0", - "fees": "0.2.1", - "coin": "0.3.2", - "stake": "0.1.2" - }, - "nodes": [ - "localhost:46657", - "mercury.interchain.io:443" - ] -} -``` - -`/commits` - -``` -{ - "last_height": 4555, - "update_problems": "too much change" -} -``` - -info on last commit diff --git a/_attic/modules/docs/basecoin-basics.rst b/_attic/modules/docs/basecoin-basics.rst deleted file mode 100644 index 099b4c4ec1..0000000000 --- a/_attic/modules/docs/basecoin-basics.rst +++ /dev/null @@ -1,388 +0,0 @@ -.. raw:: html - - - -Basecoin Basics -=============== - -Here we explain how to get started with a basic Basecoin blockchain, how -to send transactions between accounts using the ``basecoin`` tool, and -what is happening under the hood. - -Install -------- - -With go, it's one command: - -.. code:: shelldown[0] - -:: - - go get -u github.com/tendermint/basecoin/cmd/... - -If you have trouble, see the `installation guide <./install.html>`__. - -Note the above command installs two binaries: ``basecoin`` and -``basecli``. The former is the running node. The latter is a -command-line light-client. This tutorial assumes you have a 'fresh' -working environment. See how to clean up below. - -Generate some keys -~~~~~~~~~~~~~~~~~~ - -Let's generate two keys, one to receive an initial allocation of coins, -and one to send some coins to later: - -.. code:: shelldown[1] - -:: - - basecli keys new cool - basecli keys new friend - -You'll need to enter passwords. You can view your key names and -addresses with ``basecli keys list``, or see a particular key's address -with ``basecli keys get ``. - -Initialize Basecoin -------------------- - -To initialize a new Basecoin blockchain, run: - -.. code:: shelldown[2] - -:: - - basecoin init
- -If you prefer not to copy-paste, you can provide the address -programatically: - -.. code:: shelldown[3] - -:: - - basecoin init $(basecli keys get cool | awk '{print $2}') - -This will create the necessary files for a Basecoin blockchain with one -validator and one account (corresponding to your key) in -``~/.basecoin``. For more options on setup, see the `guide to using the -Basecoin tool `__. - -If you like, you can manually add some more accounts to the blockchain -by generating keys and editing the ``~/.basecoin/genesis.json``. - -Start Basecoin -~~~~~~~~~~~~~~ - -Now we can start Basecoin: - -.. code:: shelldown[4] - -:: - - basecoin start - -You should see blocks start streaming in! - -Initialize Light-Client ------------------------ - -Now that Basecoin is running we can initialize ``basecli``, the -light-client utility. Basecli is used for sending transactions and -querying the state. Leave Basecoin running and open a new terminal -window. Here run: - -.. code:: shelldown[5] - -:: - - basecli init --node=tcp://localhost:46657 --genesis=$HOME/.basecoin/genesis.json - -If you provide the genesis file to basecli, it can calculate the proper -chainID and validator hash. Basecli needs to get this information from -some trusted source, so all queries done with ``basecli`` can be -cryptographically proven to be correct according to a known validator -set. - -Note: that ``--genesis`` only works if there have been no validator set -changes since genesis. If there are validator set changes, you need to -find the current set through some other method. - -Send transactions -~~~~~~~~~~~~~~~~~ - -Now we are ready to send some transactions. First Let's check the -balance of the two accounts we setup earlier: - -.. code:: shelldown[6] - -:: - - ME=$(basecli keys get cool | awk '{print $2}') - YOU=$(basecli keys get friend | awk '{print $2}') - basecli query account $ME - basecli query account $YOU - -The first account is flush with cash, while the second account doesn't -exist. Let's send funds from the first account to the second: - -.. code:: shelldown[7] - -:: - - basecli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1 - -Now if we check the second account, it should have ``1000`` 'mycoin' -coins! - -.. code:: shelldown[8] - -:: - - basecli query account $YOU - -We can send some of these coins back like so: - -.. code:: shelldown[9] - -:: - - basecli tx send --name=friend --amount=500mycoin --to=$ME --sequence=1 - -Note how we use the ``--name`` flag to select a different account to -send from. - -If we try to send too much, we'll get an error: - -.. code:: shelldown[10] - -:: - - basecli tx send --name=friend --amount=500000mycoin --to=$ME --sequence=2 - -Let's send another transaction: - -.. code:: shelldown[11] - -:: - - basecli tx send --name=cool --amount=2345mycoin --to=$YOU --sequence=2 - -Note the ``hash`` value in the response - this is the hash of the -transaction. We can query for the transaction by this hash: - -.. code:: shelldown[12] - -:: - - basecli query tx - -See ``basecli tx send --help`` for additional details. - -Proof ------ - -Even if you don't see it in the UI, the result of every query comes with -a proof. This is a Merkle proof that the result of the query is actually -contained in the state. And the state's Merkle root is contained in a -recent block header. Behind the scenes, ``countercli`` will not only -verify that this state matches the header, but also that the header is -properly signed by the known validator set. It will even update the -validator set as needed, so long as there have not been major changes -and it is secure to do so. So, if you wonder why the query may take a -second... there is a lot of work going on in the background to make sure -even a lying full node can't trick your client. - -Accounts and Transactions -------------------------- - -For a better understanding of how to further use the tools, it helps to -understand the underlying data structures. - -Accounts -~~~~~~~~ - -The Basecoin state consists entirely of a set of accounts. Each account -contains a public key, a balance in many different coin denominations, -and a strictly increasing sequence number for replay protection. This -type of account was directly inspired by accounts in Ethereum, and is -unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). Note -Basecoin is a multi-asset cryptocurrency, so each account can have many -different kinds of tokens. - -.. code:: golang - -:: - - type Account struct { - PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known. - Sequence int `json:"sequence"` - Balance Coins `json:"coins"` - } - - type Coins []Coin - - type Coin struct { - Denom string `json:"denom"` - Amount int64 `json:"amount"` - } - -If you want to add more coins to a blockchain, you can do so manually in -the ``~/.basecoin/genesis.json`` before you start the blockchain for the -first time. - -Accounts are serialized and stored in a Merkle tree under the key -``base/a/
``, where ``
`` is the address of the account. -Typically, the address of the account is the 20-byte ``RIPEMD160`` hash -of the public key, but other formats are acceptable as well, as defined -in the `Tendermint crypto -library `__. The Merkle tree -used in Basecoin is a balanced, binary search tree, which we call an -`IAVL tree `__. - -Transactions -~~~~~~~~~~~~ - -Basecoin defines a transaction type, the ``SendTx``, which allows tokens -to be sent to other accounts. The ``SendTx`` takes a list of inputs and -a list of outputs, and transfers all the tokens listed in the inputs -from their corresponding accounts to the accounts listed in the output. -The ``SendTx`` is structured as follows: - -.. code:: golang - -:: - - type SendTx struct { - Gas int64 `json:"gas"` - Fee Coin `json:"fee"` - Inputs []TxInput `json:"inputs"` - Outputs []TxOutput `json:"outputs"` - } - - type TxInput struct { - Address []byte `json:"address"` // Hash of the PubKey - Coins Coins `json:"coins"` // - Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput - Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx - PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0 - } - - type TxOutput struct { - Address []byte `json:"address"` // Hash of the PubKey - Coins Coins `json:"coins"` // - } - -Note the ``SendTx`` includes a field for ``Gas`` and ``Fee``. The -``Gas`` limits the total amount of computation that can be done by the -transaction, while the ``Fee`` refers to the total amount paid in fees. -This is slightly different from Ethereum's concept of ``Gas`` and -``GasPrice``, where ``Fee = Gas x GasPrice``. In Basecoin, the ``Gas`` -and ``Fee`` are independent, and the ``GasPrice`` is implicit. - -In Basecoin, the ``Fee`` is meant to be used by the validators to inform -the ordering of transactions, like in Bitcoin. And the ``Gas`` is meant -to be used by the application plugin to control its execution. There is -currently no means to pass ``Fee`` information to the Tendermint -validators, but it will come soon... - -Note also that the ``PubKey`` only needs to be sent for -``Sequence == 0``. After that, it is stored under the account in the -Merkle tree and subsequent transactions can exclude it, using only the -``Address`` to refer to the sender. Ethereum does not require public -keys to be sent in transactions as it uses a different elliptic curve -scheme which enables the public key to be derived from the signature -itself. - -Finally, note that the use of multiple inputs and multiple outputs -allows us to send many different types of tokens between many different -accounts at once in an atomic transaction. Thus, the ``SendTx`` can -serve as a basic unit of decentralized exchange. When using multiple -inputs and outputs, you must make sure that the sum of coins of the -inputs equals the sum of coins of the outputs (no creating money), and -that all accounts that provide inputs have signed the transaction. - -Clean Up --------- - -**WARNING:** Running these commands will wipe out any existing -information in both the ``~/.basecli`` and ``~/.basecoin`` directories, -including private keys. - -To remove all the files created and refresh your environment (e.g., if -starting this tutorial again or trying something new), the following -commands are run: - -.. code:: shelldown[end-of-tutorials] - -:: - - basecli reset_all - rm -rf ~/.basecoin - -In this guide, we introduced the ``basecoin`` and ``basecli`` tools, -demonstrated how to start a new basecoin blockchain and how to send -tokens between accounts, and discussed the underlying data types for -accounts and transactions, specifically the ``Account`` and the -``SendTx``. diff --git a/_attic/modules/docs/basecoin-kubernetes.rst b/_attic/modules/docs/basecoin-kubernetes.rst deleted file mode 100644 index e89cd5b94c..0000000000 --- a/_attic/modules/docs/basecoin-kubernetes.rst +++ /dev/null @@ -1,228 +0,0 @@ -Basecoin Kubernetes -=================== - -*Note:* This guide is based from - and has been updated - the `origin Medium article `__. - -So, your Tendermint application is finally ready and you want to -distribute it and run it on several machines, or just run it locally by -creating a dozen Docker containers. We have created -`mintnet-kubernetes `__ -to help you achieve this goal as fast as possible. Note that it should -be primarily used for testing purposes or for tightly-defined chains -operated by a single stakeholder (see `the security -precautions `__). -If you want to launch an application with many stakeholders, consider -using `our set of -Ansible `__ -scripts to deploy Tendermint. - -``mintnet-kubernetes`` is a configuration file for -`Kubernetes `__. - -*Kubernetes is an open-source system for automating deployment, scaling, -and management of containerized applications.* - -If you had never heard of it, it won’t hurt to read `What is -Kubernetes? `__ -and go through their `interactive -lessons `__. It -won't take long, I promise. - -There are several ways to install a Kubernetes cluster: - -- a local Docker-based solution using - `Minikube `__ -- hosted solutions using a Web UI or CLI (e.g. GCE) -- turn-key cloud solutions (e.g. AWS using `Kubernetes - Operations `__; - AWS, Azure, GCE or bare metal using - `Kargo `__) -- custom solutions (e.g. Linux machines using - `kubeadm `__) - -If you just want to play with your application, choose a local -installation with Minikube. If you want to run it in the cloud or on -bare metal, refer to `Picking the Right -Solution `__, taking -into account the cost, safety, reliability, and configuration options of -those solutions. - -Further, we will assume that you have a standard 64-bit Linux desktop -with `VirtualBox `__ or -`KVM `__ installed. - -Install kubectl ---------------- - -:: - - curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x ./kubectl && sudo mv ./kubectl /usr/local/bin/kubectl - -For Windows or OS X, please check out `Installing and Setting Up -kubectl `__ guide. - -Install Minikube ----------------- - -:: - - curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.19.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ - -For Windows or OS X, please check out -`Releases `__ page. - -Start Minikube --------------- - -:: - - minikube start - -Configure your app ------------------- - -Get the config file: - -:: - - curl -Lo app.yaml https://raw.githubusercontent.com/tendermint/tools/master/mintnet-kubernetes/examples/basecoin/app.yaml - -Open it in the editor of your choice: - -:: - -$EDITOR app.yaml - -and configure the parameters required for your application. - -The Cosmos SDK will help us create our own -currency, extensible with plugins. Writing plugins is out of scope of -this article, but you can read about it -`here `__. - -Kubernetes DSL (Domain Specific Language) can be difficult for the -beginner to grasp. Fortunately, we will need to change only a small -piece of code. - -The most important thing is the application’s ``genesis.json`` file. It -defines the initial distribution of assets. We have 4 nodes by default -(``replicas: 4``\ in StatefulSet). Generally, it is a good idea to split -assets evenly between them and have some large number for everyone. - -Let’s change denom to “MyAwesomeCoin”. You are welcome to pick any other -name you like. - -:: - - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: app-config - data: - genesis.json: |- - { - "chain_id": "chain-tTH4mi", - "app_options": { - "accounts": [ - { - "pub_key": "tm-0", - "coins": [ - { - "denom": "MyAwesomeCoin", - "amount": 1000000000 - } - ] - }, - { - "pub_key": "tm-1", - "coins": [ - { - "denom": "MyAwesomeCoin", - "amount": 1000000000 - } - ] - }, - { - "pub_key": "tm-2", - "coins": [ - { - "denom": "MyAwesomeCoin", - "amount": 1000000000 - } - ] - }, - { - "pub_key": "tm-3", - "coins": [ - { - "denom": "MyAwesomeCoin", - "amount": 1000000000 - } - ] - } - ] - } - } - -Launch your app ---------------- - -:: - - kubectl create -f ./app.yaml - -Wait until all of the nodes are running: - -:: - - kubectl get pods -w -o wide -L tm - NAME READY STATUS RESTARTS AGE IP NODE TM - tm-0 3/3 Running 0 3m 172.17.0.2 minikube - tm-1 3/3 Running 0 3m 172.17.0.3 minikube - tm-2 3/3 Running 1 3m 172.17.0.4 minikube - tm-3 3/3 Running 0 3m 172.17.0.7 minikube - -Let’s check the first account: - -:: - - ADDR=$(kubectl exec -c app tm-0 -- cat /app/key.json | jq ".address" | tr -d "\"") - - kubectl exec -c app tm-0 -- basecoin account $ADDR - {"pub_key":{"type":"ed25519","data":"793B7E33EF94132E16534CC9BA59F74944065FA917A98DB68ABA806D219A4529"},"sequence":1,"coins":[{"denom":"MyAwesomeCoin","amount":999999995}]} - -Great! Let’s try to send a transaction from the first to the second -account: - -:: - - RECIPIENT=$(kubectl exec -c app tm-1 -- cat /app/key.json | jq ".address" | tr -d "\"") - - kubectl exec -c app tm-0 -- basecoin tx send --to 0x$RECIPIENT --amount 5MyAwesomeCoin --from /app/key.json --chain_id chain-tTH4mi - Signed SendTx: - 0100000000000000000104636F696E000000000000000001010114A677E98456071E3240EF0A2E0B80FFE7D36515BF010101066D79636F696E0000000000000005010201E6A038849655CD3C94D06BAC1CA74443D312855A9BC3575311842DF74AF7DB772673DF60F3AE08CC5260AE93DCE4DB588EF24D08768D0DE2752F001DDC1DEE0F0001010114E2AFEA4A193E85A2DBB8668D4EA0DC0B1A6AD63A010101066D79636F696E0000000000000005 - Response: 3D54EECAAE072477E6119C6DF1762168F276F0C1 ; - -Checking the first account’s balance we should see 5 coins making their -way into the second account: - -:: - - kubectl exec -c app tm-0 -- basecoin account $ADDR - {"pub_key":{"type":"ed25519","data":"793B7E33EF94132E16534CC9BA59F74944065FA917A98DB68ABA806D219A4529"},"sequence":2,"coins":[{"denom":"MyAwesomeCoin","amount":999999990}]} - -As you can see, it was fairly simple to launch a new cryptocurrency in a -Kubernetes cluster. Moreover, with Kubernetes you can add new nodes -(pods) with a single command. And using -`federation `__, -you can be sure that your currency will stay alive even after loss of -the entire cluster! - -Clean up --------- - -:: - - kubectl delete -f ./app.yaml - kubectl delete pvc -l app=tm diff --git a/_attic/modules/docs/basecoin-plugins.rst b/_attic/modules/docs/basecoin-plugins.rst deleted file mode 100644 index 9f225ea396..0000000000 --- a/_attic/modules/docs/basecoin-plugins.rst +++ /dev/null @@ -1,276 +0,0 @@ -.. raw:: html - - - -Basecoin Plugins -================ - -In the `previous guide `__, we saw how to use the -``basecoin`` tool to start a blockchain and the ``basecli`` tools to -send transactions. We also learned about ``Account`` and ``SendTx``, the -basic data types giving us a multi-asset cryptocurrency. Here, we will -demonstrate how to extend the tools to use another transaction type, the -``AppTx``, so we can send data to a custom plugin. In this example we -explore a simple plugin named ``counter``. - -Example Plugin --------------- - -The design of the ``basecoin`` tool makes it easy to extend for custom -functionality. The Counter plugin is bundled with basecoin, so if you -have already `installed basecoin `__ and run -``make install`` then you should be able to run a full node with -``counter`` and the a light-client ``countercli`` from terminal. The -Counter plugin is just like the ``basecoin`` tool. They both use the -same library of commands, including one for signing and broadcasting -``SendTx``. - -Counter transactions take two custom inputs, a boolean argument named -``valid``, and a coin amount named ``countfee``. The transaction is only -accepted if both ``valid`` is set to true and the transaction input -coins is greater than ``countfee`` that the user provides. - -A new blockchain can be initialized and started just like in the -`previous guide `__: - -.. code:: shelldown[0] - - # WARNING: this wipes out data - but counter is only for demos... - rm -rf ~/.counter - countercli reset_all - - countercli keys new cool - countercli keys new friend - - counter init $(countercli keys get cool | awk '{print $2}') - - counter start - -The default files are stored in ``~/.counter``. In another window we can -initialize the light-client and send a transaction: - -.. code:: shelldown[1] - - countercli init --node=tcp://localhost:46657 --genesis=$HOME/.counter/genesis.json - - YOU=$(countercli keys get friend | awk '{print $2}') - countercli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1 - -But the Counter has an additional command, ``countercli tx counter``, -which crafts an ``AppTx`` specifically for this plugin: - -.. code:: shelldown[2] - - countercli tx counter --name cool - countercli tx counter --name cool --valid - -The first transaction is rejected by the plugin because it was not -marked as valid, while the second transaction passes. We can build -plugins that take many arguments of different types, and easily extend -the tool to accomodate them. Of course, we can also expose queries on -our plugin: - -.. code:: shelldown[3] - - countercli query counter - -Tada! We can now see that our custom counter plugin transactions went -through. You should see a Counter value of 1 representing the number of -valid transactions. If we send another transaction, and then query -again, we will see the value increment. Note that we need the sequence -number here to send the coins (it didn't increment when we just pinged -the counter) - -.. code:: shelldown[4] - - countercli tx counter --name cool --countfee=2mycoin --sequence=2 --valid - countercli query counter - -The Counter value should be 2, because we sent a second valid -transaction. And this time, since we sent a countfee (which must be less -than or equal to the total amount sent with the tx), it stores the -``TotalFees`` on the counter as well. - -Keep it mind that, just like with ``basecli``, the ``countercli`` -verifies a proof that the query response is correct and up-to-date. - -Now, before we implement our own plugin and tooling, it helps to -understand the ``AppTx`` and the design of the plugin system. - -AppTx ------ - -The ``AppTx`` is similar to the ``SendTx``, but instead of sending coins -from inputs to outputs, it sends coins from one input to a plugin, and -can also send some data. - -.. code:: golang - - type AppTx struct { - Gas int64 `json:"gas"` - Fee Coin `json:"fee"` - Input TxInput `json:"input"` - Name string `json:"type"` // Name of the plugin - Data []byte `json:"data"` // Data for the plugin to process - } - -The ``AppTx`` enables Basecoin to be extended with arbitrary additional -functionality through the use of plugins. The ``Name`` field in the -``AppTx`` refers to the particular plugin which should process the -transaction, and the ``Data`` field of the ``AppTx`` is the data to be -forwarded to the plugin for processing. - -Note the ``AppTx`` also has a ``Gas`` and ``Fee``, with the same meaning -as for the ``SendTx``. It also includes a single ``TxInput``, which -specifies the sender of the transaction, and some coins that can be -forwarded to the plugin as well. - -Plugins -------- - -A plugin is simply a Go package that implements the ``Plugin`` -interface: - -.. code:: golang - - type Plugin interface { - - // Name of this plugin, should be short. - Name() string - - // Run a transaction from ABCI DeliverTx - RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result) - - // Other ABCI message handlers - SetOption(store KVStore, key string, value string) (log string) - InitChain(store KVStore, vals []*abci.Validator) - BeginBlock(store KVStore, hash []byte, header *abci.Header) - EndBlock(store KVStore, height uint64) (res abci.ResponseEndBlock) - } - - type CallContext struct { - CallerAddress []byte // Caller's Address (hash of PubKey) - CallerAccount *Account // Caller's Account, w/ fee & TxInputs deducted - Coins Coins // The coins that the caller wishes to spend, excluding fees - } - -The workhorse of the plugin is ``RunTx``, which is called when an -``AppTx`` is processed. The ``Data`` from the ``AppTx`` is passed in as -the ``txBytes``, while the ``Input`` from the ``AppTx`` is used to -populate the ``CallContext``. - -Note that ``RunTx`` also takes a ``KVStore`` - this is an abstraction -for the underlying Merkle tree which stores the account data. By passing -this to the plugin, we enable plugins to update accounts in the Basecoin -state directly, and also to store arbitrary other information in the -state. In this way, the functionality and state of a Basecoin-derived -cryptocurrency can be greatly extended. One could imagine going so far -as to implement the Ethereum Virtual Machine as a plugin! - -For details on how to initialize the state using ``SetOption``, see the -`guide to using the basecoin tool `__. - -Implement your own ------------------- - -To implement your own plugin and tooling, make a copy of -``docs/guide/counter``, and modify the code accordingly. Here, we will -briefly describe the design and the changes to be made, but see the code -for more details. - -First is the ``cmd/counter/main.go``, which drives the program. It can -be left alone, but you should change any occurrences of ``counter`` to -whatever your plugin tool is going to be called. You must also register -your plugin(s) with the basecoin app with ``RegisterStartPlugin``. - -The light-client is located in ``cmd/countercli/main.go`` and allows for -transaction and query commands. This file can also be left mostly alone -besides replacing the application name and adding references to new -plugin commands. - -Next is the custom commands in ``cmd/countercli/commands/``. These files -are where we extend the tool with any new commands and flags we need to -send transactions or queries to our plugin. You define custom ``tx`` and -``query`` subcommands, which are registered in ``main.go`` (avoiding -``init()`` auto-registration, for less magic and more control in the -main executable). - -Finally is ``plugins/counter/counter.go``, where we provide an -implementation of the ``Plugin`` interface. The most important part of -the implementation is the ``RunTx`` method, which determines the meaning -of the data sent along in the ``AppTx``. In our example, we define a new -transaction type, the ``CounterTx``, which we expect to be encoded in -the ``AppTx.Data``, and thus to be decoded in the ``RunTx`` method, and -used to update the plugin state. - -For more examples and inspiration, see our `repository of example -plugins `__. - -Conclusion ----------- - -In this guide, we demonstrated how to create a new plugin and how to -extend the ``basecoin`` tool to start a blockchain with the plugin -enabled and send transactions to it. In the next guide, we introduce a -`plugin for Inter Blockchain Communication `__, which allows us -to publish proofs of the state of one blockchain to another, and thus to -transfer tokens and data between them. diff --git a/_attic/modules/docs/basecoin-tool.rst b/_attic/modules/docs/basecoin-tool.rst deleted file mode 100644 index 020c8bb4b8..0000000000 --- a/_attic/modules/docs/basecoin-tool.rst +++ /dev/null @@ -1,282 +0,0 @@ -.. raw:: html - - - -Basecoin The Tool -================= - -We previously learned about basecoin basics. In this tutorial, we -provide more details on using the Basecoin tool. - -Generate a Key --------------- - -Generate a key using the ``basecli`` tool: - -.. comment code:: shelldown[0] - -:: - - basecli keys new mykey - ME=$(basecli keys get mykey | awk '{print $2}') - -Data Directory --------------- - -By default, ``basecoin`` works out of ``~/.basecoin``. To change this, -set the ``BCHOME`` environment variable: - -.. comment code:: shelldown[1] - -:: - - export BCHOME=~/.my_basecoin_data - basecoin init $ME - basecoin start - -or - -.. comment code:: shelldown[2] - -:: - - BCHOME=~/.my_basecoin_data basecoin init $ME - BCHOME=~/.my_basecoin_data basecoin start - -ABCI Server ------------ - -So far we have run Basecoin and Tendermint in a single process. However, -since we use ABCI, we can actually run them in different processes. -First, initialize them: - -.. comment code:: shelldown[3] - -:: - - basecoin init $ME - -This will create a single ``genesis.json`` file in ``~/.basecoin`` with -the information for both Basecoin and Tendermint. - -Now, In one window, run - -.. comment code:: shelldown[4] - -:: - - basecoin start --without-tendermint - -and in another, - -.. comment code:: shelldown[5] - -:: - - TMROOT=~/.basecoin tendermint node - -You should see Tendermint start making blocks! - -Alternatively, you could ignore the Tendermint details in -``~/.basecoin/genesis.json`` and use a separate directory by running: - -.. comment code:: shelldown[6] - -:: - - tendermint init - tendermint node - -See the `tendermint documentation `__ for more information. - -Keys and Genesis ----------------- - -In previous tutorials we used ``basecoin init`` to initialize -``~/.basecoin`` with the default configuration. This command creates -files both for Tendermint and for Basecoin, and a single -``genesis.json`` file for both of them. You can read more about these -files in the Tendermint documentation. - -Now let's make our own custom Basecoin data. - -First, create a new directory: - -.. comment code:: shelldown[7] - -:: - - mkdir example-data - -We can tell ``basecoin`` to use this directory by exporting the -``BCHOME`` environment variable: - -.. comment code:: shelldown[8] - -:: - - export BCHOME=$(pwd)/example-data - -If you're going to be using multiple terminal windows, make sure to add -this variable to your shell startup scripts (eg. ``~/.bashrc``). - -Now, let's create a new key: - -.. comment code:: shelldown[9] - -:: - - basecli keys new foobar - -The key's info can be retrieved with - -.. comment code:: shelldown[10] - -:: - - basecli keys get foobar -o=json - -You should get output which looks similar to the following: - -.. code:: json - - { - "name": "foobar", - "address": "404C5003A703C7DA888C96A2E901FCE65A6869D9", - "pubkey": { - "type": "ed25519", - "data": "8786B7812AB3B27892D8E14505EEFDBB609699E936F6A4871B1983F210736EEA" - } - } - -Yours will look different - each key is randomly derived. Now we can -make a ``genesis.json`` file and add an account with our public key: - -.. code:: json - - { - "app_hash": "", - "chain_id": "example-chain", - "genesis_time": "0001-01-01T00:00:00.000Z", - "validators": [ - { - "amount": 10, - "name": "", - "pub_key": { - "type": "ed25519", - "data": "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30" - } - } - ], - "app_options": { - "accounts": [ - { - "pub_key": { - "type": "ed25519", - "data": "8786B7812AB3B27892D8E14505EEFDBB609699E936F6A4871B1983F210736EEA" - }, - "coins": [ - { - "denom": "gold", - "amount": 1000000000 - } - ] - } - ] - } - } - -Here we've granted ourselves ``1000000000`` units of the ``gold`` token. -Note that we've also set the ``chain-id`` to be ``example-chain``. All -transactions must therefore include the ``--chain-id example-chain`` in -order to make sure they are valid for this chain. Previously, we didn't -need this flag because we were using the default chain ID -("test\_chain\_id"). Now that we're using a custom chain, we need to -specify the chain explicitly on the command line. - -Note we have also left out the details of the Tendermint genesis. See the -`Tendermint documentation `__ for more -information. - -Reset ------ - -You can reset all blockchain data by running: - -.. (comment) code:: shelldown[11] - -:: - - basecoin unsafe_reset_all - -Similarly, you can reset client data by running: - -.. (comment) code:: shelldown[12] - -:: - - basecli reset_all - -Genesis -------- - -Any required plugin initialization should be constructed using -``SetOption`` on genesis. When starting a new chain for the first time, -``SetOption`` will be called for each item the genesis file. Within -genesis.json file entries are made in the format: -``"/", ""``, where ```` is the plugin name, -and ```` and ```` are the strings passed into the plugin -SetOption function. This function is intended to be used to set plugin -specific information such as the plugin state. diff --git a/_attic/modules/docs/conf.py b/_attic/modules/docs/conf.py deleted file mode 100644 index ff69cce334..0000000000 --- a/_attic/modules/docs/conf.py +++ /dev/null @@ -1,173 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cosmos-SDK documentation build configuration file, created by -# sphinx-quickstart on Fri Sep 1 21:37:02 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - -import sphinx_rtd_theme - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Cosmos-SDK' -copyright = u'2017, The Authors' -author = u'The Authors' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = u'' -# The full version, including alpha/beta/rc tags. -release = u'' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'sphinx_rtd_theme' -# html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - 'donate.html', - ] -} - - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Cosmos-SDKdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'Cosmos-SDK.tex', u'Cosmos-SDK Documentation', - u'The Authors', 'manual'), -] - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'cosmos-sdk', u'Cosmos-SDK Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'Cosmos-SDK', u'Cosmos-SDK Documentation', - author, 'Cosmos-SDK', 'One line description of project.', - 'Miscellaneous'), -] - - - diff --git a/_attic/modules/docs/glossary.rst b/_attic/modules/docs/glossary.rst deleted file mode 100644 index 6c99a6a821..0000000000 --- a/_attic/modules/docs/glossary.rst +++ /dev/null @@ -1,334 +0,0 @@ -Glossary -======== - -This glossary defines many terms used throughout documentation of Quark. -If there is every a concept that seems unclear, check here. This is -mainly to provide a background and general understanding of the -different words and concepts that are used. Other documents will explain -in more detail how to combine these concepts to build a particular -application. - -Transaction ------------ - -A transaction is a packet of binary data that contains all information -to validate and perform an action on the blockchain. The only other data -that it interacts with is the current state of the chain (key-value -store), and it must have a deterministic action. The transaction is the -main piece of one request. - -We currently make heavy use of -`go-wire `__ and -`data `__ to -provide binary and json encodings and decodings for ``struct`` or -interface\ ``objects. Here, encoding and decoding operations are designed to operate with interfaces nested any amount times (like an onion!). There is one public``\ TxMapper\` -in the basecoin root package, and all modules can register their own -transaction types there. This allows us to deserialize the entire -transaction in one location (even with types defined in other repos), to -easily embed an arbitrary transaction inside another without specifying -the type, and provide an automatic json representation allowing for -users (or apps) to inspect the chain. - -Note how we can wrap any other transaction, add a fee level, and not -worry about the encoding in our module any more? - -.. code:: golang - - type Fee struct { - Fee coin.Coin `json:"fee"` - Payer basecoin.Actor `json:"payer"` // the address who pays the fee - Tx basecoin.Tx `json:"tx"` - } - -Context (ctx) -------------- - -As a request passes through the system, it may pick up information such -as the authorization it has received from another middleware, or the -block height the request runs at. In order to carry this information -between modules it is saved to the context. Further, all information -must be deterministic from the context in which the request runs (based -on the transaction and the block it was included in) and can be used to -validate the transaction. - -Data Store ----------- - -In order to provide proofs to Tendermint, we keep all data in one -key-value (kv) store which is indexed with a merkle tree. This allows -for the easy generation of a root hash and proofs for queries without -requiring complex logic inside each module. Standardization of this -process also allows powerful light-client tooling as any store data may -be verified on the fly. - -The largest limitation of the current implemenation of the kv-store is -that interface that the application must use can only ``Get`` and -``Set`` single data points. That said, there are some data structures -like queues and range queries that are available in ``state`` package. -These provide higher-level functionality in a standard format, but have -not yet been integrated into the kv-store interface. - -Isolation ---------- - -One of the main arguments for blockchain is security. So while we -encourage the use of third-party modules, all developers must be -vigilant against security holes. If you use the -`stack `__ -package, it will provide two different types of compartmentalization -security. - -The first is to limit the working kv-store space of each module. When -``DeliverTx`` is called for a module, it is never given the entire data -store, but rather only its own prefixed subset of the store. This is -achieved by prefixing all keys transparently with -`` + 0x0``, using the null byte as a separator. Since the -module name must be a string, no malicious naming scheme can ever lead -to a collision. Inside a module, we can write using any key value we -desire without the possibility that we have modified data belonging to -separate module. - -The second is to add permissions to the transaction context. The -transaction context can specify that the tx has been signed by one or -multiple specific -`actors `__. -A transactions will only be executed if the permission requirements have -been fulfilled. For example the sender of funds must have signed, or 2 -out of 3 multi-signature actors must have signed a joint account. To -prevent the forgery of account signatures from unintended modules each -permission is associated with the module that granted it (in this case -`auth `__), -and if a module tries to add a permission for another module, it will -panic. There is also protection if a module creates a brand new fake -context to trick the downstream modules. Each context enforces the rules -on how to make child contexts, and the stack middleware builder enforces -that the context passed from one level to the next is a valid child of -the original one. - -These security measures ensure that modules can confidently write to -their local section of the database and trust the permissions associated -with the context, without concern of interference from other modules. -(Okay, if you see a bunch of C-code in the module traversing through all -the memory space of the application, then get worried....) - -Handler -------- - -The ABCI interface is handled by ``app``, which translates these data -structures into an internal format that is more convenient, but unable -to travel over the wire. The basic interface for any code that modifies -state is the ``Handler`` interface, which provides four methods: - -.. code:: golang - - Name() string - CheckTx(ctx Context, store state.KVStore, tx Tx) (Result, error) - DeliverTx(ctx Context, store state.KVStore, tx Tx) (Result, error) - SetOption(l log.Logger, store state.KVStore, module, key, value string) (string, error) - -Note the ``Context``, ``KVStore``, and ``Tx`` as principal carriers of -information. And that Result is always success, and we have a second -error return for errors (which is much more standard golang that -``res.IsErr()``) - -The ``Handler`` interface is designed to be the basis for all modules -that execute transactions, and this can provide a large degree of code -interoperability, much like ``http.Handler`` does in golang web -development. - -Middleware ----------- - -Middleware is a series of processing steps that any request must travel -through before (and after) executing the registered ``Handler``. Some -examples are a logger (that records the time before executing the -transaction, then outputs info - including duration - after the -execution), of a signature checker (which unwraps the transaction by one -layer, verifies signatures, and adds the permissions to the Context -before passing the request along). - -In keeping with the standardization of ``http.Handler`` and inspired by -the super minimal -`negroni `__ -package, we just provide one more ``Middleware`` interface, which has an -extra ``next`` parameter, and a ``Stack`` that can wire all the levels -together (which also gives us a place to perform isolation of each -step). - -.. code:: golang - - Name() string - CheckTx(ctx Context, store state.KVStore, tx Tx, next Checker) (Result, error) - DeliverTx(ctx Context, store state.KVStore, tx Tx, next Deliver) (Result, error) - SetOption(l log.Logger, store state.KVStore, module, key, value string, next Optioner) (string, error) - -Modules -------- - -A module is a set of functionality which should be typically designed as -self-sufficient. Common elements of a module are: - -- transaction types (either end transactions, or transaction wrappers) -- custom error codes -- data models (to persist in the kv-store) -- handler (to handle any end transactions) -- middleware (to handler any wrapper transactions) - -To enable a module, you must add the appropriate middleware (if any) to -the stack in ``main.go`` for the client application (default: -``basecli/main.go``), as well as adding the handler (if any) to the -dispatcher (default: ``app/app.go``). Once the stack is compiled into a -``Handler``, then each transaction is handled by the appropriate module. - -Dispatcher ----------- - -We usually will want to have multiple modules working together, and need -to make sure the correct transactions get to the correct module. So we -have ``coin`` sending money, ``roles`` to create multi-sig accounts, and -``ibc`` for following other chains all working together without -interference. - -After the chain of middleware, we can register a ``Dispatcher``, which -also implements the ``Handler`` interface. We then register a list of -modules with the dispatcher. Every module has a unique ``Name()``, which -is used for isolating its state space. We use this same name for routing -transactions. Each transaction implementation must be registed with -go-wire via ``TxMapper``, so we just look at the registered name of this -transaction, which should be of the form ``/xxx``. The -dispatcher grabs the appropriate module name from the tx name and routes -it if the module is present. - -This all seems like a bit of magic, but really we're just making use of -go-wire magic that we are already using, rather than add another layer. -For all the transactions to be properly routed, the only thing you need -to remember is to use the following pattern: - -.. code:: golang - - const ( - NameCoin = "coin" - TypeSend = NameCoin + "/send" - ) - -Inter-Plugin Communication (IPC) --------------------------------- - -But wait, there's more... since we have isolated all the modules from -each other, we need to allow some way for them to interact in a -controlled fashion. One example is the ``fee`` middleware, which wants -to deduct coins from the calling account and can be accomplished most -easily with the ``coin`` module. - -To make a call from the middleware, we the ``next`` Handler, which will -execute the rest of the stack. It can create a new SendTx and pass it -down the stack. If it returns success, do the rest of the processing -(and send the original transaction down the stack), otherwise abort. - -However, if one ``Handler`` inside the ``Dispatcher`` wants to do this, -it becomes more complex. The solution is that the ``Dispatcher`` accepts -not a ``Handler``, but a ``Dispatchable``, which looks like a -middleware, except that the ``next`` argument is a callback to the -dispatcher to execute a sub-transaction. If a module doesn't want to use -this functionality, it can just implement ``Handler`` and call -``stack.WrapHandler(h)`` to convert it to a ``Dispatchable`` that never -uses the callback. - -One example of this is the counter app, which can optionally accept a -payment. If the transaction contains a payment, it must create a SendTx -and pass this to the dispatcher to deduct the amount from the proper -account. Take a look at `counter -plugin `__\ for -a better idea. - -Permissions ------------ - -IPC requires a more complex permissioning system to allow the modules to -have limited access to each other and also to allow more types of -permissions than simple public key signatures. Rather than just use an -address to identify who is performing an action, we can use a more -complex structure: - -.. code:: golang - - type Actor struct { - ChainID string `json:"chain"` // this is empty unless it comes from a different chain - App string `json:"app"` // the app that the actor belongs to - Address data.Bytes `json:"addr"` // arbitrary app-specific unique id - } - -Here, the ``Actor`` abstracts any address that can authorize actions, -hold funds, or initiate any sort of transaction. It doesn't just have to -be a pubkey on this chain, it could stem from another app (such as -multi-sig account), or even another chain (via IBC) - -``ChainID`` is for IBC, discussed below. Let's focus on ``App`` and -``Address``. For a signature, the App is ``auth``, and any modules can -check to see if a specific public key address signed like this -``ctx.HasPermission(auth.SigPerm(addr))``. However, we can also -authorize a tx with ``roles``, which handles multi-sig accounts, it -checks if there were enough signatures by checking as above, then it can -add the role permission like -``ctx= ctx.WithPermissions(NewPerm(assume.Role))`` - -In addition to the permissions schema, the Actors are addresses just -like public key addresses. So one can create a mulit-sig role, then send -coin there, which can only be moved upon meeting the authorization -requirements from that module. ``coin`` doesn't even know the existence -of ``roles`` and one could build any other sort of module to provide -permissions (like bind the outcome of an election to move coins or to -modify the accounts on a role). - -One idea - not yet implemented - is to provide scopes on the -permissions. Currently, if I sign a transaction to one module, it can -pass it on to any other module over IPC with the same permissions. It -could move coins, vote in an election, or anything else. Ideally, when -signing, one could also specify the scope(s) that this signature -authorizes. The `oauth -protocol `__ also has to deal -with a similar problem, and maybe could provide some inspiration. - -Replay Protection ------------------ - -In order to prevent `replay -attacks `__ a multi account -nonce system has been constructed as a module, which can be found in -``modules/nonce``. By adding the nonce module to the stack, each -transaction is verified for authenticity against replay attacks. This is -achieved by requiring that a new signed copy of the sequence number -which must be exactly 1 greater than the sequence number of the previous -transaction. A distinct sequence number is assigned per chain-id, -application, and group of signers. Each sequence number is tracked as a -nonce-store entry where the key is the marshaled list of actors after -having been sorted by chain, app, and address. - -.. code:: golang - - // Tx - Nonce transaction structure, contains list of signers and current sequence number - type Tx struct { - Sequence uint32 `json:"sequence"` - Signers []basecoin.Actor `json:"signers"` - Tx basecoin.Tx `json:"tx"` - } - -By distinguishing sequence numbers across groups of Signers, -multi-signature Actors need not lock up use of their Address while -waiting for all the members of a multi-sig transaction to occur. Instead -only the multi-sig account will be locked, while other accounts -belonging to that signer can be used and signed with other sequence -numbers. - -By abstracting out the nonce module in the stack, entire series of -transactions can occur without needing to verify the nonce for each -member of the series. An common example is a stack which will send coins -and charge a fee. Within the SDK this can be achieved using separate -modules in a stack, one to send the coins and the other to charge the -fee, however both modules do not need to check the nonce. This can occur -as a separate module earlier in the stack. - -IBC (Inter-Blockchain Communication) ------------------------------------- - -Stay tuned! diff --git a/_attic/modules/docs/graphics/README.md b/_attic/modules/docs/graphics/README.md deleted file mode 100644 index aefc54550e..0000000000 --- a/_attic/modules/docs/graphics/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Usage - -Graphics can be imported and edited with the draw.io tool: -https://www.draw.io/?mode=github - -Images can be exported from the draw.io directly to this github repo. -All diagrams are saved to the single .xml file. To export each infographic -select the relevant elements and then export to .png using the following settings: - -- Selection Only -- Crop -- Zoom: 200% -- Borderwidth: 20 diff --git a/_attic/modules/docs/graphics/cosmos-sdk-image.png b/_attic/modules/docs/graphics/cosmos-sdk-image.png deleted file mode 100644 index 666dff22cd..0000000000 Binary files a/_attic/modules/docs/graphics/cosmos-sdk-image.png and /dev/null differ diff --git a/_attic/modules/docs/graphics/datastore.png b/_attic/modules/docs/graphics/datastore.png deleted file mode 100644 index c659c87631..0000000000 Binary files a/_attic/modules/docs/graphics/datastore.png and /dev/null differ diff --git a/_attic/modules/docs/graphics/dispatcher.png b/_attic/modules/docs/graphics/dispatcher.png deleted file mode 100644 index 424a87b94a..0000000000 Binary files a/_attic/modules/docs/graphics/dispatcher.png and /dev/null differ diff --git a/_attic/modules/docs/graphics/infographic.xml b/_attic/modules/docs/graphics/infographic.xml deleted file mode 100644 index a2165cd16e..0000000000 --- a/_attic/modules/docs/graphics/infographic.xml +++ /dev/null @@ -1 +0,0 @@ -7T1rk+I4kr+G2N0PRVjy+2NXddfORczcTkz3xex9NEaArwxmbFOP/fWnp209MC6QKaqhIpoG2ZLlfCmVmcqcuA/r13+WyXb1WzFH+QQ689eJ+3UCIfAiiP8jLW+sxQ3Z72WZzfk9bcP37D+INzq8dZfNUSXdWBdFXmdbuTEtNhuU1lJbUpbFi3zbosjlp26TJdIavqdJrrf+mc3rFW8FjtNe+AVlyxV/dOTzC7MkfVqWxW7DnzeB7oL+scvrRIzF769Wybx46TS53ybuQ1kUNfu2fn1AOQGtABvr97jnajPvEm3qIR2gG7Muz0m+Q2LOdGb1m4AG7oIBj3/c4+luSWOaFzs8wv3LKqvR922SksYXTAq4bVWvc/wLkNvrsnhCD0VelHQk16F/+Moiy3PRvik2ZOxFsak5JQDAf3e6kr9H/Br3SZ4tN7gtRwv8ivf6G3MgPKOyRq+dJg6Bf6JijeryDd/Cr3oOf+c3gWeXj/HSIh+CiLWtOniHIe+ZcIJbNoO3QMdfONz34UBDwe+oXGdVlRWbbLPU8IFfq+4DtACoDmMBuxQDC+H2ewKkDNP9F35hnc3n5DFGzHYwBB0dQy1yyX18ugaKfDd+QkdCTxw5GnaA5+jYEW0nIcfTkPMtSVdk1O02x6CrMZLI/RX+KHf0K/lIJoTzgpwgKsNfluRLlWzms+JVtONnN5eohKPjFHlSI4JwlO7KrCZwKLPqqZriL3+uEHsCxt4iSSlxODNUvyDa3pkSns4DuXPB50Lwjz/Jz3pVVMj8Ammx3pYFJj00pzeS2zDespJ82eDnFOUTlVrFLp9ToswotGbNhBGZ5o8VHY1+YGBl6JmPhyXjksIurTHVYLKQ6dx5WaESzcgrIwbkdJUQcD7QPimWqzX7QXvLL5Am5BNP/xmvHXP+2ngVwYSNATqXnkbXhLJ5xbpMNhWeEx8Iky/hMI4R3Avfu+YDVluUZossZS+BO0wFNmdli0u15aEZksJkm1SVAhE2EcZ+LwmFNyYW8gZZtU3qFAOGgyHPixcGLYZTOslkLr9gRS/TcRkWttu7inIzG4QOjQdNCTox2ih3KgPor2VdDnEZrkqhutgeFkHA7RFBNqQOkBcFB7ia2PG8WBc7jZZwktzxDesyw8g8e5bwEPy1I+rCfZ5t0J2YyBd8C52I394gEFm/NuyyLp4RJfmMkcyC9mzEE32UTNSGpl2utuSNXKM8izi37mcV/Kw82z9KUWbLbJMQABF+JuMN6vdf9w9Nl6q3D27UX2MIBJI1ocvNrNp2ILvB8FYuWYUqFkjLDt4GwYKjusK0yAQHyiv0t2rQKIOgc1XSwQtkpQSA2KCVBAatBIQWxINQ27ta+hxvYfhPDki6EUGkiyNj4v9QXb9xSCU7vIIQFsN6wbLATPZrQQD8FdgAaFXsypRP0OUirU4w8fLb3IC1kcn3gr1EWC3KnuX92UkQ1AXsd6oqYB2m0oDbbHywgoRhS95SJVOyvOJ1+Vf66yt+sRP2P32w7qDRAh0DqNAxdHydjqGBjgMLZOwZNpsdMm5p8lvbup+qMRTKt3+T9mkQ+qLhf3HDnTN1nEi04N1VhqdKNkB0iI/hhkDnBg/Y5gba9UtZJm+dG7ZY3tdVZ+TfSUOHJiKFJtzY72JV6wAj0NsBf2FzaImieZlhdOLapJPLwbfzOfGtCQ3b+BbA6ghnqspdr1SOziiV3ciw91BALzOXbY4aAk2JuUKDauF/mGoRavD7tt5SS05jCDioLGMtJPtPMqM3EJBwJsZ3+/cT/yuhdAzoigNzqNbM2eEHxcidd16dGbiqzuyHOlU7BqqGNnQNR8PKQ0GMS9ciVNQdiwfOqekBA/S5aeBaEACdD8WAyaKkgL7zvqr8mBV1XaypCj3/QlxspC0v0qd3gLOrs6F8Vrx01TXagC+IB2saHHrN6n/z2ZHvRLHHmj7/pSr1nc2AGzS7A9bHAeG+vcCg5abZ63fXm3DoesOpAe9JsPyDEkXcCSfT+xQ+XUHzXZnS4sCXx2Cvw7u1RHSy6hhHbnc8Cx0UEDWvsv8J7+0Qyx0wm4a9HaCjdgD9HfQnHOoQ9U9JVrDb7gJtxWJRoVrp8e5Nl66EY6UEi2TiPTpNcBRbtCFWz6RaUfZm/CkCAaIOszvT2Aklhmcb+cEixyAaBvH4EewMQyFjBTsLHfREdoZBqJK0siAwQaSx81iUoSu4xHZGXVpXreFqG+nQYBQeTcHVt21fCHR7XIS6Q4Z5iN+2aGLyX2fLrp8ge4ft/ydENvQ102mkY9vkAnBtYFsP3DkS20VNncvM166bvq8UlyaDy1i49PWt6SFcUszpCN3HuY0b1sS8sqOSxkUYBiBb5Rvrc6R76k7ONQj6cCxygRq5fE1qEp3yvS5KXTm7tnixQGHmONAjN4wBY74N5OgBY9YCNwzRAj/kGK01Kp+Y4CgRDRCgUR5JmqKKhgHRqc4xsXSiyV7YjfQSIaJ1Md/RMf5ORUEbk/QPFjxE719mNJoALx3r7gOYvCJvuZuJKRQl2zbMWdQSvQX3y8jgyXY73RcpgTl8I7/mtkSL7JUNwyLMNs9ZlVFRSWY22xFVd1NMeLQJf/262NFgMrHQzSmz7AtF6Yu7+Fps/lZPeBAWe0rz1i9lRuP2eKQdeValPOxAhMb/bLK/du17IvaG+OMJEerm8VusiQ2LiYky/BGhG13o9semXHWcR+DLWzpjGJhrkvSRf7owEVYb6/5xP5JMYsQWFTYtH+Yf/2A/aOR6Mq5B0G+midV9udJhn5mmeZ4/dWAMYIB3in4s3qcZTGyzD9jsTNOaijGh6zrquJE7DRwQeyD0Qj+EylP2mBKOMBMEwUjUS3x7skE38G/E+07iDWKVLi6CeIPYmRKqjIDvu24cqbQbmUjbPu1Cx2rISYVnVgvrJ1/+aNsjCaAXHgvVPopbOteHUnKPJ6ylcbdPId9L410DqW8IaPGjC+EFZdEWO/d9RHeow8kBLb5uS29UdXra6yq30WEcKGCHekBANJK5FMT9MbQ3DvcNUTXCBHb+qBpfdzq0O2RmnnrsbpmvkaEC1QEBIp2h/JEYqglvuDHUPoaKDAxlXX0czFCmML+WobjB+Op5KlKjdkw8ZTIA2OEpoEH9xlMST8UGnoIfxlOm4/SCf7JZeuMnGHuqrm3gJ5N13gY/Bbqn7cqCQNUo0AbUHejHBujbCEEUa901B4GGUTgAAcFICIAaAv5FvAnfa5pz4FpwEANwGAfAMST8sIGEUOeCb68o3fH0AxgX5FT+waXh5/bhqotEGBviMUxalw0fbjiiD/e3boqHhrO4c5Y6FVlmirSYU+MQ2lXJLMtZIhCWt4Gk/1iWvJU4cr/QKeGLSUmu0wA/FiEiJ5QomXOxzZDB0kBQJ+mM5Z94vcONd2uacWJOwV3TPBy7igRxygP2HOa/XoehGkgUeQZ/oUm9iWwQrh7j/2uxXDKPuY6wv1NXef36j+sR/SCIJfxABxqCQ0YT/boZ+A+UFnj6bzfsmLADwDkXZn3z9sBS5KioucpMARpuTEvyWLiJ9I3bH2ibJwa++b0sasSTOV0PcmRHaQuwsyBH12gfERqSQup6EGI+CjAWQvR9njUFNi/IIQCn2jVBhVSLRGVZlEaU35RCPBhUtA7XoHW4pu2MZ4Ea9AST1qjhge4UWFK7TZa29IC3GYQ+6CURJVrd6OQQnci7B7P+A6FBaoQW6GTEbS+GQbbIBDWwJJZpidZ878vSH1borx3a0CDXzW49a88r3Mikn0wag2GXTEx+XpFw6SQyGTE1YYdMKqFj34hg2Jpi1MdNawq0QQT6TtbemiKMTZ28rHTp6C4s1KZxI4wh0sELDGlWQoPq6VpQNuL+uMlzZyZUjpg3IcSO402kEOLQ35sfbi9OLIc56ue+vX3mkPdG1eKRph6W3CHgn3KwMHQid9q9LD9lT1jt/rDMEwJvY+8k+ulGiUcTJeuHPwKBGSmmzV7gQG/SzV5ArCjvzEowNpWBOJ5CJ8briQt9PwIm0iDtbuy7XqQeaxlKgQeegrfC08gNxR3BiQS4dw7qU+3mrYv7z+vciHd04lUCuYmPcAzq1R4T+x9BvjyvjDXy7T+wc1u7T1m7NQefrbUbE+SlrN3hRdHPTyXIKJatCDKVLIedoRqHYKKLIhgbAqclOpaCWtDch8qiwJ12BARUSMAN4u5l90gxFXiymFIe4jmXIqUuK3f+MVJKUhRjVVMM3r0YdoOnowsReJRgRhB4bnCqdnYC7TXJvy6E+H4uFauxgNpWsUAQXYjwAuJASF8a18arvivzt/sySZ8Icx+q1tcS3Um1+/rIzX7tvubEaF88lyimJBeHs+AxA47uWv2tJ0Lyl2SDr5WfMcma9QBfBW/AEB9hOvprI4EWcEyezhsTtR4DT/cYmJjIhtdZ2OCkePjNfMvE6Y2D9nOQojB5ge7/GysFHXChhrSvnUqFB5Hzc59e8IG6KrkmF9xIxxeAq69KLIFat5iks2KsRB6WrdvkbdIpBHb8gKapmO2qbMMivvJimaX04AGN95moFTSVIpc84RvRCKkHt3nwQ3NBmhiWoTVqo0Lo0+RxaE65lChwLFnddASKu2QXr+8FCn1FegCIL/RUib5cC/TlnWbn65wwTnNMJRi73UPGH1aiCQj/d3c7DD6ujkwzH6N2eUWh536kxjsBQ6ZlU6iLjWBa4Fs9g3+51G+ozwjEFvuDMzoFmrIDD2Q3g/0dTvaVNSU27OdmlCwvn45ihAbz2ShGPZhtn2IMJUd7dObrkeaud05p7tmL0fhEnGpI1teoFx+h2ejho98xnH68ari5/H29DZYI1HgSQ8pyU/UBK4nwvNPCPjocEX4ijjAkt/tIjhCpOT4m0dMzrbd2HF4GJXoa6AKVa7sJB7rqcZK8VuTH70mNr25oC6Suq2FEILhs5A3fUQpMGKpngfj5nL0KjNrB9W0rMHoKRp6/51oFt5oe3ii4R8tg6uqRDOcLW2ilB5cvcpq49/L0MIYV55fGdi37vmpx8I/MZ+2rXKlpsfaSVgNDjVtrp3IMFuQ5wd+aWIUJweO2pmQRNeFOhLlWtg4n9aRjD+Z+HmEUJlblX+hAxDgsdELMTfRFZ0iMPRdPYunb+KHTjjTq6aIUQ7odH5ITlIXKPhianIEmb2BoxbYMDSS8b2t84a7ZsqgTSvR4YSKFT63gxwtV27/QWrsZhgwJ5NzYhrdWhMacbvs3LhvjRddZXYbOozcOR4rphP9PwzRcI3SmgU9ChiPf8UMvdOJePf89DKWk6vBMKbtMGRmt8JMh6dBVZSTVzIGm4JOxMpICv98aePm+nS4ecfuC/pkwT/4eH1XbQDvNrnlA7Ksbxh8mFkcy/es7XaDudNWlzdKJqwjuedDePfi+mdlzO5kyGF9bDl2x8e0VGSPl0AWGCo+P6Iqy50bqjva80LdcVOwTCOxWh1VPFDWmd6maH7tvRDF/njCZPSLZxao83vJ4EQz9KBADNLR4rJ0mBPGUDugEURz4vjquE071p1pebmKgJY2LLK8exiI6dgxEX+bzjCjuSZ6/7Y3tW6GclkxdYMmXZyzteCepcBOGuE6eRFnapk3Ub2Uxf9WEZxRLGMk2OY9FbVmeKOZm1CGUpYbDuIZKWwAYcsIAJ7YgtQ2Z/78jvBNlaa3v8L9/4Zd5ztDL+RAzNHK4t0aJ7chhRbOJDGk8m6qH1uOGg5/ajGBF8VTdPb6OH2jaq9owFQS64vlDzpDFMrwvsrIyHJ0o0TKr8D6hm9edSmhz+e224/w9gf0/oZNPiwwzOflGKygPQkM0f9ehYl1efq6zFqo9HITQEE4GDNjxrGBHZ8pvCS03X79O+CkIdpYBy8Blw3NyZYaK1fxwMFxp105JhjlaYAWMsOyOlocnupUzIx+IPSbZbnOMJEILxHn2WLLUeewhu7zOtvT4Rp68sYL0TEd6ZRoaH0OazJrqrJhosi29ndzPitrn6BnlrGOeUf2MzrPY8GerooQeD6mKrjIouwLXOyKo2IumWITV5S7tOOrWGUkW2/RFnSopFGLXduzDU8s7hoFO6r5QIaT1B1og9QOp/SxGPF9cnbrjMCttkONxjKPvTiKlljOMQU+pY627RoLxwJSEx+xWDQUZrFKg0a7SR5tnDVccPcZFrUQWqSdDB8e4HBzJYoyLoRJEU44DNw+KRDu7RjR6ADFQlKDI96d4efBCx48i6Apz1iGFVWXmo9YJkUHmKrhUsowK2pQEf2Rd8A/HBNR45b8LlmD9xicMQqF7FJ/4NrCjbx2a1Nc39HDtYuBOG9iwUhoy2/+Jmu3Y/G2TrAnU6Bas2a7Q3RTb4dHIRlo7z7zNo3uwEfB6ooFzdPuJ4hQni5OG1aZ6vHX7iSFV/Rd6h1SKcdUkFnGqVbHLySZU5EJA6xma85KJ5SzDe1j6evUYPPrZcBkbSqdCk7XFCi5jXfkT9srtxOS9WuOVONswx5WzJRYZCgeHtd/RbT255nWuESTecXyQa1xsSpfnKC1KbmAm9xDlpSSuMt0v1hhURcMfpMxJa6HFLz0zRCBv1bZVqbYc9cqMwMjFiFzUii9g2iFE3BccrU1tjInwmsTqNMjCaJqIwohm+43CZKTw4iKnJoQFNRxInAT570cs9XNC7r+g/BmRUfs4/IA3w8YiqXKgq0tTYJKmoQ2lJTYV/lC1fS3Idxi4Rt8xd81kPSLqxI2156rr3bGpn7WRQn9Y8spjNtaxKTbghlnJ0KHgo63j9l7Mxi44MJJNzEYaZh/LZI1eipJ4HW7u9/1lxw2JZtzAcPbFhnYDHbuxbeZM1L1Hto85Ozy68b2XAvYiXTbMmELWROP5DTONgjwk0oJqlQYO/JOTpDFsdLEYFFHRC1r7iSabCgHtYUj97BIABv6yYZhsrDZSEWEy+wlxYuIPWu6Znh58TLKcGpTPJQ6HORiBjq7HRxIoOhZ+DEdhGjElnWe2wRUicubIs2XvFFyzvEifJseG+2oc1+DhZHyNnjdbw7KaXH2P7jFgpBAO0oeO0GKgEJFXJzOVZOSeKZfoaDIT6tFHssz8inJMiuVVS00VQ0DPxjmi1DztRO5Nag6VmiqW/ehYqamO5Cny16bU1O01LJNDc2qMuTcOBYGmK/J2ExZuX6G0oAkX9PsWhqNQlxElaqCq5oiNBSkQaSH2hpy8RrucjThECHXrzX2TsVlF0q8spfKexfOnO7FGCukorGsoq+4YTj/YOLIG4WVVuWrtAuSUnmIYODYlwrmqBkHnQNUg30rVIKhEybUU8xFFX6Co2HUhFPS5qwYFh1A7vOKZI1UNEhbcVlGXS56dekb9FAoS5uZurMmqKCrq+qZObhpxzbzgExG9gBfzSlcNLku5H9nhrVVTdw0x18DkcxCZjE5aOwx1Nh4pUm4RQuzuKIYfFcAFDfn5NZzIQvnAMbljdaneAzf2TRJepEWbmo7BGY4pAit+EkMi7euAe6xFLxr0WFO6SWAj3yQ05P+8Crj7jhrfHhvgbsrPHFsBu+6+vQ6wK+kQ2rMmUqJ4w3En34Z0907zRnS2WT3uV3iq+/WD7HGHLSfd3aEwjXTdr/Bc6fLwz7IgoWWt7ow5YvVbMUfkjv8H \ No newline at end of file diff --git a/_attic/modules/docs/graphics/middleware.png b/_attic/modules/docs/graphics/middleware.png deleted file mode 100644 index eea0692f01..0000000000 Binary files a/_attic/modules/docs/graphics/middleware.png and /dev/null differ diff --git a/_attic/modules/docs/graphics/overview-framework.png b/_attic/modules/docs/graphics/overview-framework.png deleted file mode 100644 index c9d507dce5..0000000000 Binary files a/_attic/modules/docs/graphics/overview-framework.png and /dev/null differ diff --git a/_attic/modules/docs/graphics/overview-security.png b/_attic/modules/docs/graphics/overview-security.png deleted file mode 100644 index c507a9cee5..0000000000 Binary files a/_attic/modules/docs/graphics/overview-security.png and /dev/null differ diff --git a/_attic/modules/docs/graphics/permission.png b/_attic/modules/docs/graphics/permission.png deleted file mode 100644 index 1dd0f2a2b8..0000000000 Binary files a/_attic/modules/docs/graphics/permission.png and /dev/null differ diff --git a/_attic/modules/docs/graphics/tx.png b/_attic/modules/docs/graphics/tx.png deleted file mode 100644 index 7318c43a10..0000000000 Binary files a/_attic/modules/docs/graphics/tx.png and /dev/null differ diff --git a/_attic/modules/docs/guide/shunit2 b/_attic/modules/docs/guide/shunit2 deleted file mode 100644 index f347ca565d..0000000000 --- a/_attic/modules/docs/guide/shunit2 +++ /dev/null @@ -1,1067 +0,0 @@ -#! /bin/sh -# $Id$ -# vim:et:ft=sh:sts=2:sw=2 -# -# Copyright 2008 Kate Ward. All Rights Reserved. -# Released under the LGPL (GNU Lesser General Public License) -# -# shUnit2 -- Unit testing framework for Unix shell scripts. -# http://code.google.com/p/shunit2/ -# -# Author: kate.ward@forestent.com (Kate Ward) -# -# shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is -# based on the popular JUnit unit testing framework for Java. - -# return if shunit already loaded -[ -n "${SHUNIT_VERSION:-}" ] && exit 0 -SHUNIT_VERSION='2.1.7pre' - -# return values that scripts can use -SHUNIT_TRUE=0 -SHUNIT_FALSE=1 -SHUNIT_ERROR=2 - -# logging functions -_shunit_warn() { echo "shunit2:WARN $@" >&2; } -_shunit_error() { echo "shunit2:ERROR $@" >&2; } -_shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } - -# determine some reasonable command defaults -__SHUNIT_UNAME_S=`uname -s` -case "${__SHUNIT_UNAME_S}" in - BSD) __SHUNIT_EXPR_CMD='gexpr' ;; - *) __SHUNIT_EXPR_CMD='expr' ;; -esac - -# commands a user can override if needed -SHUNIT_EXPR_CMD=${SHUNIT_EXPR_CMD:-${__SHUNIT_EXPR_CMD}} - -# enable strict mode by default -SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} - -# specific shell checks -if [ -n "${ZSH_VERSION:-}" ]; then - setopt |grep "^shwordsplit$" >/dev/null - if [ $? -ne ${SHUNIT_TRUE} ]; then - _shunit_fatal 'zsh shwordsplit option is required for proper operation' - fi - if [ -z "${SHUNIT_PARENT:-}" ]; then - _shunit_fatal "zsh does not pass \$0 through properly. please declare \ -\"SHUNIT_PARENT=\$0\" before calling shUnit2" - fi -fi - -# -# constants -# - -__SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' -__SHUNIT_MODE_SOURCED='sourced' -__SHUNIT_MODE_STANDALONE='standalone' -__SHUNIT_PARENT=${SHUNIT_PARENT:-$0} - -# set the constants readonly -__shunit_constants=`set |grep '^__SHUNIT_' |cut -d= -f1` -echo "${__shunit_constants}" |grep '^Binary file' >/dev/null && \ - __shunit_constants=`set |grep -a '^__SHUNIT_' |cut -d= -f1` -for __shunit_const in ${__shunit_constants}; do - if [ -z "${ZSH_VERSION:-}" ]; then - readonly ${__shunit_const} - else - case ${ZSH_VERSION} in - [123].*) readonly ${__shunit_const} ;; - *) readonly -g ${__shunit_const} # declare readonly constants globally - esac - fi -done -unset __shunit_const __shunit_constants - -# -# internal variables -# - -# variables -__shunit_lineno='' # line number of executed test -__shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode -__shunit_reportGenerated=${SHUNIT_FALSE} # is report generated -__shunit_script='' # filename of unittest script (standalone mode) -__shunit_skip=${SHUNIT_FALSE} # is skipping enabled -__shunit_suite='' # suite of tests to execute - -# counts of tests -__shunit_testSuccess=${SHUNIT_TRUE} -__shunit_testsTotal=0 -__shunit_testsPassed=0 -__shunit_testsFailed=0 - -# counts of asserts -__shunit_assertsTotal=0 -__shunit_assertsPassed=0 -__shunit_assertsFailed=0 -__shunit_assertsSkipped=0 - -# macros -_SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' - -#----------------------------------------------------------------------------- -# private functions - -#----------------------------------------------------------------------------- -# assert functions -# - -# Assert that two values are equal to one another. -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertEquals() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertEquals() requires two or three arguments; $# given" - _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_expected_=$1 - shunit_actual_=$2 - - shunit_return=${SHUNIT_TRUE} - if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then - _shunit_assertPass - else - failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" - shunit_return=${SHUNIT_FALSE} - fi - - unset shunit_message_ shunit_expected_ shunit_actual_ - return ${shunit_return} -} -_ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' - -# Assert that two values are not equal to one another. -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertNotEquals() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertNotEquals() requires two or three arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_expected_=$1 - shunit_actual_=$2 - - shunit_return=${SHUNIT_TRUE} - if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then - _shunit_assertPass - else - failSame "${shunit_message_}" "$@" - shunit_return=${SHUNIT_FALSE} - fi - - unset shunit_message_ shunit_expected_ shunit_actual_ - return ${shunit_return} -} -_ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' - -# Assert that a value is null (i.e. an empty string) -# -# Args: -# message: string: failure message [optional] -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertNull() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 1 -o $# -gt 2 ]; then - _shunit_error "assertNull() requires one or two arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - assertTrue "${shunit_message_}" "[ -z '$1' ]" - shunit_return=$? - - unset shunit_message_ - return ${shunit_return} -} -_ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' - -# Assert that a value is not null (i.e. a non-empty string) -# -# Args: -# message: string: failure message [optional] -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertNotNull() -{ - ${_SHUNIT_LINENO_} - if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null - _shunit_error "assertNotNull() requires one or two arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` - test -n "${shunit_actual_}" - assertTrue "${shunit_message_}" $? - shunit_return=$? - - unset shunit_actual_ shunit_message_ - return ${shunit_return} -} -_ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' - -# Assert that two values are the same (i.e. equal to one another). -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertSame() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertSame() requires two or three arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - assertEquals "${shunit_message_}" "$1" "$2" - shunit_return=$? - - unset shunit_message_ - return ${shunit_return} -} -_ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' - -# Assert that two values are not the same (i.e. not equal to one another). -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertNotSame() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertNotSame() requires two or three arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then - shunit_message_="${shunit_message_:-}$1" - shift - fi - assertNotEquals "${shunit_message_}" "$1" "$2" - shunit_return=$? - - unset shunit_message_ - return ${shunit_return} -} -_ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' - -# Assert that a value or shell test condition is true. -# -# In shell, a value of 0 is true and a non-zero value is false. Any integer -# value passed can thereby be tested. -# -# Shell supports much more complicated tests though, and a means to support -# them was needed. As such, this function tests that conditions are true or -# false through evaluation rather than just looking for a true or false. -# -# The following test will succeed: -# assertTrue 0 -# assertTrue "[ 34 -gt 23 ]" -# The following test will fail with a message: -# assertTrue 123 -# assertTrue "test failed" "[ -r '/non/existent/file' ]" -# -# Args: -# message: string: failure message [optional] -# condition: string: integer value or shell conditional statement -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertTrue() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 1 -o $# -gt 2 ]; then - _shunit_error "assertTrue() takes one or two arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_condition_=$1 - - # see if condition is an integer, i.e. a return value - shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` - shunit_return=${SHUNIT_TRUE} - if [ -z "${shunit_condition_}" ]; then - # null condition - shunit_return=${SHUNIT_FALSE} - elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] - then - # possible return value. treating 0 as true, and non-zero as false. - [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} - else - # (hopefully) a condition - ( eval ${shunit_condition_} ) >/dev/null 2>&1 - [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} - fi - - # record the test - if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then - _shunit_assertPass - else - _shunit_assertFail "${shunit_message_}" - fi - - unset shunit_message_ shunit_condition_ shunit_match_ - return ${shunit_return} -} -_ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' - -# Assert that a value or shell test condition is false. -# -# In shell, a value of 0 is true and a non-zero value is false. Any integer -# value passed can thereby be tested. -# -# Shell supports much more complicated tests though, and a means to support -# them was needed. As such, this function tests that conditions are true or -# false through evaluation rather than just looking for a true or false. -# -# The following test will succeed: -# assertFalse 1 -# assertFalse "[ 'apples' = 'oranges' ]" -# The following test will fail with a message: -# assertFalse 0 -# assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" -# -# Args: -# message: string: failure message [optional] -# condition: string: integer value or shell conditional statement -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertFalse() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 1 -o $# -gt 2 ]; then - _shunit_error "assertFalse() quires one or two arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_condition_=$1 - - # see if condition is an integer, i.e. a return value - shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` - shunit_return=${SHUNIT_TRUE} - if [ -z "${shunit_condition_}" ]; then - # null condition - shunit_return=${SHUNIT_FALSE} - elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] - then - # possible return value. treating 0 as true, and non-zero as false. - [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} - else - # (hopefully) a condition - ( eval ${shunit_condition_} ) >/dev/null 2>&1 - [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} - fi - - # record the test - if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then - _shunit_assertPass - else - _shunit_assertFail "${shunit_message_}" - fi - - unset shunit_message_ shunit_condition_ shunit_match_ - return ${shunit_return} -} -_ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' - -#----------------------------------------------------------------------------- -# failure functions -# - -# Records a test failure. -# -# Args: -# message: string: failure message [optional] -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -fail() -{ - ${_SHUNIT_LINENO_} - if [ $# -gt 1 ]; then - _shunit_error "fail() requires zero or one arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 1 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - - _shunit_assertFail "${shunit_message_}" - - unset shunit_message_ - return ${SHUNIT_FALSE} -} -_FAIL_='eval fail --lineno "${LINENO:-}"' - -# Records a test failure, stating two values were not equal. -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -failNotEquals() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "failNotEquals() requires one or two arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_expected_=$1 - shunit_actual_=$2 - - _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" - - unset shunit_message_ shunit_expected_ shunit_actual_ - return ${SHUNIT_FALSE} -} -_FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' - -# Records a test failure, stating two values should have been the same. -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -failSame() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "failSame() requires two or three arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - - _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" - - unset shunit_message_ - return ${SHUNIT_FALSE} -} -_FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' - -# Records a test failure, stating two values were not equal. -# -# This is functionally equivalent to calling failNotEquals(). -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -failNotSame() -{ - ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "failNotEquals() requires one or two arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - failNotEquals "${shunit_message_}" "$1" "$2" - shunit_return=$? - - unset shunit_message_ - return ${shunit_return} -} -_FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' - -#----------------------------------------------------------------------------- -# skipping functions -# - -# Force remaining assert and fail functions to be "skipped". -# -# This function forces the remaining assert and fail functions to be "skipped", -# i.e. they will have no effect. Each function skipped will be recorded so that -# the total of asserts and fails will not be altered. -# -# Args: -# None -startSkipping() -{ - __shunit_skip=${SHUNIT_TRUE} -} - -# Resume the normal recording behavior of assert and fail calls. -# -# Args: -# None -endSkipping() -{ - __shunit_skip=${SHUNIT_FALSE} -} - -# Returns the state of assert and fail call skipping. -# -# Args: -# None -# Returns: -# boolean: (TRUE/FALSE constant) -isSkipping() -{ - return ${__shunit_skip} -} - -#----------------------------------------------------------------------------- -# suite functions -# - -# Stub. This function should contains all unit test calls to be made. -# -# DEPRECATED (as of 2.1.0) -# -# This function can be optionally overridden by the user in their test suite. -# -# If this function exists, it will be called when shunit2 is sourced. If it -# does not exist, shunit2 will search the parent script for all functions -# beginning with the word 'test', and they will be added dynamically to the -# test suite. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -# Adds a function name to the list of tests schedule for execution. -# -# This function should only be called from within the suite() function. -# -# Args: -# function: string: name of a function to add to current unit test suite -suite_addTest() -{ - shunit_func_=${1:-} - - __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" - __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` - - unset shunit_func_ -} - -# Stub. This function will be called once before any tests are run. -# -# Common one-time environment preparation tasks shared by all tests can be -# defined here. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -# Stub. This function will be called once after all tests are finished. -# -# Common one-time environment cleanup tasks shared by all tests can be defined -# here. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -# Stub. This function will be called before each test is run. -# -# Common environment preparation tasks shared by all tests can be defined here. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#setUp() { :; } - -# Note: see _shunit_mktempFunc() for actual implementation -# Stub. This function will be called after each test is run. -# -# Common environment cleanup tasks shared by all tests can be defined here. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -#------------------------------------------------------------------------------ -# internal shUnit2 functions -# - -# Create a temporary directory to store various run-time files in. -# -# This function is a cross-platform temporary directory creation tool. Not all -# OSes have the mktemp function, so one is included here. -# -# Args: -# None -# Outputs: -# string: the temporary directory that was created -_shunit_mktempDir() -{ - # try the standard mktemp function - ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return - - # the standard mktemp didn't work. doing our own. - if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then - _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" -#! /bin/sh -exit ${SHUNIT_TRUE} -EOF - chmod +x "${_shunit_file_}" - done - - unset _shunit_file_ -} - -# Final cleanup function to leave things as we found them. -# -# Besides removing the temporary directory, this function is in charge of the -# final exit code of the unit test. The exit code is based on how the script -# was ended (e.g. normal exit, or via Ctrl-C). -# -# Args: -# name: string: name of the trap called (specified when trap defined) -_shunit_cleanup() -{ - _shunit_name_=$1 - - case ${_shunit_name_} in - EXIT) _shunit_signal_=0 ;; - INT) _shunit_signal_=2 ;; - TERM) _shunit_signal_=15 ;; - *) - _shunit_warn "unrecognized trap value (${_shunit_name_})" - _shunit_signal_=0 - ;; - esac - - # do our work - rm -fr "${__shunit_tmpDir}" - - # exit for all non-EXIT signals - if [ ${_shunit_name_} != 'EXIT' ]; then - _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" - # disable EXIT trap - trap 0 - # add 128 to signal and exit - exit `expr ${_shunit_signal_} + 128` - elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then - _shunit_assertFail 'Unknown failure encountered running a test' - _shunit_generateReport - exit ${SHUNIT_ERROR} - fi - - unset _shunit_name_ _shunit_signal_ -} - -# The actual running of the tests happens here. -# -# Args: -# None -_shunit_execSuite() -{ - for _shunit_test_ in ${__shunit_suite}; do - __shunit_testSuccess=${SHUNIT_TRUE} - - # disable skipping - endSkipping - - # execute the per-test setup function - setUp - - # execute the test - echo "${_shunit_test_}" - eval ${_shunit_test_} - - # execute the per-test tear-down function - tearDown - - # update stats - if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then - __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` - else - __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` - fi - done - - unset _shunit_test_ -} - -# Generates the user friendly report with appropriate OK/FAILED message. -# -# Args: -# None -# Output: -# string: the report of successful and failed tests, as well as totals. -_shunit_generateReport() -{ - _shunit_ok_=${SHUNIT_TRUE} - - # if no exit code was provided one, determine an appropriate one - [ ${__shunit_testsFailed} -gt 0 \ - -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ - && _shunit_ok_=${SHUNIT_FALSE} - - echo - if [ ${__shunit_testsTotal} -eq 1 ]; then - echo "Ran ${__shunit_testsTotal} test." - else - echo "Ran ${__shunit_testsTotal} tests." - fi - - _shunit_failures_='' - _shunit_skipped_='' - [ ${__shunit_assertsFailed} -gt 0 ] \ - && _shunit_failures_="failures=${__shunit_assertsFailed}" - [ ${__shunit_assertsSkipped} -gt 0 ] \ - && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" - - if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then - _shunit_msg_='OK' - [ -n "${_shunit_skipped_}" ] \ - && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" - else - _shunit_msg_="FAILED (${_shunit_failures_}" - [ -n "${_shunit_skipped_}" ] \ - && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" - _shunit_msg_="${_shunit_msg_})" - fi - - echo - echo ${_shunit_msg_} - __shunit_reportGenerated=${SHUNIT_TRUE} - - unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ -} - -# Test for whether a function should be skipped. -# -# Args: -# None -# Returns: -# boolean: whether the test should be skipped (TRUE/FALSE constant) -_shunit_shouldSkip() -{ - [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} - _shunit_assertSkip -} - -# Records a successful test. -# -# Args: -# None -_shunit_assertPass() -{ - __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` - __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` -} - -# Records a test failure. -# -# Args: -# message: string: failure message to provide user -_shunit_assertFail() -{ - _shunit_msg_=$1 - - __shunit_testSuccess=${SHUNIT_FALSE} - __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` - __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` - echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" - - unset _shunit_msg_ -} - -# Records a skipped test. -# -# Args: -# None -_shunit_assertSkip() -{ - __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` - __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` -} - -# Prepare a script filename for sourcing. -# -# Args: -# script: string: path to a script to source -# Returns: -# string: filename prefixed with ./ (if necessary) -_shunit_prepForSourcing() -{ - _shunit_script_=$1 - case "${_shunit_script_}" in - /*|./*) echo "${_shunit_script_}" ;; - *) echo "./${_shunit_script_}" ;; - esac - unset _shunit_script_ -} - -# Escape a character in a string. -# -# Args: -# c: string: unescaped character -# s: string: to escape character in -# Returns: -# string: with escaped character(s) -_shunit_escapeCharInStr() -{ - [ -n "$2" ] || return # no point in doing work on an empty string - - # Note: using shorter variable names to prevent conflicts with - # _shunit_escapeCharactersInString(). - _shunit_c_=$1 - _shunit_s_=$2 - - - # escape the character - echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' - - unset _shunit_c_ _shunit_s_ -} - -# Escape a character in a string. -# -# Args: -# str: string: to escape characters in -# Returns: -# string: with escaped character(s) -_shunit_escapeCharactersInString() -{ - [ -n "$1" ] || return # no point in doing work on an empty string - - _shunit_str_=$1 - - # Note: using longer variable names to prevent conflicts with - # _shunit_escapeCharInStr(). - for _shunit_char_ in '"' '$' "'" '`'; do - _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` - done - - echo "${_shunit_str_}" - unset _shunit_char_ _shunit_str_ -} - -# Extract list of functions to run tests against. -# -# Args: -# script: string: name of script to extract functions from -# Returns: -# string: of function names -_shunit_extractTestFunctions() -{ - _shunit_script_=$1 - - # extract the lines with test function names, strip of anything besides the - # function name, and output everything on a single line. - _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' - egrep "${_shunit_regex_}" "${_shunit_script_}" \ - |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ - |xargs - - unset _shunit_regex_ _shunit_script_ -} - -#------------------------------------------------------------------------------ -# main -# - -# determine the operating mode -if [ $# -eq 0 ]; then - __shunit_script=${__SHUNIT_PARENT} - __shunit_mode=${__SHUNIT_MODE_SOURCED} -else - __shunit_script=$1 - [ -r "${__shunit_script}" ] || \ - _shunit_fatal "unable to read from ${__shunit_script}" - __shunit_mode=${__SHUNIT_MODE_STANDALONE} -fi - -# create a temporary storage location -__shunit_tmpDir=`_shunit_mktempDir` - -# provide a public temporary directory for unit test scripts -# TODO(kward): document this -SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" -mkdir "${SHUNIT_TMPDIR}" - -# setup traps to clean up after ourselves -trap '_shunit_cleanup EXIT' 0 -trap '_shunit_cleanup INT' 2 -trap '_shunit_cleanup TERM' 15 - -# create phantom functions to work around issues with Cygwin -_shunit_mktempFunc -PATH="${__shunit_tmpDir}:${PATH}" - -# make sure phantom functions are executable. this will bite if /tmp (or the -# current $TMPDIR) points to a path on a partition that was mounted with the -# 'noexec' option. the noexec command was created with _shunit_mktempFunc(). -noexec 2>/dev/null || _shunit_fatal \ - 'please declare TMPDIR with path on partition with exec permission' - -# we must manually source the tests in standalone mode -if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then - . "`_shunit_prepForSourcing \"${__shunit_script}\"`" -fi - -# execute the oneTimeSetUp function (if it exists) -oneTimeSetUp - -# execute the suite function defined in the parent test script -# deprecated as of 2.1.0 -suite - -# if no suite function was defined, dynamically build a list of functions -if [ -z "${__shunit_suite}" ]; then - shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` - for shunit_func_ in ${shunit_funcs_}; do - suite_addTest ${shunit_func_} - done -fi -unset shunit_func_ shunit_funcs_ - -# execute the tests -_shunit_execSuite - -# execute the oneTimeTearDown function (if it exists) -oneTimeTearDown - -# generate the report -_shunit_generateReport - -# that's it folks -[ ${__shunit_testsFailed} -eq 0 ] -exit $? diff --git a/_attic/modules/docs/ibc.rst b/_attic/modules/docs/ibc.rst deleted file mode 100644 index f7f523ec69..0000000000 --- a/_attic/modules/docs/ibc.rst +++ /dev/null @@ -1,425 +0,0 @@ -InterBlockchain Communication with Basecoin -=========================================== - -One of the most exciting elements of the Cosmos Network is the -InterBlockchain Communication (IBC) protocol, which enables -interoperability across different blockchains. We implemented IBC as a -basecoin plugin, and we'll show you how to use it to send tokens across -blockchains! - -Please note, this tutorial assumes you are familiar with `Basecoin -plugins `__, but we'll explain how IBC -works. You may also want to see `our repository of example -plugins `__. - -The IBC plugin defines a new set of transactions as subtypes of the -``AppTx``. The plugin's functionality is accessed by setting the -``AppTx.Name`` field to ``"IBC"``, and setting the ``Data`` field to the -serialized IBC transaction type. - -We'll demonstrate exactly how this works below. - -IBC ---- - -Let's review the IBC protocol. The purpose of IBC is to enable one -blockchain to function as a light-client of another. Since we are using -a classical Byzantine Fault Tolerant consensus algorithm, light-client -verification is cheap and easy: all we have to do is check validator -signatures on the latest block, and verify a Merkle proof of the state. - -In Tendermint, validators agree on a block before processing it. This -means that the signatures and state root for that block aren't included -until the next block. Thus, each block contains a field called -``LastCommit``, which contains the votes responsible for committing the -previous block, and a field in the block header called ``AppHash``, -which refers to the Merkle root hash of the application after processing -the transactions from the previous block. So, if we want to verify the -``AppHash`` from height H, we need the signatures from ``LastCommit`` at -height H+1. (And remember that this ``AppHash`` only contains the -results from all transactions up to and including block H-1) - -Unlike Proof-of-Work, the light-client protocol does not need to -download and check all the headers in the blockchain - the client can -always jump straight to the latest header available, so long as the -validator set has not changed much. If the validator set is changing, -the client needs to track these changes, which requires downloading -headers for each block in which there is a significant change. Here, we -will assume the validator set is constant, and postpone handling -validator set changes for another time. - -Now we can describe exactly how IBC works. Suppose we have two -blockchains, ``chain1`` and ``chain2``, and we want to send some data -from ``chain1`` to ``chain2``. We need to do the following: 1. Register -the details (ie. chain ID and genesis configuration) of ``chain1`` on -``chain2`` 2. Within ``chain1``, broadcast a transaction that creates an -outgoing IBC packet destined for ``chain2`` 3. Broadcast a transaction -to ``chain2`` informing it of the latest state (ie. header and commit -signatures) of ``chain1`` 4. Post the outgoing packet from ``chain1`` to -``chain2``, including the proof that it was indeed committed on -``chain1``. Note ``chain2`` can only verify this proof because it has a -recent header and commit. - -Each of these steps involves a separate IBC transaction type. Let's take -them up in turn. - -IBCRegisterChainTx -~~~~~~~~~~~~~~~~~~ - -The ``IBCRegisterChainTx`` is used to register one chain on another. It -contains the chain ID and genesis configuration of the chain to -register: - -.. code:: golang - - type IBCRegisterChainTx struct { BlockchainGenesis } - - type BlockchainGenesis struct { ChainID string Genesis string } - -This transaction should only be sent once for a given chain ID, and -successive sends will return an error. - -IBCUpdateChainTx -~~~~~~~~~~~~~~~~ - -The ``IBCUpdateChainTx`` is used to update the state of one chain on -another. It contains the header and commit signatures for some block in -the chain: - -.. code:: golang - - type IBCUpdateChainTx struct { - Header tm.Header - Commit tm.Commit - } - -In the future, it needs to be updated to include changes to the -validator set as well. Anyone can relay an ``IBCUpdateChainTx``, and -they only need to do so as frequently as packets are being sent or the -validator set is changing. - -IBCPacketCreateTx -~~~~~~~~~~~~~~~~~ - -The ``IBCPacketCreateTx`` is used to create an outgoing packet on one -chain. The packet itself contains the source and destination chain IDs, -a sequence number (i.e. an integer that increments with every message -sent between this pair of chains), a packet type (e.g. coin, data, -etc.), and a payload. - -.. code:: golang - - type IBCPacketCreateTx struct { - Packet - } - - type Packet struct { - SrcChainID string - DstChainID string - Sequence uint64 - Type string - Payload []byte - } - -We have yet to define the format for the payload, so, for now, it's just -arbitrary bytes. - -One way to think about this is that ``chain2`` has an account on -``chain1``. With a ``IBCPacketCreateTx`` on ``chain1``, we send funds to -that account. Then we can prove to ``chain2`` that there are funds -locked up for it in it's account on ``chain1``. Those funds can only be -unlocked with corresponding IBC messages back from ``chain2`` to -``chain1`` sending the locked funds to another account on ``chain1``. - -IBCPacketPostTx -~~~~~~~~~~~~~~~ - -The ``IBCPacketPostTx`` is used to post an outgoing packet from one -chain to another. It contains the packet and a proof that the packet was -committed into the state of the sending chain: - -.. code:: golang - - type IBCPacketPostTx struct { - FromChainID string // The immediate source of the packet, not always Packet.SrcChainID - FromChainHeight uint64 // The block height in which Packet was committed, to check Proof Packet - Proof *merkle.IAVLProof - } - -The proof is a Merkle proof in an IAVL tree, our implementation of a -balanced, Merklized binary search tree. It contains a list of nodes in -the tree, which can be hashed together to get the Merkle root hash. This -hash must match the ``AppHash`` contained in the header at -``FromChainHeight + 1`` - -- note the ``+ 1`` is necessary since ``FromChainHeight`` is the height - in which the packet was committed, and the resulting state root is - not included until the next block. - -IBC State -~~~~~~~~~ - -Now that we've seen all the transaction types, let's talk about the -state. Each chain stores some IBC state in its Merkle tree. For each -chain being tracked by our chain, we store: - -- Genesis configuration -- Latest state -- Headers for recent heights - -We also store all incoming (ingress) and outgoing (egress) packets. - -The state of a chain is updated every time an ``IBCUpdateChainTx`` is -committed. New packets are added to the egress state upon -``IBCPacketCreateTx``. New packets are added to the ingress state upon -``IBCPacketPostTx``, assuming the proof checks out. - -Merkle Queries --------------- - -The Basecoin application uses a single Merkle tree that is shared across -all its state, including the built-in accounts state and all plugin -state. For this reason, it's important to use explicit key names and/or -hashes to ensure there are no collisions. - -We can query the Merkle tree using the ABCI Query method. If we pass in -the correct key, it will return the corresponding value, as well as a -proof that the key and value are contained in the Merkle tree. - -The results of a query can thus be used as proof in an -``IBCPacketPostTx``. - -Relay ------ - -While we need all these packet types internally to keep track of all the -proofs on both chains in a secure manner, for the normal work-flow, we -can run a relay node that handles the cross-chain interaction. - -In this case, there are only two steps. First ``basecoin relay init``, -which must be run once to register each chain with the other one, and -make sure they are ready to send and recieve. And then -``basecoin relay start``, which is a long-running process polling the -queue on each side, and relaying all new message to the other block. - -This requires that the relay has access to accounts with some funds on -both chains to pay for all the ibc packets it will be forwarding. - -Try it out ----------- - -Now that we have all the background knowledge, let's actually walk -through the tutorial. - -Make sure you have installed `basecoin and -basecli `__. - -Basecoin is a framework for creating new cryptocurrency applications. It -comes with an ``IBC`` plugin enabled by default. - -You will also want to install the -`jq `__ for handling JSON at the command -line. - -If you have any trouble with this, you can also look at the `test -scripts `__ or just run ``make test_cli`` in basecoin -repo. Otherwise, open up 5 (yes 5!) terminal tabs.... - -Preliminaries -~~~~~~~~~~~~~ - -:: - - # first, clean up any old garbage for a fresh slate... - rm -rf ~/.ibcdemo/ - -Let's start by setting up some environment variables and aliases: - -:: - - export BCHOME1_CLIENT=~/.ibcdemo/chain1/client - export BCHOME1_SERVER=~/.ibcdemo/chain1/server - export BCHOME2_CLIENT=~/.ibcdemo/chain2/client - export BCHOME2_SERVER=~/.ibcdemo/chain2/server - alias basecli1="basecli --home $BCHOME1_CLIENT" - alias basecli2="basecli --home $BCHOME2_CLIENT" - alias basecoin1="basecoin --home $BCHOME1_SERVER" - alias basecoin2="basecoin --home $BCHOME2_SERVER" - -This will give us some new commands to use instead of raw ``basecli`` -and ``basecoin`` to ensure we're using the right configuration for the -chain we want to talk to. - -We also want to set some chain IDs: - -:: - - export CHAINID1="test-chain-1" - export CHAINID2="test-chain-2" - -And since we will run two different chains on one machine, we need to -maintain different sets of ports: - -:: - - export PORT_PREFIX1=1234 - export PORT_PREFIX2=2345 - export RPC_PORT1=${PORT_PREFIX1}7 - export RPC_PORT2=${PORT_PREFIX2}7 - -Setup Chain 1 -~~~~~~~~~~~~~ - -Now, let's create some keys that we can use for accounts on -test-chain-1: - -:: - - basecli1 keys new money - basecli1 keys new gotnone - export MONEY=$(basecli1 keys get money | awk '{print $2}') - export GOTNONE=$(basecli1 keys get gotnone | awk '{print $2}') - -and create an initial configuration giving lots of coins to the $MONEY -key: - -:: - - basecoin1 init --chain-id $CHAINID1 $MONEY - -Now start basecoin: - -:: - - sed -ie "s/4665/$PORT_PREFIX1/" $BCHOME1_SERVER/config.toml - - basecoin1 start &> basecoin1.log & - -Note the ``sed`` command to replace the ports in the config file. You -can follow the logs with ``tail -f basecoin1.log`` - -Now we can attach the client to the chain and verify the state. The -first account should have money, the second none: - -:: - - basecli1 init --node=tcp://localhost:${RPC_PORT1} --genesis=${BCHOME1_SERVER}/genesis.json - basecli1 query account $MONEY - basecli1 query account $GOTNONE - -Setup Chain 2 -~~~~~~~~~~~~~ - -This is the same as above, except with ``basecli2``, ``basecoin2``, and -``$CHAINID2``. We will also need to change the ports, since we're -running another chain on the same local machine. - -Let's create new keys for test-chain-2: - -:: - - basecli2 keys new moremoney - basecli2 keys new broke - MOREMONEY=$(basecli2 keys get moremoney | awk '{print $2}') - BROKE=$(basecli2 keys get broke | awk '{print $2}') - -And prepare the genesis block, and start the server: - -:: - - basecoin2 init --chain-id $CHAINID2 $(basecli2 keys get moremoney | awk '{print $2}') - - sed -ie "s/4665/$PORT_PREFIX2/" $BCHOME2_SERVER/config.toml - - basecoin2 start &> basecoin2.log & - -Now attach the client to the chain and verify the state. The first -account should have money, the second none: - -:: - - basecli2 init --node=tcp://localhost:${RPC_PORT2} --genesis=${BCHOME2_SERVER}/genesis.json - basecli2 query account $MOREMONEY - basecli2 query account $BROKE - -Connect these chains -~~~~~~~~~~~~~~~~~~~~ - -OK! So we have two chains running on your local machine, with different -keys on each. Let's hook them up together by starting a relay process to -forward messages from one chain to the other. - -The relay account needs some money in it to pay for the ibc messages, so -for now, we have to transfer some cash from the rich accounts before we -start the actual relay. - -:: - - # note that this key.json file is a hardcoded demo for all chains, this will - # be updated in a future release - RELAY_KEY=$BCHOME1_SERVER/key.json - RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") - - basecli1 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR--name=money - basecli1 query account $RELAY_ADDR - - basecli2 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=moremoney - basecli2 query account $RELAY_ADDR - -Now we can start the relay process. - -:: - - basecoin relay init --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 \ - --chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} \ - --genesis1=${BCHOME1_SERVER}/genesis.json --genesis2=${BCHOME2_SERVER}/genesis.json \ - --from=$RELAY_KEY - - basecoin relay start --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 \ - --chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} \ - --from=$RELAY_KEY &> relay.log & - -This should start up the relay, and assuming no error messages came out, -the two chains are now fully connected over IBC. Let's use this to send -our first tx accross the chains... - -Sending cross-chain payments -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The hard part is over, we set up two blockchains, a few private keys, -and a secure relay between them. Now we can enjoy the fruits of our -labor... - -:: - - # Here's an empty account on test-chain-2 - basecli2 query account $BROKE - -:: - - # Let's send some funds from test-chain-1 - basecli1 tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$BROKE --name=money - -:: - - # give it time to arrive... - sleep 2 - # now you should see 12345 coins! - basecli2 query account $BROKE - -You're no longer broke! Cool, huh? Now have fun exploring and sending -coins across the chains. And making more accounts as you want to. - -Conclusion ----------- - -In this tutorial we explained how IBC works, and demonstrated how to use -it to communicate between two chains. We did the simplest communciation -possible: a one way transfer of data from chain1 to chain2. The most -important part was that we updated chain2 with the latest state (i.e. -header and commit) of chain1, and then were able to post a proof to -chain2 that a packet was committed to the outgoing state of chain1. - -In a future tutorial, we will demonstrate how to use IBC to actually -transfer tokens between two blockchains, but we'll do it with real -testnets deployed across multiple nodes on the network. Stay tuned! diff --git a/_attic/modules/docs/index.rst b/_attic/modules/docs/index.rst deleted file mode 100644 index 77f41c985f..0000000000 --- a/_attic/modules/docs/index.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. Cosmos-SDK documentation master file, created by - sphinx-quickstart on Fri Sep 1 21:37:02 2017. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to the Cosmos SDK! -====================================== - -.. image:: graphics/cosmos-sdk-image.png - :height: 250px - :width: 500px - :align: center - -.. toctree:: - :maxdepth: 2 - - overview.rst - install.rst - basecoin-basics.rst - basecoin-tool.rst - key-management.rst - roles-and-multi-sig.rst - basecoin-plugins.rst - basecoin-kubernetes.rst - ibc.rst - glossary.rst - stdlib.rst diff --git a/_attic/modules/docs/install.rst b/_attic/modules/docs/install.rst deleted file mode 100644 index 5c606c0f44..0000000000 --- a/_attic/modules/docs/install.rst +++ /dev/null @@ -1,35 +0,0 @@ -Install -======= - -If you aren't used to compile go programs and just want the released -version of the code, please head to our -`downloads `__ page to get a -pre-compiled binary for your platform. - -Usually, Cosmos SDK can be installed like a normal Go program: - -:: - - go get -u github.com/cosmos/cosmos-sdk/cmd/... - -If the dependencies have been updated with breaking changes, or if -another branch is required, ``glide`` is used for dependency management. -Thus, assuming you've already run ``go get`` or otherwise cloned the -repo, the correct way to install is: - -:: - - cd $GOPATH/src/github.com/tendermint/basecoin - git pull origin master - make all - -This will create the ``basecoin`` binary in ``$GOPATH/bin``. -``make all`` implies ``make get_vendor_deps`` and uses ``glide`` to -install the correct version of all dependencies. It also tests the code, -including some cli tests to make sure your binary behaves properly. - -If you need another branch, make sure to run ``git checkout `` -before ``make all``. And if you switch branches a lot, especially -touching other tendermint repos, you may need to ``make fresh`` -sometimes so glide doesn't get confused with all the branches and -versions lying around. diff --git a/_attic/modules/docs/key-management.rst b/_attic/modules/docs/key-management.rst deleted file mode 100644 index fdda0cd7b1..0000000000 --- a/_attic/modules/docs/key-management.rst +++ /dev/null @@ -1,204 +0,0 @@ -Key Management -============== - -Here we explain a bit how to work with your keys, using the -``basecli keys`` subcommand. - -**Note:** This keys tooling is not considered production ready and is -for dev only. - -We'll look at what you can do using the six sub-commands of -``basecli keys``: - -:: - - new - list - get - delete - recover - update - -Create keys ------------ - -``basecli keys new`` has two inputs (name, password) and two outputs -(address, seed). - -First, we name our key: - -.. code:: shelldown - - basecli keys new alice - -This will prompt (10 character minimum) password entry which must be -re-typed. You'll see: - -:: - - Enter a passphrase: - Repeat the passphrase: - alice A159C96AE911F68913E715ED889D211C02EC7D70 - **Important** write this seed phrase in a safe place. - It is the only way to recover your account if you ever forget your password. - - pelican amateur empower assist awkward claim brave process cliff save album pigeon intact asset - -which shows the address of your key named ``alice``, and its recovery -seed. We'll use these shortly. - -Adding the ``--output json`` flag to the above command would give this -output: - -:: - - Enter a passphrase: - Repeat the passphrase: - { - "key": { - "name": "alice", - "address": "A159C96AE911F68913E715ED889D211C02EC7D70", - "pubkey": { - "type": "ed25519", - "data": "4BF22554B0F0BF2181187E5E5456E3BF3D96DB4C416A91F07F03A9C36F712B77" - } - }, - "seed": "pelican amateur empower assist awkward claim brave process cliff save album pigeon intact asset" - } - -To avoid the prompt, it's possible to pipe the password into the -command, e.g.: - -:: - - echo 1234567890 | basecli keys new fred --output json - -After trying each of the three ways to create a key, look at them, use: - -:: - - basecli keys list - -to list all the keys: - -:: - - All keys: - alice 6FEA9C99E2565B44FCC3C539A293A1378CDA7609 - bob A159C96AE911F68913E715ED889D211C02EC7D70 - charlie 784D623E0C15DE79043C126FA6449B68311339E5 - -Again, we can use the ``--output json`` flag: - -:: - - [ - { - "name": "alice", - "address": "6FEA9C99E2565B44FCC3C539A293A1378CDA7609", - "pubkey": { - "type": "ed25519", - "data": "878B297F1E863CC30CAD71E04A8B3C23DB71C18F449F39E35B954EDB2276D32D" - } - }, - { - "name": "bob", - "address": "A159C96AE911F68913E715ED889D211C02EC7D70", - "pubkey": { - "type": "ed25519", - "data": "2127CAAB96C08E3042C5B33C8B5A820079AAE8DD50642DCFCC1E8B74821B2BB9" - } - }, - { - "name": "charlie", - "address": "784D623E0C15DE79043C126FA6449B68311339E5", - "pubkey": { - "type": "ed25519", - "data": "4BF22554B0F0BF2181187E5E5456E3BF3D96DB4C416A91F07F03A9C36F712B77" - } - }, - ] - -to get machine readable output. - -If we want information about one specific key, then: - -:: - - basecli keys get charlie --output json - -will, for example, return the info for only the "charlie" key returned -from the previous ``basecoin keys list`` command. - -The keys tooling can support different types of keys with a flag: - -:: - - basecli keys new bit --type secp256k1 - -and you'll see the difference in the ``"type": field from``\ basecli -keys get\` - -Before moving on, let's set an enviroment variable to make -``--output json`` the default. - -Either run or put in your ``~/.bash_profile`` the following line: - -:: - - export BC_OUTPUT=json - -Recover a key -------------- - -Let's say, for whatever reason, you lose a key or forget the password. -On creation, you were given a seed. We'll use it to recover a lost key. - -First, let's simulate the loss by deleting a key: - -:: - - basecli keys delete alice - -which prompts for your current password, now rendered obsolete, and -gives a warning message. The only way you can recover your key now is -using the 12 word seed given on initial creation of the key. Let's try -it: - -:: - - basecli keys recover alice-again - -which prompts for a new password then the seed: - -:: - - Enter the new passphrase: - Enter your recovery seed phrase: - strike alien praise vendor term left market practice junior better deputy divert front calm - alice-again CBF5D9CE6DDCC32806162979495D07B851C53451 - -and voila! You've recovered your key. Note that the seed can be typed -our, pasted in, or piped into the command alongside the password. - -To change the password of a key, we can: - -:: - - basecli keys update alice-again - -and follow the prompts. - -That covers most features of the keys sub command. - -.. raw:: html - - diff --git a/_attic/modules/docs/make.bat b/_attic/modules/docs/make.bat deleted file mode 100644 index 916e57ee79..0000000000 --- a/_attic/modules/docs/make.bat +++ /dev/null @@ -1,36 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=python -msphinx -) -set SOURCEDIR=. -set BUILDDIR=_build -set SPHINXPROJ=Cosmos-SDK - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The Sphinx module was not found. Make sure you have Sphinx installed, - echo.then set the SPHINXBUILD environment variable to point to the full - echo.path of the 'sphinx-build' executable. Alternatively you may add the - echo.Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/_attic/modules/docs/overview.rst b/_attic/modules/docs/overview.rst deleted file mode 100644 index 22d26c5f80..0000000000 --- a/_attic/modules/docs/overview.rst +++ /dev/null @@ -1,88 +0,0 @@ -SDK Overview -============== - -The SDK middleware design optimizes flexibility and security. The -framework is designed around a modular execution stack which allows -applications to mix and match modular elements as desired. Along side, -all modules are permissioned and sandboxed to isolate modules for -greater application security. - -Framework Overview ------------------- - -Transactions -~~~~~~~~~~~~ - -Each transaction passes through the middleware stack which can be -defined uniquely by each application. From the multiple layers of -transaction, each middleware may strip off one level, like an onion. As -such, the transaction must be constructed to mirror the execution stack, -and each middleware module should allow an arbitrary transaction to be -embedded for the next layer in the stack. - -Execution Stack -~~~~~~~~~~~~~~~ - -Middleware components allow for code reusability and integrability. A -standard set of middleware are provided and can be mix-and-matched with -custom middleware. Some of the `standard library <./stdlib.html>`__ -middlewares provided in this package include: - Logging - Recovery - -Signatures - Chain - Nonce - Fees - Roles - -Inter-Blockchain-Communication (IBC) - -As a part of stack execution the state space provided to each middleware -is isolated ``Data Store`` below. When -executing the stack, state-recovery checkpoints can be assigned for -stack execution of ``CheckTx`` or ``DeliverTx``. This means, that all -state changes will be reverted to the checkpoint state on failure when -either being run as a part of ``CheckTx`` or ``DeliverTx``. Example -usage of the checkpoints is when we may want to deduct a fee even if the -end business logic fails; under this situation we would add the -``DeliverTx`` checkpoint after the fee middleware but before the -business logic. This diagram displays a typical process flow through an -execution stack. - -Dispatcher -~~~~~~~~~~ - -The dispatcher handler aims to allow for reusable business logic. As a -transaction is passed to the end handler, the dispatcher routes the -logic to the correct module. To use the dispatcher tool, all transaction -types must first be registered with the dispatcher. Once registered the -middleware stack or any other handler can call the dispatcher to execute -a transaction. Similarly to the execution stack, when executing a -transaction the dispatcher isolates the state space available to the -designated module (see ``Data Store`` below). - -Security Overview ------------------ - -Permission -~~~~~~~~~~ - -Each application is run in a sandbox to isolate security risks. When -interfacing between applications, if one of those applications is -compromised the entire network should still be secure. This is achieved -through actor permissioning whereby each chain, account, or application -can provided a designated permission for the transaction context to -perform a specific action. - -Context is passed through the middleware and dispatcher, allowing one to -add permissions on this app-space, and check current permissions. - -Data Store -~~~~~~~~~~ - -The entire merkle tree can access all data. When we call a module (or -middleware), we give them access to a subtree corresponding to their -app. This is achieved through the use of unique prefix assigned to each -module. From the module's perspective it is no different, the module -need-not have regard for the prefix as it is assigned outside of the -modules scope. For example, if a module named ``foo`` wanted to write to -the store it could save records under the key ``bar``, however, the -dispatcher would register that record in the persistent state under -``foo/bar``. Next time the ``foo`` app was called that record would be -accessible to it under the assigned key ``bar``. This effectively makes -app prefixing invisible to each module while preventing each module from -affecting each other module. Under this model no two registered modules -are permitted to have the same namespace. diff --git a/_attic/modules/docs/roles-and-multi-sig.rst b/_attic/modules/docs/roles-and-multi-sig.rst deleted file mode 100644 index 1681d76531..0000000000 --- a/_attic/modules/docs/roles-and-multi-sig.rst +++ /dev/null @@ -1,322 +0,0 @@ -This guide uses the roles functionality provided by ``basecli`` to -create a multi-sig wallet. It builds upon the basecoin basics and key -management guides. You should have ``basecoin`` started with blocks -streaming in, and three accounts: ``rich, poor, igor`` where ``rich`` -was the account used on ``basecoin init``, *and* run ``basecli init`` -with the appropriate flags. Review the intro guides for more -information. - -In this example, ``rich`` will create the role and send it some coins -(i.e., fill the multi-sig wallet). Then, ``poor`` will prepare a -transaction to withdraw coins, which will be approved by ``igor``. Let's -look at our keys: - -:: - - basecli keys list - -:: - - All keys: - igor 5E4CB7A4E729BA0A8B18DE99E21409B6D706D0F1 - poor 65D406E028319289A0706E294F3B764F44EBA3CF - rich CB76F4092D1B13475272B36585EBD15D22A2848D - -Using the ``basecli query account`` command, you'll see that ``rich`` -has plenty of coins: - -:: - - { - "height": 81, - "data": { - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ], - "credit": [] - } - } - -whereas ``poor`` and ``igor`` have no coins (in fact, the chain doesn't -know about them yet): - -:: - - ERROR: Account bytes are empty for address 65D406E028319289A0706E294F3B764F44EBA3CF - -Create Role ------------ - -This first step defines the parameters of a new role, which will have -control of any coins sent to it, and only release them if correct -conditions are met. In this example, we are going to make a 2/3 -multi-sig wallet. Let's look a the command and dissect it below: - -:: - - basecli tx create-role --role=10CAFE4E --min-sigs=2 --members=5E4CB7A4E729BA0A8B18DE99E21409B6D706D0F1,65D406E028319289A0706E294F3B764F44EBA3CF,CB76F4092D1B13475272B36585EBD15D22A2848D --sequence=1 --name=rich - -In the first part we are sending a transaction that creates a role, -rather than transfering coins. The ``--role`` flag is the name of the -role (in hex only) and must be in double quotes. The ``--min-sigs`` and -``--members`` define your multi-sig parameters. Here, we require a -minimum of 2 signatures out of 3 members but we could easily say 3 of 5 -or 9 of 10, or whatever your application requires. The ``--members`` -flag requires a comma-seperated list of addresses that will be -signatories on the role. Then we set the ``--sequence`` number for the -transaction, which will start at 1 and must be incremented by 1 for -every transaction from an account. Finally, we use the name of the -key/account that will be used to create the role, in this case the -account ``rich``. - -Remember that ``rich``'s address was used on ``basecoin init`` and is -included in the ``--members`` list. The command above will prompt for a -password (which can also be piped into the command if desired) then - if -executed correctly - return some data: - -:: - - { - "check_tx": { - "code": 0, - "data": "", - "log": "" - }, - "deliver_tx": { - "code": 0, - "data": "", - "log": "" - }, - "hash": "4849DA762E19CE599460B9882DD42C7F19655DC1", - "height": 321 - } - -showing the block height at which the transaction was committed and its -hash. A quick review of what we did: 1) created a role, essentially an -account, that requires a minimum of two (2) signatures from three (3) -accounts (members). And since it was the account named ``rich``'s first -transaction, the sequence was set to 1. - -Let's look at the balance of the role that we've created: - -:: - - basecli query account role:10CAFE4E - -and it should be empty: - -:: - - ERROR: Account bytes are empty for address role:10CAFE4E - -Next, we want to send coins *to* that role. Notice that because this is -the second transaction being sent by rich, we need to increase -``--sequence`` to ``2``: - -:: - - basecli tx send --fee=90mycoin --amount=10000mycoin --to=role:10CAFE4E --sequence=2 --name=rich - -We need to pay a transaction fee to the validators, in this case 90 -``mycoin`` to send 10000 ``mycoin`` Notice that for the ``--to`` flag, -to specify that we are sending to a role instead of an account, the -``role:`` prefix is added before the role. Because it's ``rich``'s -second transaction, we've incremented the sequence. The output will be -nearly identical to the output from ``create-role`` above. - -Now the role has coins (think of it like a bank). - -Double check with: - -:: - - basecli query account role:10CAFE4E - -and this time you'll see the coins in the role's account: - -:: - - { - "height": 2453, - "data": { - "coins": [ - { - "denom": "mycoin", - "amount": 10000 - } - ], - "credit": [] - } - } - -``Poor`` decides to initiate a multi-sig transaction to himself from the -role's account. First, it must be prepared like so: - -:: - - basecli tx send --amount=6000mycoin --from=role:10CAFE4E --to=65D406E028319289A0706E294F3B764F44EBA3CF --sequence=1 --assume-role=10CAFE4E --name=poor --multi --prepare=tx.json - -you'll be prompted for ``poor``'s password and there won't be any -``stdout`` to the terminal. Note that the address in the ``--to`` flag -matches the address of ``poor``'s account from the beginning of the -tutorial. The main output is the ``tx.json`` file that has just been -created. In the above command, the ``--assume-role`` flag is used to -evaluate account permissions on the transaction, while the ``--multi`` -flag is used in combination with ``--prepare``, to specify the file that -is prepared for a multi-sig transaction. - -The ``tx.json`` file will look like this: - -:: - - { - "type": "sigs/multi", - "data": { - "tx": { - "type": "chain/tx", - "data": { - "chain_id": "test_chain_id", - "expires_at": 0, - "tx": { - "type": "nonce", - "data": { - "sequence": 1, - "signers": [ - { - "chain": "", - "app": "sigs", - "addr": "65D406E028319289A0706E294F3B764F44EBA3CF" - } - ], - "tx": { - "type": "role/assume", - "data": { - "role": "10CAFE4E", - "tx": { - "type": "coin/send", - "data": { - "inputs": [ - { - "address": { - "chain": "", - "app": "role", - "addr": "10CAFE4E" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 6000 - } - ] - } - ], - "outputs": [ - { - "address": { - "chain": "", - "app": "sigs", - "addr": "65D406E028319289A0706E294F3B764F44EBA3CF" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 6000 - } - ] - } - ] - } - } - } - } - } - } - } - }, - "signatures": [ - { - "Sig": { - "type": "ed25519", - "data": "A38F73BF2D109015E4B0B6782C84875292D5FAA75F0E3362C9BD29B16CB15D57FDF0553205E7A33C740319397A434B7C31CBB10BE7F8270C9984C5567D2DC002" - }, - "Pubkey": { - "type": "ed25519", - "data": "6ED38C7453148DD90DFC41D9339CE45BEFA5EB505FD7E93D85E71DFFDAFD9B8F" - } - } - ] - } - } - -and it is loaded by the next command. - -With the transaction prepared, but not sent, we'll have ``igor`` sign -and send the prepared transaction: - -:: - - basecli tx --in=tx.json --name=igor - -which will give output similar to: - -:: - - { - "check_tx": { - "code": 0, - "data": "", - "log": "" - }, - "deliver_tx": { - "code": 0, - "data": "", - "log": "" - }, - "hash": "E345BDDED9517EB2CAAF5E30AFF3AB38A1172833", - "height": 2673 - } - -and voila! That's the basics for creating roles and sending multi-sig -transactions. For 3 of 3, you'd add an intermediate transactions like: - -:: - - basecli tx --in=tx.json --name=igor --prepare=tx2.json - -before having rich sign and send the transaction. The ``--prepare`` flag -writes files to disk rather than sending the transaction and can be used -to chain together multiple transactions. - -We can check the balance of the role: - -:: - - basecli query account role:10CAFE4E - -and get the result: - -:: - - { - "height": 2683, - "data": { - "coins": [ - { - "denom": "mycoin", - "amount": 4000 - } - ], - "credit": [] - } - } - -and see that ``poor`` now has 6000 ``mycoin``: - -:: - - basecli query account 65D406E028319289A0706E294F3B764F44EBA3CF - -to confirm that everything worked as expected. diff --git a/_attic/modules/docs/stdlib.rst b/_attic/modules/docs/stdlib.rst deleted file mode 100644 index f6373cf703..0000000000 --- a/_attic/modules/docs/stdlib.rst +++ /dev/null @@ -1,150 +0,0 @@ -Standard Library -================ - -The Cosmos-SDK comes bundled with a number of standard modules that -provide common functionality useful across a wide variety of -applications. See examples below. It is recommended to investigate if -desired functionality is already provided before developing new modules. - -Basic Middleware ----------------- - -Logging -~~~~~~~ - -``modules.base.Logger`` is a middleware that records basic info on -``CheckTx``, ``DeliverTx``, and ``SetOption``, along with timing in -microseconds. It can be installed standard at the top of all middleware -stacks, or replaced with your own middleware if you want to record -custom information with each request. - -Recovery -~~~~~~~~ - -To avoid accidental panics (e.g. bad go-wire decoding) killing the ABCI -app, wrap the stack with ``stack.Recovery``, which catches all panics -and returns them as errors, so they can be handled normally. - -Signatures -~~~~~~~~~~ - -The first layer of the transaction contains the signatures to authorize -it. This is then verified by ``modules.auth.Signatures``. All -transactions may have one or multiple signatures which are then -processed and verified by this middleware and then passed down the -stack. - -Chain -~~~~~ - -The next layer of a transaction (in the standard stack) binds the -transaction to a specific chain with a block height that has an optional -expiration. This keeps the transactions from being replayed on a fork or -other such chain, as well as a partially signed multi-sig being delayed -months before being committed to the chain. This functionality is -provided in ``modules.base.Chain`` - -Nonce -~~~~~ - -To avoid replay attacks, a nonce can be associated with each actor. A -separate nonce is used for each distinct group signers required for a -transaction as well as for each separate application and chain-id. This -creates replay protection cross-IBC and cross-plugins and also allows -signing parties to not be bound to waiting for a particular transaction -to be completed before being able to sign a separate transaction. - -Rather than force each module to implement its own replay protection, a -transaction stack may contain a nonce wrap and the account it belongs -to. The nonce must contain a signed sequence number which is incremented -one higher than the last request or the request is rejected. This is -implemented in ``modules.nonce.ReplayCheck``. - -If you're interested checkout this `design -discussion `__. - -Fees -~~~~ - -An optional - but useful - feature on many chains, is charging -transaction fees. A simple implementation of this is provided in -``modules.fee.SimpleFeeMiddleware``. A fee currency and minimum amount -are defined in the constructor (eg. in code). If the minimum amount is -0, then the fee is optional. If it is above 0, then every transaction -with insufficient fee is rejected. This fee is deducted from the payers -account before executing any other transaction. - -This module is dependent on the ``coin`` module. - -Other Apps ----------- - -Coin -~~~~ - -What would a crypto-currency be without tokens? The ``SendTx`` logic -from earlier implementations of basecoin was extracted into one module, -which is now optional, meaning most of the other functionality will also -work in a system with no built-in tokens, such as a private network that -provides other access control mechanisms. - -``modules.coin.Handler`` defines a Handler that maintains a number of -accounts along with a set of various tokens, supporting multiple token -denominations. The main access is ``SendTx``, which can support any type -of actor (other apps as well as public key addresses) and is a building -block for any other app that requires some payment solution, like fees -or trader. - -Roles -~~~~~ - -Roles encapsulate what are typically called N-of-M multi-signatures -accounts in the crypto world. However, I view this as a type of role or -group, which can be the basis for building a permission system. For -example, a set of people could be called registrars, which can authorize -a new IBC chain, and need eg. 2 out of 7 signatures to approve it. - -Currently, one can create a role with ``modules.roles.Handler``, and -assume one of those roles by wrapping another transaction with -``AssumeRoleTx``, which is processed by ``modules.roles.Middleware``. -Updating the set of actors in a role is planned in the near future. - -Inter-Blockchain Communication (IBC) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -IBC, is the cornerstone of The Cosmos Network, and is built into the -Cosmos-SDK framework as a basic primitive. To fully grasp these concepts -requires a much longer explanation, but in short, the chain works as a -light-client to another chain and maintains input and output queue to -send packets with that chain. This mechanism allows blockchains to prove -the state of their respective blockchains to each other ultimately -invoke inter-blockchain transactions. - -Most functionality is implemented in ``modules.ibc.Handler``. -Registering a chain is a seed of trust that requires verification of the -proper seed (or genesis block), and this generally requires approval of -an authorized registrar (which may be a multi-sig role). Updating a -registered chain can be done by anyone, as the new header can be -completely verified by the existing knowledge of the chain. Also, -modules can initiate an outgoing IBC message to another chain by calling -``CreatePacketTx`` over IPC (inter-plugin communication) with a -transaction that belongs to their module. (This must be explicitly -authorized by the same module, so only the eg. coin module can authorize -a ``SendTx`` to another chain). - -``PostPacketTx`` can post a transaction that was created on another -chain along with the merkle proof, which must match an already -registered header. If this chain can verify the authenticity, it will -accept the packet, along with all the permissions from the other chain, -and execute it on this stack. This is the only way to get permissions -that belong to another chain. - -These various pieces can be combined in a relay, which polls for new -packets on one chain, and then posts the packets along with the new -headers on the other chain. - -Example Apps ------------- - -See the `Cosmos Academy `__ -for example applications. diff --git a/_attic/modules/ibc/commands/query.go b/_attic/modules/ibc/commands/query.go deleted file mode 100644 index fb1da65067..0000000000 --- a/_attic/modules/ibc/commands/query.go +++ /dev/null @@ -1,230 +0,0 @@ -package commands - -import ( - "fmt" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/query" - "github.com/cosmos/cosmos-sdk/modules/ibc" - "github.com/cosmos/cosmos-sdk/stack" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/go-wire/data" - "github.com/tendermint/iavl" -) - -// TODO: query seeds (register/update) - -// IBCQueryCmd - parent command to query ibc info -var IBCQueryCmd = &cobra.Command{ - Use: "ibc", - Short: "Get information about IBC", - RunE: commands.RequireInit(ibcQueryCmd), - // HandlerInfo -} - -// ChainsQueryCmd - get a list of all registered chains -var ChainsQueryCmd = &cobra.Command{ - Use: "chains", - Short: "Get a list of all registered chains", - RunE: commands.RequireInit(chainsQueryCmd), - // ChainSet ([]string) -} - -// ChainQueryCmd - get details on one registered chain -var ChainQueryCmd = &cobra.Command{ - Use: "chain [id]", - Short: "Get details on one registered chain", - RunE: commands.RequireInit(chainQueryCmd), - // ChainInfo -} - -// PacketsQueryCmd - get latest packet in a queue -var PacketsQueryCmd = &cobra.Command{ - Use: "packets", - Short: "Get latest packet in a queue", - RunE: commands.RequireInit(packetsQueryCmd), - // uint64 -} - -// PacketQueryCmd - get the names packet (by queue and sequence) -var PacketQueryCmd = &cobra.Command{ - Use: "packet", - Short: "Get packet with given sequence from the named queue", - RunE: commands.RequireInit(packetQueryCmd), - // Packet -} - -//nolint -const ( - FlagFromChain = "from" - FlagToChain = "to" - FlagSequence = "sequence" -) - -func init() { - IBCQueryCmd.AddCommand( - ChainQueryCmd, - ChainsQueryCmd, - PacketQueryCmd, - PacketsQueryCmd, - ) - - fs1 := PacketsQueryCmd.Flags() - fs1.String(FlagFromChain, "", "Name of the input chain (where packets came from)") - fs1.String(FlagToChain, "", "Name of the output chain (where packets go to)") - - fs2 := PacketQueryCmd.Flags() - fs2.String(FlagFromChain, "", "Name of the input chain (where packets came from)") - fs2.String(FlagToChain, "", "Name of the output chain (where packets go to)") - fs2.Int(FlagSequence, -1, "Index of the packet in the queue (starts with 0)") -} - -func ibcQueryCmd(cmd *cobra.Command, args []string) error { - var res ibc.HandlerInfo - key := stack.PrefixedKey(ibc.NameIBC, ibc.HandlerKey()) - prove := !viper.GetBool(commands.FlagTrustNode) - h, err := query.GetParsed(key, &res, query.GetHeight(), prove) - if err != nil { - return err - } - return query.OutputProof(res, h) -} - -func chainsQueryCmd(cmd *cobra.Command, args []string) error { - list := [][]byte{} - key := stack.PrefixedKey(ibc.NameIBC, ibc.ChainsKey()) - prove := !viper.GetBool(commands.FlagTrustNode) - h, err := query.GetParsed(key, &list, query.GetHeight(), prove) - if err != nil { - return err - } - - // convert these names to strings for better output - res := make([]string, len(list)) - for i := range list { - res[i] = string(list[i]) - } - - return query.OutputProof(res, h) -} - -func chainQueryCmd(cmd *cobra.Command, args []string) error { - arg, err := commands.GetOneArg(args, "id") - if err != nil { - return err - } - - var res ibc.ChainInfo - key := stack.PrefixedKey(ibc.NameIBC, ibc.ChainKey(arg)) - prove := !viper.GetBool(commands.FlagTrustNode) - h, err := query.GetParsed(key, &res, query.GetHeight(), prove) - if err != nil { - return err - } - - return query.OutputProof(res, h) -} - -func assertOne(from, to string) error { - if from == "" && to == "" { - return errors.Errorf("You must specify either --%s or --%s", - FlagFromChain, FlagToChain) - } - if from != "" && to != "" { - return errors.Errorf("You can only specify one of --%s or --%s", - FlagFromChain, FlagToChain) - } - return nil -} - -func packetsQueryCmd(cmd *cobra.Command, args []string) error { - from := viper.GetString(FlagFromChain) - to := viper.GetString(FlagToChain) - err := assertOne(from, to) - if err != nil { - return err - } - - var key []byte - if from != "" { - key = stack.PrefixedKey(ibc.NameIBC, ibc.QueueInKey(from)) - } else { - key = stack.PrefixedKey(ibc.NameIBC, ibc.QueueOutKey(to)) - } - - var res uint64 - prove := !viper.GetBool(commands.FlagTrustNode) - h, err := query.GetParsed(key, &res, query.GetHeight(), prove) - if err != nil { - return err - } - - return query.OutputProof(res, h) -} - -func packetQueryCmd(cmd *cobra.Command, args []string) error { - from := viper.GetString(FlagFromChain) - to := viper.GetString(FlagToChain) - err := assertOne(from, to) - if err != nil { - return err - } - - seq := viper.GetInt(FlagSequence) - if seq < 0 { - return errors.Errorf("--%s must be a non-negative number", FlagSequence) - } - prove := !viper.GetBool(commands.FlagTrustNode) - - var key []byte - if from != "" { - key = stack.PrefixedKey(ibc.NameIBC, ibc.QueueInPacketKey(from, uint64(seq))) - } else { - key = stack.PrefixedKey(ibc.NameIBC, ibc.QueueOutPacketKey(to, uint64(seq))) - } - - // Input queue just display the results - var packet ibc.Packet - if from != "" { - h, err := query.GetParsed(key, &packet, query.GetHeight(), prove) - if err != nil { - return err - } - return query.OutputProof(packet, h) - } - - // output queue, create a post packet - bs, height, proof, err := query.GetWithProof(key, query.GetHeight()) - if err != nil { - return err - } - if len(bs) == 0 { - // TODO: what info here? - return errors.New("no such packet") - } - - err = wire.ReadBinaryBytes(bs, &packet) - if err != nil { - return err - } - // create the post packet here. - post := ibc.PostPacketTx{ - FromChainID: commands.GetChainID(), - FromChainHeight: height, - Key: key, - Packet: packet, - Proof: proof.(*iavl.KeyExistsProof), - } - - // print json direct, as we don't need to wrap with the height - res, err := data.ToJSON(post) - if err != nil { - return err - } - fmt.Println(string(res)) - return nil -} diff --git a/_attic/modules/ibc/commands/tx.go b/_attic/modules/ibc/commands/tx.go deleted file mode 100644 index 292658721c..0000000000 --- a/_attic/modules/ibc/commands/tx.go +++ /dev/null @@ -1,115 +0,0 @@ -package commands - -import ( - "encoding/json" - "os" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/commands" - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - "github.com/cosmos/cosmos-sdk/modules/ibc" - "github.com/tendermint/light-client/certifiers" -) - -// RegisterChainTxCmd is CLI command to register a new chain for ibc -var RegisterChainTxCmd = &cobra.Command{ - Use: "ibc-register", - Short: "Register a new chain", - RunE: commands.RequireInit(registerChainTxCmd), -} - -// UpdateChainTxCmd is CLI command to update the header for an ibc chain -var UpdateChainTxCmd = &cobra.Command{ - Use: "ibc-update", - Short: "Add new header to an existing chain", - RunE: commands.RequireInit(updateChainTxCmd), -} - -// PostPacketTxCmd is CLI command to post ibc packet on the destination chain -var PostPacketTxCmd = &cobra.Command{ - Use: "ibc-post", - Short: "Post an ibc packet on the destination chain", - RunE: commands.RequireInit(postPacketTxCmd), -} - -// TODO: relay! - -//nolint -const ( - FlagCommit = "commit" - FlagPacket = "packet" -) - -func init() { - fs1 := RegisterChainTxCmd.Flags() - fs1.String(FlagCommit, "", "Filename with a commit file") - - fs2 := UpdateChainTxCmd.Flags() - fs2.String(FlagCommit, "", "Filename with a commit file") - - fs3 := PostPacketTxCmd.Flags() - fs3.String(FlagPacket, "", "Filename with a packet to post") -} - -func registerChainTxCmd(cmd *cobra.Command, args []string) error { - fc, err := readCommit() - if err != nil { - return err - } - tx := ibc.RegisterChainTx{fc}.Wrap() - return txcmd.DoTx(tx) -} - -func updateChainTxCmd(cmd *cobra.Command, args []string) error { - fc, err := readCommit() - if err != nil { - return err - } - tx := ibc.UpdateChainTx{fc}.Wrap() - return txcmd.DoTx(tx) -} - -func postPacketTxCmd(cmd *cobra.Command, args []string) error { - post, err := readPostPacket() - if err != nil { - return err - } - return txcmd.DoTx(post.Wrap()) -} - -func readCommit() (fc certifiers.FullCommit, err error) { - name := viper.GetString(FlagCommit) - if name == "" { - return fc, errors.New("You must specify a commit file") - } - - err = readFile(name, &fc) - return -} - -func readPostPacket() (post ibc.PostPacketTx, err error) { - name := viper.GetString(FlagPacket) - if name == "" { - return post, errors.New("You must specify a packet file") - } - - err = readFile(name, &post) - return -} - -func readFile(name string, input interface{}) (err error) { - var f *os.File - f, err = os.Open(name) - if err != nil { - return errors.WithStack(err) - } - defer f.Close() - - // read the file as json into a seed - j := json.NewDecoder(f) - err = j.Decode(input) - return errors.Wrap(err, "Invalid file") -} diff --git a/_attic/modules/ibc/errors.go b/_attic/modules/ibc/errors.go deleted file mode 100644 index 8c3c99a611..0000000000 --- a/_attic/modules/ibc/errors.go +++ /dev/null @@ -1,109 +0,0 @@ -package ibc - -import ( - "fmt" - - abci "github.com/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/errors" -) - -// nolint -var ( - errChainNotRegistered = fmt.Errorf("Chain not registered") - errChainAlreadyExists = fmt.Errorf("Chain already exists") - errWrongDestChain = fmt.Errorf("This is not the destination") - errNeedsIBCPermission = fmt.Errorf("Needs app-permission to send IBC") - errCannotSetPermission = fmt.Errorf("Requesting invalid permission on IBC") - errHeaderNotFound = fmt.Errorf("Header not found") - errPacketAlreadyExists = fmt.Errorf("Packet already handled") - errPacketOutOfOrder = fmt.Errorf("Packet out of order") - errInvalidProof = fmt.Errorf("Invalid merkle proof") - msgInvalidCommit = "Invalid header and commit" - - IBCCodeChainNotRegistered = abci.CodeType(1001) - IBCCodeChainAlreadyExists = abci.CodeType(1002) - IBCCodeUnknownChain = abci.CodeType(1003) - IBCCodeInvalidPacketSequence = abci.CodeType(1004) - IBCCodeUnknownHeight = abci.CodeType(1005) - IBCCodeInvalidCommit = abci.CodeType(1006) - IBCCodeInvalidProof = abci.CodeType(1007) - IBCCodeInvalidCall = abci.CodeType(1008) -) - -func ErrNotRegistered(chainID string) error { - return errors.WithMessage(chainID, errChainNotRegistered, IBCCodeChainNotRegistered) -} -func IsNotRegisteredErr(err error) bool { - return errors.IsSameError(errChainNotRegistered, err) -} - -func ErrAlreadyRegistered(chainID string) error { - return errors.WithMessage(chainID, errChainAlreadyExists, IBCCodeChainAlreadyExists) -} -func IsAlreadyRegisteredErr(err error) bool { - return errors.IsSameError(errChainAlreadyExists, err) -} - -func ErrWrongDestChain(chainID string) error { - return errors.WithMessage(chainID, errWrongDestChain, IBCCodeUnknownChain) -} -func IsWrongDestChainErr(err error) bool { - return errors.IsSameError(errWrongDestChain, err) -} - -func ErrNeedsIBCPermission() error { - return errors.WithCode(errNeedsIBCPermission, IBCCodeInvalidCall) -} -func IsNeedsIBCPermissionErr(err error) bool { - return errors.IsSameError(errNeedsIBCPermission, err) -} - -func ErrCannotSetPermission() error { - return errors.WithCode(errCannotSetPermission, IBCCodeInvalidCall) -} -func IsCannotSetPermissionErr(err error) bool { - return errors.IsSameError(errCannotSetPermission, err) -} - -func ErrHeaderNotFound(h int) error { - msg := fmt.Sprintf("height %d", h) - return errors.WithMessage(msg, errHeaderNotFound, IBCCodeUnknownHeight) -} -func IsHeaderNotFoundErr(err error) bool { - return errors.IsSameError(errHeaderNotFound, err) -} - -func ErrPacketAlreadyExists() error { - return errors.WithCode(errPacketAlreadyExists, IBCCodeInvalidPacketSequence) -} -func IsPacketAlreadyExistsErr(err error) bool { - return errors.IsSameError(errPacketAlreadyExists, err) -} - -func ErrPacketOutOfOrder(seq uint64) error { - msg := fmt.Sprintf("expected %d", seq) - return errors.WithMessage(msg, errPacketOutOfOrder, IBCCodeInvalidPacketSequence) -} -func IsPacketOutOfOrderErr(err error) bool { - return errors.IsSameError(errPacketOutOfOrder, err) -} - -func ErrInvalidProof() error { - return errors.WithCode(errInvalidProof, IBCCodeInvalidProof) -} -func ErrInvalidProofWithReason(err error) error { - return errors.WithCode(err, IBCCodeInvalidProof) -} -func IsInvalidProofErr(err error) bool { - return errors.HasErrorCode(err, IBCCodeInvalidProof) -} - -func ErrInvalidCommit(err error) error { - if err == nil { - return nil - } - return errors.WithMessage(msgInvalidCommit, err, IBCCodeInvalidCommit) -} -func IsInvalidCommitErr(err error) bool { - return errors.HasErrorCode(err, IBCCodeInvalidCommit) -} diff --git a/_attic/modules/ibc/handler.go b/_attic/modules/ibc/handler.go deleted file mode 100644 index 47b8c56975..0000000000 --- a/_attic/modules/ibc/handler.go +++ /dev/null @@ -1,211 +0,0 @@ -package ibc - -import ( - "fmt" - - "github.com/tendermint/go-wire/data" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -const ( - // NameIBC is the name of this module - NameIBC = "ibc" - // OptionRegistrar is the option name to set the actor - // to handle ibc chain registration - OptionRegistrar = "registrar" -) - -var ( - // Semi-random bytes that shouldn't conflict with keys (20 bytes) - // or any strings (non-ascii). - // TODO: consider how to make this more collision-proof.... - allowIBC = []byte{0x42, 0xbe, 0xef, 0x1} -) - -// AllowIBC returns a specially crafted Actor that -// enables sending IBC packets for this app type -func AllowIBC(app string) sdk.Actor { - return sdk.Actor{App: app, Address: allowIBC} -} - -// Handler updates the chain state or creates an ibc packet -type Handler struct { - sdk.NopInitValidate -} - -var _ sdk.Handler = Handler{} - -// NewHandler returns a Handler that allows all chains to connect via IBC. -// Set a Registrar via InitState to restrict it. -func NewHandler() Handler { - return Handler{} -} - -// Name returns name space -func (Handler) Name() string { - return NameIBC -} - -// InitState sets the registrar for IBC -func (h Handler) InitState(l log.Logger, store state.SimpleDB, module, key, value string) (log string, err error) { - if module != NameIBC { - return "", errors.ErrUnknownModule(module) - } - if key == OptionRegistrar { - var act sdk.Actor - err = data.FromJSON([]byte(value), &act) - if err != nil { - return "", err - } - // Save the data - info := HandlerInfo{act} - info.Save(store) - return "Success", nil - } - return "", errors.ErrUnknownKey(key) -} - -// CheckTx verifies the packet is formated correctly, and has the proper sequence -// for a registered chain -func (h Handler) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - err = tx.ValidateBasic() - if err != nil { - return res, err - } - - // TODO: better fee calculation (don't do complex crypto) - switch tx.Unwrap().(type) { - case RegisterChainTx: - return res, nil - case UpdateChainTx: - return res, nil - case CreatePacketTx: - return res, nil - } - return res, errors.ErrUnknownTxType(tx.Unwrap()) -} - -// DeliverTx verifies all signatures on the tx and updates the chain state -// apropriately -func (h Handler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - err = tx.ValidateBasic() - if err != nil { - return res, err - } - - switch t := tx.Unwrap().(type) { - case RegisterChainTx: - return h.registerChain(ctx, store, t) - case UpdateChainTx: - return h.updateChain(ctx, store, t) - case CreatePacketTx: - return h.createPacket(ctx, store, t) - } - return res, errors.ErrUnknownTxType(tx.Unwrap()) -} - -// registerChain imports the first seed for this chain and -// accepts it as the root of trust. -// -// only the registrar, if set, is allowed to do this -func (h Handler) registerChain(ctx sdk.Context, store state.SimpleDB, - t RegisterChainTx) (res sdk.DeliverResult, err error) { - - info := LoadInfo(store) - if !info.Registrar.Empty() && !ctx.HasPermission(info.Registrar) { - return res, errors.ErrUnauthorized() - } - - // verify that the header looks reasonable - chainID := t.ChainID() - s := NewChainSet(store) - err = s.Register(chainID, ctx.BlockHeight(), t.Commit.Height()) - if err != nil { - return res, err - } - - space := stack.PrefixedStore(chainID, store) - provider := newDBProvider(space) - err = provider.StoreCommit(t.Commit) - return res, err -} - -// updateChain checks the seed against the existing chain data and rejects it if it -// doesn't fit (or no chain data) -func (h Handler) updateChain(ctx sdk.Context, store state.SimpleDB, - t UpdateChainTx) (res sdk.DeliverResult, err error) { - - chainID := t.ChainID() - s := NewChainSet(store) - if !s.Exists([]byte(chainID)) { - return res, ErrNotRegistered(chainID) - } - - // load the certifier for this chain - fc := t.Commit - space := stack.PrefixedStore(chainID, store) - cert, err := newCertifier(space, chainID, fc.Height()) - if err != nil { - return res, err - } - - // this will import the commit if it is valid in the current context - err = cert.Update(fc) - if err != nil { - return res, ErrInvalidCommit(err) - } - - // update the tracked height in chain info - err = s.Update(chainID, fc.Height()) - return res, err -} - -// createPacket makes sure all permissions are good and the destination -// chain is registed. If so, it appends it to the outgoing queue -func (h Handler) createPacket(ctx sdk.Context, store state.SimpleDB, - t CreatePacketTx) (res sdk.DeliverResult, err error) { - - // make sure the chain is registed - dest := t.DestChain - if !NewChainSet(store).Exists([]byte(dest)) { - return res, ErrNotRegistered(dest) - } - - // make sure we have the special IBC permission - mod, err := t.Tx.GetMod() - if err != nil { - return res, err - } - if !ctx.HasPermission(AllowIBC(mod)) { - return res, ErrNeedsIBCPermission() - } - - // start making the packet to send - packet := Packet{ - DestChain: dest, - Tx: t.Tx, - Permissions: make([]sdk.Actor, len(t.Permissions)), - } - - // make sure we have all the permissions we want to send - for i, p := range t.Permissions { - if !ctx.HasPermission(p) { - return res, ErrCannotSetPermission() - } - // add the permission with the current ChainID - packet.Permissions[i] = p.WithChain(ctx.ChainID()) - } - - // now add it to the output queue.... - q := OutputQueue(store, dest) - packet.Sequence = q.Tail() - q.Push(packet.Bytes()) - - res = sdk.DeliverResult{Log: fmt.Sprintf("Packet %s %d", dest, packet.Sequence)} - return -} diff --git a/_attic/modules/ibc/ibc_test.go b/_attic/modules/ibc/ibc_test.go deleted file mode 100644 index ceb92237fd..0000000000 --- a/_attic/modules/ibc/ibc_test.go +++ /dev/null @@ -1,413 +0,0 @@ -package ibc - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - wire "github.com/tendermint/go-wire" - "github.com/tendermint/light-client/certifiers" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -// this tests registration without registrar permissions -func TestIBCRegister(t *testing.T) { - assert := assert.New(t) - - // the validators we use to make seeds - keys := certifiers.GenValKeys(5) - keys2 := certifiers.GenValKeys(7) - appHash := []byte{0, 4, 7, 23} - appHash2 := []byte{12, 34, 56, 78} - - // badCommit doesn't validate - badCommit := genEmptyCommit(keys2, "chain-2", 123, appHash, len(keys2)) - badCommit.Header.AppHash = appHash2 - - cases := []struct { - fc certifiers.FullCommit - checker errors.CheckErr - }{ - { - genEmptyCommit(keys, "chain-1", 100, appHash, len(keys)), - errors.NoErr, - }, - { - genEmptyCommit(keys, "chain-1", 200, appHash, len(keys)), - IsAlreadyRegisteredErr, - }, - { - badCommit, - IsInvalidCommitErr, - }, - { - genEmptyCommit(keys2, "chain-2", 123, appHash2, 5), - errors.NoErr, - }, - } - - ctx := stack.MockContext("hub", 50) - store := state.NewMemKVStore() - app := stack.New().Dispatch(stack.WrapHandler(NewHandler())) - - for i, tc := range cases { - tx := RegisterChainTx{tc.fc}.Wrap() - _, err := app.DeliverTx(ctx, store, tx) - assert.True(tc.checker(err), "%d: %+v", i, err) - } -} - -// this tests permission controls on ibc registration -func TestIBCRegisterPermissions(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - // the validators we use to make seeds - keys := certifiers.GenValKeys(4) - appHash := []byte{0x17, 0x21, 0x5, 0x1e} - - foobar := sdk.Actor{App: "foo", Address: []byte("bar")} - baz := sdk.Actor{App: "baz", Address: []byte("bar")} - foobaz := sdk.Actor{App: "foo", Address: []byte("baz")} - - cases := []struct { - seed certifiers.FullCommit - registrar sdk.Actor - signer sdk.Actor - checker errors.CheckErr - }{ - // no sig, no registrar - { - seed: genEmptyCommit(keys, "chain-1", 100, appHash, len(keys)), - checker: errors.NoErr, - }, - // sig, no registrar - { - seed: genEmptyCommit(keys, "chain-2", 100, appHash, len(keys)), - signer: foobaz, - checker: errors.NoErr, - }, - // registrar, no sig - { - seed: genEmptyCommit(keys, "chain-3", 100, appHash, len(keys)), - registrar: foobar, - checker: errors.IsUnauthorizedErr, - }, - // registrar, wrong sig - { - seed: genEmptyCommit(keys, "chain-4", 100, appHash, len(keys)), - signer: foobaz, - registrar: foobar, - checker: errors.IsUnauthorizedErr, - }, - // registrar, wrong sig - { - seed: genEmptyCommit(keys, "chain-5", 100, appHash, len(keys)), - signer: baz, - registrar: foobar, - checker: errors.IsUnauthorizedErr, - }, - // registrar, proper sig - { - seed: genEmptyCommit(keys, "chain-6", 100, appHash, len(keys)), - signer: foobar, - registrar: foobar, - checker: errors.NoErr, - }, - } - - store := state.NewMemKVStore() - app := stack.New().Dispatch(stack.WrapHandler(NewHandler())) - - for i, tc := range cases { - // set option specifies the registrar - msg, err := json.Marshal(tc.registrar) - require.Nil(err, "%+v", err) - _, err = app.InitState(log.NewNopLogger(), store, - NameIBC, OptionRegistrar, string(msg)) - require.Nil(err, "%+v", err) - - // add permissions to the context - ctx := stack.MockContext("hub", 50).WithPermissions(tc.signer) - tx := RegisterChainTx{tc.seed}.Wrap() - _, err = app.DeliverTx(ctx, store, tx) - assert.True(tc.checker(err), "%d: %+v", i, err) - } -} - -// this verifies that we can properly update the headers on the chain -func TestIBCUpdate(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - // this is the root seed, that others are evaluated against - keys := certifiers.GenValKeys(7) - appHash := []byte{0, 4, 7, 23} - start := 100 // initial height - root := genEmptyCommit(keys, "chain-1", 100, appHash, len(keys)) - - keys2 := keys.Extend(2) - keys3 := keys2.Extend(2) - - // create the app and register the root of trust (for chain-1) - ctx := stack.MockContext("hub", 50) - store := state.NewMemKVStore() - app := stack.New().Dispatch(stack.WrapHandler(NewHandler())) - tx := RegisterChainTx{root}.Wrap() - _, err := app.DeliverTx(ctx, store, tx) - require.Nil(err, "%+v", err) - - cases := []struct { - fc certifiers.FullCommit - checker errors.CheckErr - }{ - // same validator, higher up - { - genEmptyCommit(keys, "chain-1", start+50, []byte{22}, len(keys)), - errors.NoErr, - }, - // same validator, between existing (not most recent) - { - genEmptyCommit(keys, "chain-1", start+5, []byte{15, 43}, len(keys)), - errors.NoErr, - }, - // same validators, before root of trust - { - genEmptyCommit(keys, "chain-1", start-8, []byte{11, 77}, len(keys)), - IsHeaderNotFoundErr, - }, - // insufficient signatures - { - genEmptyCommit(keys, "chain-1", start+60, []byte{24}, len(keys)/2), - IsInvalidCommitErr, - }, - // unregistered chain - { - genEmptyCommit(keys, "chain-2", start+60, []byte{24}, len(keys)/2), - IsNotRegisteredErr, - }, - // too much change (keys -> keys3) - { - genEmptyCommit(keys3, "chain-1", start+100, []byte{22}, len(keys3)), - IsInvalidCommitErr, - }, - // legit update to validator set (keys -> keys2) - { - genEmptyCommit(keys2, "chain-1", start+90, []byte{33}, len(keys2)), - errors.NoErr, - }, - // now impossible jump works (keys -> keys2 -> keys3) - { - genEmptyCommit(keys3, "chain-1", start+100, []byte{44}, len(keys3)), - errors.NoErr, - }, - } - - for i, tc := range cases { - tx := UpdateChainTx{tc.fc}.Wrap() - _, err := app.DeliverTx(ctx, store, tx) - assert.True(tc.checker(err), "%d: %+v", i, err) - } -} - -// try to create an ibc packet and verify the number we get back -func TestIBCCreatePacket(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - // this is the root seed, that others are evaluated against - keys := certifiers.GenValKeys(7) - appHash := []byte{1, 2, 3, 4} - start := 100 // initial height - chainID := "cosmos-hub" - root := genEmptyCommit(keys, chainID, start, appHash, len(keys)) - - // create the app and register the root of trust (for chain-1) - ctx := stack.MockContext("hub", 50) - store := state.NewMemKVStore() - app := stack.New().Dispatch(stack.WrapHandler(NewHandler())) - tx := RegisterChainTx{root}.Wrap() - _, err := app.DeliverTx(ctx, store, tx) - require.Nil(err, "%+v", err) - - // this is the tx we send, and the needed permission to send it - raw := stack.NewRawTx([]byte{0xbe, 0xef}) - ibcPerm := AllowIBC(stack.NameOK) - somePerm := sdk.Actor{App: "some", Address: []byte("perm")} - - cases := []struct { - dest string - ibcPerms sdk.Actors - ctxPerms sdk.Actors - checker errors.CheckErr - }{ - // wrong chain -> error - { - dest: "some-other-chain", - ctxPerms: sdk.Actors{ibcPerm}, - checker: IsNotRegisteredErr, - }, - - // no ibc permission -> error - { - dest: chainID, - checker: IsNeedsIBCPermissionErr, - }, - - // correct -> nice sequence - { - dest: chainID, - ctxPerms: sdk.Actors{ibcPerm}, - checker: errors.NoErr, - }, - - // requesting invalid permissions -> error - { - dest: chainID, - ibcPerms: sdk.Actors{somePerm}, - ctxPerms: sdk.Actors{ibcPerm}, - checker: IsCannotSetPermissionErr, - }, - - // requesting extra permissions when present - { - dest: chainID, - ibcPerms: sdk.Actors{somePerm}, - ctxPerms: sdk.Actors{ibcPerm, somePerm}, - checker: errors.NoErr, - }, - } - - for i, tc := range cases { - tx := CreatePacketTx{ - DestChain: tc.dest, - Permissions: tc.ibcPerms, - Tx: raw, - }.Wrap() - - myCtx := ctx.WithPermissions(tc.ctxPerms...) - _, err = app.DeliverTx(myCtx, store, tx) - assert.True(tc.checker(err), "%d: %+v", i, err) - } - - // query packet state - make sure both packets are properly writen - p := stack.PrefixedStore(NameIBC, store) - q := OutputQueue(p, chainID) - if assert.Equal(2, q.Size()) { - expected := []struct { - seq uint64 - perm sdk.Actors - }{ - {0, nil}, - {1, sdk.Actors{somePerm}}, - } - - for _, tc := range expected { - var packet Packet - err = wire.ReadBinaryBytes(q.Pop(), &packet) - require.Nil(err, "%+v", err) - assert.Equal(chainID, packet.DestChain) - assert.EqualValues(tc.seq, packet.Sequence) - assert.Equal(raw, packet.Tx) - assert.Equal(len(tc.perm), len(packet.Permissions)) - } - } -} - -func TestIBCPostPacket(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - otherID := "chain-1" - ourID := "hub" - start := 200 - msg := "it's okay" - - // create the app and our chain - app := stack.New(). - IBC(NewMiddleware()). - Dispatch( - stack.WrapHandler(NewHandler()), - stack.WrapHandler(stack.OKHandler{Log: msg}), - ) - ourChain := NewAppChain(app, ourID) - - // set up the other chain and register it with us - otherChain := NewMockChain(otherID, 7) - registerTx := otherChain.GetRegistrationTx(start).Wrap() - _, err := ourChain.DeliverTx(registerTx) - require.Nil(err, "%+v", err) - - // make a random tx that is to be passed - rawTx := stack.NewRawTx([]byte{17, 24, 3, 8}) - - randomChain := NewMockChain("something-else", 4) - pbad := NewPacket(rawTx, "something-else", 0) - packetBad, _ := randomChain.MakePostPacket(pbad, 123) - - p0 := NewPacket(rawTx, ourID, 0) - packet0, update0 := otherChain.MakePostPacket(p0, start+5) - require.Nil(ourChain.Update(update0)) - - packet0badHeight := packet0 - packet0badHeight.FromChainHeight -= 2 - - theirActor := sdk.Actor{ChainID: otherID, App: "foo", Address: []byte{1}} - p1 := NewPacket(rawTx, ourID, 1, theirActor) - packet1, update1 := otherChain.MakePostPacket(p1, start+25) - require.Nil(ourChain.Update(update1)) - - packet1badProof := packet1 - packet1badProof.Key = []byte("random-data") - - ourActor := sdk.Actor{ChainID: ourID, App: "bar", Address: []byte{2}} - p2 := NewPacket(rawTx, ourID, 2, ourActor) - packet2, update2 := otherChain.MakePostPacket(p2, start+50) - require.Nil(ourChain.Update(update2)) - - ibcPerm := sdk.Actors{AllowIBC(stack.NameOK)} - cases := []struct { - packet PostPacketTx - permissions sdk.Actors - checker errors.CheckErr - }{ - // bad chain -> error - {packetBad, ibcPerm, IsNotRegisteredErr}, - - // no matching header -> error - {packet0badHeight, nil, IsHeaderNotFoundErr}, - - // out of order -> error - {packet1, ibcPerm, IsPacketOutOfOrderErr}, - - // all good -> execute tx - {packet0, ibcPerm, errors.NoErr}, - - // bad proof -> error - {packet1badProof, ibcPerm, IsInvalidProofErr}, - - // all good -> execute tx (no special permission needed) - {packet1, nil, errors.NoErr}, - - // repeat -> error - {packet0, nil, IsPacketAlreadyExistsErr}, - - // packet2 contains invalid permissions - {packet2, nil, IsCannotSetPermissionErr}, - } - - for i, tc := range cases { - res, err := ourChain.DeliverTx(tc.packet.Wrap(), tc.permissions...) - assert.True(tc.checker(err), "%d: %+v", i, err) - if err == nil { - assert.Equal(msg, res.Log) - } - } -} diff --git a/_attic/modules/ibc/keys.go b/_attic/modules/ibc/keys.go deleted file mode 100644 index 4b5a53f980..0000000000 --- a/_attic/modules/ibc/keys.go +++ /dev/null @@ -1,60 +0,0 @@ -package ibc - -import ( - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -const ( - // this is the prefix for the list of chains - // we otherwise use the chainid as prefix, so this must not be an - // alpha-numeric byte - prefixChains = "**" - - prefixInput = "i" - prefixOutput = "o" -) - -// HandlerKey is used for the global permission info -func HandlerKey() []byte { - return []byte{0x2} -} - -// ChainsKey is the key to get info on all chains -func ChainsKey() []byte { - return stack.PrefixedKey(prefixChains, state.SetKey()) -} - -// ChainKey is the key to get info on one chain -func ChainKey(chainID string) []byte { - bkey := state.MakeBKey([]byte(chainID)) - return stack.PrefixedKey(prefixChains, bkey) -} - -// QueueInKey is the key to get newest of the input queue from this chain -func QueueInKey(chainID string) []byte { - return stack.PrefixedKey(chainID, - stack.PrefixedKey(prefixInput, - state.QueueTailKey())) -} - -// QueueOutKey is the key to get v of the output queue from this chain -func QueueOutKey(chainID string) []byte { - return stack.PrefixedKey(chainID, - stack.PrefixedKey(prefixOutput, - state.QueueTailKey())) -} - -// QueueInPacketKey is the key to get given packet from this chain's input queue -func QueueInPacketKey(chainID string, seq uint64) []byte { - return stack.PrefixedKey(chainID, - stack.PrefixedKey(prefixInput, - state.QueueItemKey(seq))) -} - -// QueueOutPacketKey is the key to get given packet from this chain's output queue -func QueueOutPacketKey(chainID string, seq uint64) []byte { - return stack.PrefixedKey(chainID, - stack.PrefixedKey(prefixOutput, - state.QueueItemKey(seq))) -} diff --git a/_attic/modules/ibc/middleware.go b/_attic/modules/ibc/middleware.go deleted file mode 100644 index 09ffabb142..0000000000 --- a/_attic/modules/ibc/middleware.go +++ /dev/null @@ -1,120 +0,0 @@ -package ibc - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -// Middleware allows us to verify the IBC proof on a packet and -// and if valid, attach this permission to the wrapped packet -type Middleware struct { - stack.PassInitState - stack.PassInitValidate -} - -var _ stack.Middleware = Middleware{} - -// NewMiddleware creates a role-checking middleware -func NewMiddleware() Middleware { - return Middleware{} -} - -// Name - return name space -func (Middleware) Name() string { - return NameIBC -} - -// CheckTx verifies the named chain and height is present, and verifies -// the merkle proof in the packet -func (m Middleware) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) { - // if it is not a PostPacket, just let it go through - post, ok := tx.Unwrap().(PostPacketTx) - if !ok { - return next.CheckTx(ctx, store, tx) - } - - // parse this packet and get the ibc-enhanced tx and context - ictx, itx, err := m.verifyPost(ctx, store, post) - if err != nil { - return res, err - } - return next.CheckTx(ictx, store, itx) -} - -// DeliverTx verifies the named chain and height is present, and verifies -// the merkle proof in the packet -func (m Middleware) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) { - // if it is not a PostPacket, just let it go through - post, ok := tx.Unwrap().(PostPacketTx) - if !ok { - return next.DeliverTx(ctx, store, tx) - } - - // parse this packet and get the ibc-enhanced tx and context - ictx, itx, err := m.verifyPost(ctx, store, post) - if err != nil { - return res, err - } - return next.DeliverTx(ictx, store, itx) -} - -// verifyPost accepts a message bound for this chain... -// TODO: think about relay -func (m Middleware) verifyPost(ctx sdk.Context, store state.SimpleDB, - tx PostPacketTx) (ictx sdk.Context, itx sdk.Tx, err error) { - - // make sure the chain is registered - from := tx.FromChainID - if !NewChainSet(store).Exists([]byte(from)) { - return ictx, itx, ErrNotRegistered(from) - } - - // TODO: how to deal with routing/relaying??? - packet := tx.Packet - if packet.DestChain != ctx.ChainID() { - return ictx, itx, ErrWrongDestChain(packet.DestChain) - } - - // verify packet.Permissions all come from the other chain - if !packet.Permissions.AllHaveChain(tx.FromChainID) { - return ictx, itx, ErrCannotSetPermission() - } - - // make sure this sequence number is the next in the list - q := InputQueue(store, from) - tail := q.Tail() - if packet.Sequence < tail { - return ictx, itx, ErrPacketAlreadyExists() - } - if packet.Sequence > tail { - return ictx, itx, ErrPacketOutOfOrder(tail) - } - - // look up the referenced header - space := stack.PrefixedStore(from, store) - provider := newDBProvider(space) - - // if the query was on height H, the proof is in header H+1 - proofHeight := int(tx.FromChainHeight + 1) - seed, err := provider.GetExactHeight(proofHeight) - if err != nil { - return ictx, itx, err - } - - // verify the merkle hash.... - root := seed.Header.AppHash - pBytes := packet.Bytes() - err = tx.Proof.Verify(tx.Key, pBytes, root) - if err != nil { - return ictx, itx, ErrInvalidProofWithReason(err) - } - - // add to input queue - q.Push(pBytes) - - // return the wrapped tx along with the extra permissions - ictx = ctx.WithPermissions(packet.Permissions...) - itx = packet.Tx - return -} diff --git a/_attic/modules/ibc/provider.go b/_attic/modules/ibc/provider.go deleted file mode 100644 index 712b6ee81d..0000000000 --- a/_attic/modules/ibc/provider.go +++ /dev/null @@ -1,105 +0,0 @@ -package ibc - -import ( - wire "github.com/tendermint/go-wire" - "github.com/tendermint/light-client/certifiers" - certerr "github.com/tendermint/light-client/certifiers/errors" - - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -const ( - prefixHash = "v" - prefixHeight = "h" - prefixPacket = "p" -) - -// newCertifier loads up the current state of this chain to make a proper certifier -// it will load the most recent height before block h if h is positive -// if h < 0, it will load the latest height -func newCertifier(store state.SimpleDB, chainID string, h int) (*certifiers.Inquiring, error) { - // each chain has their own prefixed subspace - p := newDBProvider(store) - - var fc certifiers.FullCommit - var err error - if h > 0 { - // this gets the most recent verified commit below the specified height - fc, err = p.GetByHeight(h) - } else { - // 0 or negative means start at latest commit - fc, err = p.LatestCommit() - } - if err != nil { - return nil, ErrHeaderNotFound(h) - } - - // we have no source for untrusted keys, but use the db to load trusted history - cert := certifiers.NewInquiring(chainID, fc, p, - certifiers.NewMissingProvider()) - return cert, nil -} - -// dbProvider wraps our kv store so it integrates with light-client verification -type dbProvider struct { - byHash state.SimpleDB - byHeight *state.Span -} - -func newDBProvider(store state.SimpleDB) *dbProvider { - return &dbProvider{ - byHash: stack.PrefixedStore(prefixHash, store), - byHeight: state.NewSpan(stack.PrefixedStore(prefixHeight, store)), - } -} - -var _ certifiers.Provider = &dbProvider{} - -func (d *dbProvider) StoreCommit(fc certifiers.FullCommit) error { - // TODO: don't duplicate data.... - b := wire.BinaryBytes(fc) - d.byHash.Set(fc.ValidatorsHash(), b) - d.byHeight.Set(uint64(fc.Height()), b) - return nil -} - -func (d *dbProvider) LatestCommit() (fc certifiers.FullCommit, err error) { - b, _ := d.byHeight.Top() - if b == nil { - return fc, certerr.ErrCommitNotFound() - } - err = wire.ReadBinaryBytes(b, &fc) - return -} - -func (d *dbProvider) GetByHeight(h int) (fc certifiers.FullCommit, err error) { - b, _ := d.byHeight.LTE(uint64(h)) - if b == nil { - return fc, certerr.ErrCommitNotFound() - } - err = wire.ReadBinaryBytes(b, &fc) - return -} - -func (d *dbProvider) GetByHash(hash []byte) (fc certifiers.FullCommit, err error) { - b := d.byHash.Get(hash) - if b == nil { - return fc, certerr.ErrCommitNotFound() - } - err = wire.ReadBinaryBytes(b, &fc) - return -} - -// GetExactHeight is like GetByHeight, but returns an error instead of -// closest match if there is no exact match -func (d *dbProvider) GetExactHeight(h int) (fc certifiers.FullCommit, err error) { - fc, err = d.GetByHeight(h) - if err != nil { - return - } - if fc.Height() != h { - err = ErrHeaderNotFound(h) - } - return -} diff --git a/_attic/modules/ibc/provider_test.go b/_attic/modules/ibc/provider_test.go deleted file mode 100644 index 2318f97965..0000000000 --- a/_attic/modules/ibc/provider_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package ibc - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/state" - "github.com/tendermint/light-client/certifiers" - certerr "github.com/tendermint/light-client/certifiers/errors" -) - -func assertCommitsEqual(t *testing.T, fc, fc2 certifiers.FullCommit) { - assert := assert.New(t) - assert.Equal(fc.Height(), fc2.Height()) - assert.Equal(fc.ValidatorsHash(), fc2.ValidatorsHash()) - // TODO: more -} - -func TestProviderStore(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - // make a few commits - keys := certifiers.GenValKeys(2) - commits := makeCommits(keys, 4, "some-chain", "demo-store") - - // make a provider - store := state.NewMemKVStore() - p := newDBProvider(store) - - // check it... - _, err := p.GetByHeight(20) - require.NotNil(err) - assert.True(certerr.IsCommitNotFoundErr(err)) - - // add commits - for _, fc := range commits { - err = p.StoreCommit(fc) - require.Nil(err) - } - - // make sure we get it... - fc := commits[0] - val, err := p.GetByHeight(fc.Height()) - if assert.Nil(err) { - assertCommitsEqual(t, fc, val) - } - - // make sure we get higher - val, err = p.GetByHeight(fc.Height() + 2) - if assert.Nil(err) { - assertCommitsEqual(t, fc, val) - } - - // below is nothing - _, err = p.GetByHeight(fc.Height() - 2) - assert.True(certerr.IsCommitNotFoundErr(err)) - - // make sure we get highest - val, err = p.LatestCommit() - if assert.Nil(err) { - assertCommitsEqual(t, commits[3], val) - } - - // make sure by hash also (note all have same hash, so overwritten) - val, err = p.GetByHash(commits[1].ValidatorsHash()) - if assert.Nil(err) { - assertCommitsEqual(t, commits[3], val) - } -} - -func TestDBProvider(t *testing.T) { - store := state.NewMemKVStore() - p := newDBProvider(store) - checkProvider(t, p, "test-db", "bling") -} - -func makeCommits(keys certifiers.ValKeys, count int, chainID, app string) []certifiers.FullCommit { - appHash := []byte(app) - commits := make([]certifiers.FullCommit, count) - for i := 0; i < count; i++ { - // two commits for each validator, to check how we handle dups - // (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ... - vals := keys.ToValidators(10, int64(count/2)) - h := 20 + 10*i - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys)) - } - return commits -} - -func checkProvider(t *testing.T, p certifiers.Provider, chainID, app string) { - assert, require := assert.New(t), require.New(t) - keys := certifiers.GenValKeys(5) - count := 10 - - // make a bunch of commits... - commits := makeCommits(keys, count, chainID, app) - - // check provider is empty - fc, err := p.GetByHeight(20) - require.NotNil(err) - assert.True(certerr.IsCommitNotFoundErr(err)) - - fc, err = p.GetByHash(commits[3].ValidatorsHash()) - require.NotNil(err) - assert.True(certerr.IsCommitNotFoundErr(err)) - - // now add them all to the provider - for _, fc := range commits { - err = p.StoreCommit(fc) - require.Nil(err) - // and make sure we can get it back - fc2, err := p.GetByHash(fc.ValidatorsHash()) - assert.Nil(err) - assertCommitsEqual(t, fc, fc2) - // by height as well - fc2, err = p.GetByHeight(fc.Height()) - assert.Nil(err) - assertCommitsEqual(t, fc, fc2) - } - - // make sure we get the last hash if we overstep - fc, err = p.GetByHeight(5000) - if assert.Nil(err) { - assertCommitsEqual(t, commits[count-1], fc) - } - - // and middle ones as well - fc, err = p.GetByHeight(47) - if assert.Nil(err) { - // we only step by 10, so 40 must be the one below this - assert.Equal(40, fc.Height()) - } - -} diff --git a/_attic/modules/ibc/store.go b/_attic/modules/ibc/store.go deleted file mode 100644 index 6da04f004b..0000000000 --- a/_attic/modules/ibc/store.go +++ /dev/null @@ -1,122 +0,0 @@ -package ibc - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" - wire "github.com/tendermint/go-wire" -) - -// HandlerInfo is the global state of the ibc.Handler -type HandlerInfo struct { - Registrar sdk.Actor `json:"registrar"` -} - -// Save the HandlerInfo to the store -func (h HandlerInfo) Save(store state.SimpleDB) { - b := wire.BinaryBytes(h) - store.Set(HandlerKey(), b) -} - -// LoadInfo loads the HandlerInfo from the data store -func LoadInfo(store state.SimpleDB) (h HandlerInfo) { - b := store.Get(HandlerKey()) - if len(b) > 0 { - wire.ReadBinaryBytes(b, &h) - } - return -} - -// ChainInfo is the global info we store for each registered chain, -// besides the headers, proofs, and packets -type ChainInfo struct { - RegisteredAt uint64 `json:"registered_at"` - RemoteBlock int `json:"remote_block"` -} - -// ChainSet is the set of all registered chains -type ChainSet struct { - *state.Set -} - -// NewChainSet loads or initialized the ChainSet -func NewChainSet(store state.SimpleDB) ChainSet { - space := stack.PrefixedStore(prefixChains, store) - return ChainSet{ - Set: state.NewSet(space), - } -} - -// Register adds the named chain with some info -// returns error if already present -func (c ChainSet) Register(chainID string, ourHeight uint64, theirHeight int) error { - if c.Exists([]byte(chainID)) { - return ErrAlreadyRegistered(chainID) - } - info := ChainInfo{ - RegisteredAt: ourHeight, - RemoteBlock: theirHeight, - } - data := wire.BinaryBytes(info) - c.Set.Set([]byte(chainID), data) - return nil -} - -// Update sets the new tracked height on this chain -// returns error if not present -func (c ChainSet) Update(chainID string, theirHeight int) error { - d := c.Set.Get([]byte(chainID)) - if len(d) == 0 { - return ErrNotRegistered(chainID) - } - // load the data - var info ChainInfo - err := wire.ReadBinaryBytes(d, &info) - if err != nil { - return err - } - - // change the remote block and save it - info.RemoteBlock = theirHeight - d = wire.BinaryBytes(info) - c.Set.Set([]byte(chainID), d) - return nil -} - -// Packet is a wrapped transaction and permission that we want to -// send off to another chain. -type Packet struct { - DestChain string `json:"dest_chain"` - Sequence uint64 `json:"sequence"` - Permissions sdk.Actors `json:"permissions"` - Tx sdk.Tx `json:"tx"` -} - -// NewPacket creates a new outgoing packet -func NewPacket(tx sdk.Tx, dest string, seq uint64, perm ...sdk.Actor) Packet { - return Packet{ - DestChain: dest, - Sequence: seq, - Permissions: perm, - Tx: tx, - } -} - -// Bytes returns a serialization of the Packet -func (p Packet) Bytes() []byte { - return wire.BinaryBytes(p) -} - -// InputQueue returns the queue of input packets from this chain -func InputQueue(store state.SimpleDB, chainID string) *state.Queue { - ch := stack.PrefixedStore(chainID, store) - space := stack.PrefixedStore(prefixInput, ch) - return state.NewQueue(space) -} - -// OutputQueue returns the queue of output packets destined for this chain -func OutputQueue(store state.SimpleDB, chainID string) *state.Queue { - ch := stack.PrefixedStore(chainID, store) - space := stack.PrefixedStore(prefixOutput, ch) - return state.NewQueue(space) -} diff --git a/_attic/modules/ibc/test_helpers.go b/_attic/modules/ibc/test_helpers.go deleted file mode 100644 index 79960dadfb..0000000000 --- a/_attic/modules/ibc/test_helpers.go +++ /dev/null @@ -1,131 +0,0 @@ -package ibc - -import ( - "fmt" - - "github.com/tendermint/iavl" - "github.com/tendermint/light-client/certifiers" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -// MockChain is used to simulate a chain for ibc tests. -// It is able to produce ibc packets and all verification for -// them, but cannot respond to any responses. -type MockChain struct { - keys certifiers.ValKeys - chainID string - tree *iavl.Tree -} - -// NewMockChain initializes a teststore and test validators -func NewMockChain(chainID string, numKeys int) MockChain { - return MockChain{ - keys: certifiers.GenValKeys(numKeys), - chainID: chainID, - tree: iavl.NewTree(0, nil), - } -} - -// GetRegistrationTx returns a valid tx to register this chain -func (m MockChain) GetRegistrationTx(h int) RegisterChainTx { - fc := genEmptyCommit(m.keys, m.chainID, h, m.tree.Hash(), len(m.keys)) - return RegisterChainTx{fc} -} - -// MakePostPacket commits the packet locally and returns the proof, -// in the form of two packets to update the header and prove this packet. -func (m MockChain) MakePostPacket(packet Packet, h int) ( - PostPacketTx, UpdateChainTx) { - - post := makePostPacket(m.tree, packet, m.chainID, h) - fc := genEmptyCommit(m.keys, m.chainID, h+1, m.tree.Hash(), len(m.keys)) - update := UpdateChainTx{fc} - - return post, update -} - -func genEmptyCommit(keys certifiers.ValKeys, chain string, h int, - appHash []byte, count int) certifiers.FullCommit { - - vals := keys.ToValidators(10, 0) - return keys.GenFullCommit(chain, h, nil, vals, appHash, 0, count) -} - -func makePostPacket(tree *iavl.Tree, packet Packet, fromID string, fromHeight int) PostPacketTx { - key := []byte(fmt.Sprintf("some-long-prefix-%06d", packet.Sequence)) - tree.Set(key, packet.Bytes()) - _, proof, err := tree.GetWithProof(key) - if err != nil { - panic(err) - } - if proof == nil { - panic("wtf?") - } - - return PostPacketTx{ - FromChainID: fromID, - FromChainHeight: uint64(fromHeight), - Proof: proof.(*iavl.KeyExistsProof), - Key: key, - Packet: packet, - } -} - -// AppChain is ready to handle tx -type AppChain struct { - chainID string - app sdk.Handler - store state.SimpleDB - height int -} - -// NewAppChain returns a chain that is ready to respond to tx -func NewAppChain(app sdk.Handler, chainID string) *AppChain { - return &AppChain{ - chainID: chainID, - app: app, - store: state.NewMemKVStore(), - height: 123, - } -} - -// IncrementHeight allows us to jump heights, more than the auto-step -// of 1. It returns the new height we are at. -func (a *AppChain) IncrementHeight(delta int) int { - a.height += delta - return a.height -} - -// DeliverTx runs the tx and commits the new tree, incrementing height -// by one. -func (a *AppChain) DeliverTx(tx sdk.Tx, perms ...sdk.Actor) (sdk.DeliverResult, error) { - ctx := stack.MockContext(a.chainID, uint64(a.height)).WithPermissions(perms...) - store := a.store.Checkpoint() - res, err := a.app.DeliverTx(ctx, store, tx) - if err == nil { - // commit data on success - a.store.Commit(store) - } - return res, err -} - -// Update is a shortcut to DeliverTx with this. Also one return value -// to test inline -func (a *AppChain) Update(tx UpdateChainTx) error { - _, err := a.DeliverTx(tx.Wrap()) - return err -} - -// InitState sets the option on our app -func (a *AppChain) InitState(mod, key, value string) (string, error) { - return a.app.InitState(log.NewNopLogger(), a.store, mod, key, value) -} - -// GetStore is used to get the app-specific sub-store -func (a *AppChain) GetStore(app string) state.SimpleDB { - return stack.PrefixedStore(app, a.store) -} diff --git a/_attic/modules/ibc/tx.go b/_attic/modules/ibc/tx.go deleted file mode 100644 index eae5a38f94..0000000000 --- a/_attic/modules/ibc/tx.go +++ /dev/null @@ -1,133 +0,0 @@ -package ibc - -import ( - "github.com/tendermint/go-wire/data" - "github.com/tendermint/iavl" - "github.com/tendermint/light-client/certifiers" - - sdk "github.com/cosmos/cosmos-sdk" -) - -// nolint -const ( - // 0x3? series for ibc - ByteRegisterChain = byte(0x30) - ByteUpdateChain = byte(0x31) - ByteCreatePacket = byte(0x32) - BytePostPacket = byte(0x33) - - TypeRegisterChain = NameIBC + "/register" - TypeUpdateChain = NameIBC + "/update" - TypeCreatePacket = NameIBC + "/create" - TypePostPacket = NameIBC + "/post" -) - -func init() { - sdk.TxMapper. - RegisterImplementation(RegisterChainTx{}, TypeRegisterChain, ByteRegisterChain). - RegisterImplementation(UpdateChainTx{}, TypeUpdateChain, ByteUpdateChain). - RegisterImplementation(CreatePacketTx{}, TypeCreatePacket, ByteCreatePacket). - RegisterImplementation(PostPacketTx{}, TypePostPacket, BytePostPacket) -} - -// RegisterChainTx allows you to register a new chain on this blockchain -type RegisterChainTx struct { - Commit certifiers.FullCommit `json:"seed"` -} - -// ChainID helps get the chain this tx refers to -func (r RegisterChainTx) ChainID() string { - return r.Commit.Header.ChainID -} - -// ValidateBasic makes sure this is consistent, without checking the sigs -func (r RegisterChainTx) ValidateBasic() error { - err := r.Commit.ValidateBasic(r.ChainID()) - if err != nil { - err = ErrInvalidCommit(err) - } - return err -} - -// Wrap - used to satisfy TxInner -func (r RegisterChainTx) Wrap() sdk.Tx { - return sdk.Tx{r} -} - -// UpdateChainTx updates the state of this chain -type UpdateChainTx struct { - Commit certifiers.FullCommit `json:"seed"` -} - -// ChainID helps get the chain this tx refers to -func (u UpdateChainTx) ChainID() string { - return u.Commit.Header.ChainID -} - -// ValidateBasic makes sure this is consistent, without checking the sigs -func (u UpdateChainTx) ValidateBasic() error { - err := u.Commit.ValidateBasic(u.ChainID()) - if err != nil { - err = ErrInvalidCommit(err) - } - return err -} - -// Wrap - used to satisfy TxInner -func (u UpdateChainTx) Wrap() sdk.Tx { - return sdk.Tx{u} -} - -// CreatePacketTx is meant to be called by IPC, another module... -// -// this is the tx that will be sent to another app and the permissions it -// comes with (which must be a subset of the permissions on the current tx) -// -// If must have the special `AllowIBC` permission from the app -// that can send this packet (so only coins can request SendTx packet) -type CreatePacketTx struct { - DestChain string `json:"dest_chain"` - Permissions sdk.Actors `json:"permissions"` - Tx sdk.Tx `json:"tx"` -} - -// ValidateBasic makes sure this is consistent - used to satisfy TxInner -func (p CreatePacketTx) ValidateBasic() error { - if p.DestChain == "" { - return ErrWrongDestChain(p.DestChain) - } - return nil -} - -// Wrap - used to satisfy TxInner -func (p CreatePacketTx) Wrap() sdk.Tx { - return sdk.Tx{p} -} - -// PostPacketTx takes a wrapped packet from another chain and -// TODO!!! -// also think... which chains can relay packets??? -// right now, enforce that these packets are only sent directly, -// not routed over the hub. add routing later. -type PostPacketTx struct { - // The immediate source of the packet, not always Packet.SrcChainID - FromChainID string `json:"src_chain"` - // The block height in which Packet was committed, to check Proof - // AppHash for the proof in header for FromChainHeight+1 - FromChainHeight uint64 `json:"src_height"` - // this proof must match the header and the packet.Bytes() - Proof *iavl.KeyExistsProof `json:"proof"` - Key data.Bytes `json:"key"` - Packet Packet `json:"packet"` -} - -// ValidateBasic makes sure this is consistent - used to satisfy TxInner -func (p PostPacketTx) ValidateBasic() error { - // TODO - return nil -} - -// Wrap - used to satisfy TxInner -func (p PostPacketTx) Wrap() sdk.Tx { - return sdk.Tx{p} -} diff --git a/_attic/modules/roles/commands/query.go b/_attic/modules/roles/commands/query.go deleted file mode 100644 index 5fbc22405d..0000000000 --- a/_attic/modules/roles/commands/query.go +++ /dev/null @@ -1,39 +0,0 @@ -package commands - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/query" - "github.com/cosmos/cosmos-sdk/modules/roles" - "github.com/cosmos/cosmos-sdk/stack" -) - -// RoleQueryCmd - command to query a role -var RoleQueryCmd = &cobra.Command{ - Use: "role [name]", - Short: "Get details of a role, with proof", - RunE: commands.RequireInit(roleQueryCmd), -} - -func roleQueryCmd(cmd *cobra.Command, args []string) error { - arg, err := commands.GetOneArg(args, "name") - if err != nil { - return err - } - role, err := parseRole(arg) - if err != nil { - return err - } - - var res roles.Role - key := stack.PrefixedKey(roles.NameRole, role) - prove := !viper.GetBool(commands.FlagTrustNode) - height, err := query.GetParsed(key, &res, query.GetHeight(), prove) - if err != nil { - return err - } - - return query.OutputProof(res, height) -} diff --git a/_attic/modules/roles/commands/tx.go b/_attic/modules/roles/commands/tx.go deleted file mode 100644 index 2b018f1a8c..0000000000 --- a/_attic/modules/roles/commands/tx.go +++ /dev/null @@ -1,65 +0,0 @@ -package commands - -import ( - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/client/commands" - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - "github.com/cosmos/cosmos-sdk/modules/roles" -) - -// CreateRoleTxCmd is CLI command to create a new role -var CreateRoleTxCmd = &cobra.Command{ - Use: "create-role", - Short: "Create a new role", - RunE: commands.RequireInit(createRoleTxCmd), -} - -//nolint -const ( - FlagRole = "role" - FlagMembers = "members" - FlagMinSigs = "min-sigs" -) - -func init() { - flags := CreateRoleTxCmd.Flags() - flags.String(FlagRole, "", "Name of the role to create") - flags.String(FlagMembers, "", "Set of comma-separated addresses for this role") - flags.Int(FlagMinSigs, 0, "Minimum number of signatures needed to assume this role") -} - -// createRoleTxCmd creates a basic role tx and then wraps, signs, and posts it -func createRoleTxCmd(cmd *cobra.Command, args []string) error { - tx, err := readCreateRoleTxFlags() - if err != nil { - return err - } - return txcmd.DoTx(tx) -} - -func readCreateRoleTxFlags() (tx sdk.Tx, err error) { - role, err := parseRole(viper.GetString(FlagRole)) - if err != nil { - return tx, err - } - - sigs := viper.GetInt(FlagMinSigs) - if sigs < 1 { - return tx, errors.Errorf("--%s must be at least 1", FlagMinSigs) - } - - signers, err := commands.ParseActors(viper.GetString(FlagMembers)) - if err != nil { - return tx, err - } - if len(signers) == 0 { - return tx, errors.New("must specify at least one member") - } - - tx = roles.NewCreateRoleTx(role, uint32(sigs), signers) - return tx, nil -} diff --git a/_attic/modules/roles/commands/wrap.go b/_attic/modules/roles/commands/wrap.go deleted file mode 100644 index 9ea855e9e4..0000000000 --- a/_attic/modules/roles/commands/wrap.go +++ /dev/null @@ -1,59 +0,0 @@ -package commands - -import ( - "encoding/hex" - - "github.com/spf13/pflag" - "github.com/spf13/viper" - - abci "github.com/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - - sdk "github.com/cosmos/cosmos-sdk" - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/modules/roles" -) - -// nolint -const ( - FlagAssumeRole = "assume-role" -) - -// RoleWrapper wraps a tx with 0, 1, or more roles -type RoleWrapper struct{} - -var _ txcmd.Wrapper = RoleWrapper{} - -// Wrap grabs the sequence number from the flag and wraps -// the tx with this nonce. Grabs the permission from the signer, -// as we still only support single sig on the cli -func (RoleWrapper) Wrap(tx sdk.Tx) (sdk.Tx, error) { - assume := viper.GetStringSlice(FlagAssumeRole) - - // we wrap from inside-out, so we must wrap them in the reverse order, - // so they are applied in the order the user intended - for i := len(assume) - 1; i >= 0; i-- { - r, err := parseRole(assume[i]) - if err != nil { - return tx, err - } - tx = roles.NewAssumeRoleTx(r, tx) - } - return tx, nil -} - -// Register adds the sequence flags to the cli -func (RoleWrapper) Register(fs *pflag.FlagSet) { - fs.StringSlice(FlagAssumeRole, nil, "Roles to assume (can use multiple times)") -} - -// parse role turns the string->byte... todo: support hex? -func parseRole(role string) ([]byte, error) { - res, err := hex.DecodeString(cmn.StripHex(role)) - if err != nil { - err = errors.WithMessage("Address is invalid hex", err, - abci.CodeType_EncodingError) - } - return res, err -} diff --git a/_attic/modules/roles/error.go b/_attic/modules/roles/error.go deleted file mode 100644 index 4abdbf8956..0000000000 --- a/_attic/modules/roles/error.go +++ /dev/null @@ -1,73 +0,0 @@ -//nolint -package roles - -import ( - "fmt" - - abci "github.com/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/errors" -) - -var ( - errNoRole = fmt.Errorf("No such role") - errRoleExists = fmt.Errorf("Role already exists") - errNotMember = fmt.Errorf("Not a member") - errInsufficientSigs = fmt.Errorf("Not enough signatures") - errNoMembers = fmt.Errorf("No members specified") - errTooManyMembers = fmt.Errorf("Too many members specified") - errNotEnoughMembers = fmt.Errorf("Not enough members specified") - - unauthorized = abci.CodeType_Unauthorized -) - -// TODO: codegen? -// ex: err-gen NoRole,"No such role",CodeType_Unauthorized -func ErrNoRole() errors.TMError { - return errors.WithCode(errNoRole, unauthorized) -} -func IsNoRoleErr(err error) bool { - return errors.IsSameError(errNoRole, err) -} - -func ErrRoleExists() errors.TMError { - return errors.WithCode(errRoleExists, unauthorized) -} -func IsRoleExistsErr(err error) bool { - return errors.IsSameError(errRoleExists, err) -} - -func ErrNotMember() errors.TMError { - return errors.WithCode(errNotMember, unauthorized) -} -func IsNotMemberErr(err error) bool { - return errors.IsSameError(errNotMember, err) -} - -func ErrInsufficientSigs() errors.TMError { - return errors.WithCode(errInsufficientSigs, unauthorized) -} -func IsInsufficientSigsErr(err error) bool { - return errors.IsSameError(errInsufficientSigs, err) -} - -func ErrNoMembers() errors.TMError { - return errors.WithCode(errNoMembers, unauthorized) -} -func IsNoMembersErr(err error) bool { - return errors.IsSameError(errNoMembers, err) -} - -func ErrTooManyMembers() errors.TMError { - return errors.WithCode(errTooManyMembers, unauthorized) -} -func IsTooManyMembersErr(err error) bool { - return errors.IsSameError(errTooManyMembers, err) -} - -func ErrNotEnoughMembers() errors.TMError { - return errors.WithCode(errNotEnoughMembers, unauthorized) -} -func IsNotEnoughMembersErr(err error) bool { - return errors.IsSameError(errNotEnoughMembers, err) -} diff --git a/_attic/modules/roles/handler.go b/_attic/modules/roles/handler.go deleted file mode 100644 index f70091e89c..0000000000 --- a/_attic/modules/roles/handler.go +++ /dev/null @@ -1,71 +0,0 @@ -package roles - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -const ( - //NameRole - name space of the roles module - NameRole = "role" - // CostCreate is the cost to create a new role - CostCreate = uint64(40) - // CostAssume is the cost to assume a role as part of a tx - CostAssume = uint64(5) -) - -// Handler allows us to create new roles -type Handler struct { - sdk.NopInitState - sdk.NopInitValidate -} - -var _ sdk.Handler = Handler{} - -// NewHandler makes a role handler to create roles -func NewHandler() Handler { - return Handler{} -} - -// Name - return name space -func (Handler) Name() string { - return NameRole -} - -// CheckTx verifies if the transaction is properly formated -func (h Handler) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - var cr CreateRoleTx - cr, err = checkTx(ctx, tx) - if err != nil { - return - } - res = sdk.NewCheck(CostCreate, "") - err = checkNoRole(store, cr.Role) - return -} - -// DeliverTx tries to create a new role. -// -// Returns an error if the role already exists -func (h Handler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - create, err := checkTx(ctx, tx) - if err != nil { - return res, err - } - - // lets try... - role := NewRole(create.MinSigs, create.Signers) - err = createRole(store, create.Role, role) - return res, err -} - -func checkTx(ctx sdk.Context, tx sdk.Tx) (create CreateRoleTx, err error) { - // check if the tx is proper type and valid - create, ok := tx.Unwrap().(CreateRoleTx) - if !ok { - return create, errors.ErrInvalidFormat(TypeCreateRoleTx, tx) - } - err = create.ValidateBasic() - return create, err -} diff --git a/_attic/modules/roles/handler_test.go b/_attic/modules/roles/handler_test.go deleted file mode 100644 index f654f5acee..0000000000 --- a/_attic/modules/roles/handler_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package roles_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/roles" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -func TestCreateRole(t *testing.T) { - assert := assert.New(t) - - a := sdk.Actor{App: "foo", Address: []byte("bar")} - b := sdk.Actor{ChainID: "eth", App: "foo", Address: []byte("bar")} - c := sdk.Actor{App: "foo", Address: []byte("baz")} - d := sdk.Actor{App: "si-ly", Address: []byte("bar")} - - cases := []struct { - valid bool - role string - min uint32 - sigs []sdk.Actor - }{ - {true, "awesome", 1, []sdk.Actor{a}}, - {true, "cool", 2, []sdk.Actor{b, c, d}}, - {false, "oops", 3, []sdk.Actor{a, d}}, // too many - {false, "ugh", 0, []sdk.Actor{a, d}}, // too few - {false, "phew", 1, []sdk.Actor{}}, // none - {false, "cool", 1, []sdk.Actor{c, d}}, // duplicate of existing one - } - - h := roles.NewHandler() - ctx := stack.MockContext("role-chain", 123) - store := state.NewMemKVStore() - for i, tc := range cases { - tx := roles.NewCreateRoleTx([]byte(tc.role), tc.min, tc.sigs) - cres, err := h.CheckTx(ctx, store, tx) - _, err2 := h.DeliverTx(ctx, store, tx) - if tc.valid { - assert.Nil(err, "%d/%s: %+v", i, tc.role, err) - assert.Nil(err2, "%d/%s: %+v", i, tc.role, err2) - assert.Equal(roles.CostCreate, cres.GasAllocated) - assert.Equal(uint64(0), cres.GasPayment) - } else { - assert.NotNil(err, "%d/%s", i, tc.role) - assert.NotNil(err2, "%d/%s", i, tc.role) - } - } -} diff --git a/_attic/modules/roles/middleware.go b/_attic/modules/roles/middleware.go deleted file mode 100644 index 73d9255c8b..0000000000 --- a/_attic/modules/roles/middleware.go +++ /dev/null @@ -1,85 +0,0 @@ -package roles - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -// Middleware allows us to add a requested role as a permission -// if the tx requests it and has sufficient authority -type Middleware struct { - stack.PassInitState - stack.PassInitValidate -} - -var _ stack.Middleware = Middleware{} - -// NewMiddleware creates a role-checking middleware -func NewMiddleware() Middleware { - return Middleware{} -} - -// Name - return name space -func (Middleware) Name() string { - return NameRole -} - -// CheckTx tries to assume the named role if requested. -// If no role is requested, do nothing. -// If insufficient authority to assume the role, return error. -func (m Middleware) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) { - // if this is not an AssumeRoleTx, then continue - assume, ok := tx.Unwrap().(AssumeRoleTx) - if !ok { // this also breaks the recursion below - return next.CheckTx(ctx, store, tx) - } - - ctx, err = assumeRole(ctx, store, assume) - if err != nil { - return res, err - } - - // one could add multiple role statements, repeat as needed - // charging for each level - res, err = m.CheckTx(ctx, store, assume.Tx, next) - res.GasAllocated += CostAssume - return -} - -// DeliverTx tries to assume the named role if requested. -// If no role is requested, do nothing. -// If insufficient authority to assume the role, return error. -func (m Middleware) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) { - // if this is not an AssumeRoleTx, then continue - assume, ok := tx.Unwrap().(AssumeRoleTx) - if !ok { // this also breaks the recursion below - return next.DeliverTx(ctx, store, tx) - } - - ctx, err = assumeRole(ctx, store, assume) - if err != nil { - return res, err - } - - // one could add multiple role statements, repeat as needed - return m.DeliverTx(ctx, store, assume.Tx, next) -} - -func assumeRole(ctx sdk.Context, store state.SimpleDB, assume AssumeRoleTx) (sdk.Context, error) { - err := assume.ValidateBasic() - if err != nil { - return nil, err - } - - role, err := loadRole(store, assume.Role) - if err != nil { - return nil, err - } - - if !role.IsAuthorized(ctx) { - return nil, ErrInsufficientSigs() - } - ctx = ctx.WithPermissions(NewPerm(assume.Role)) - return ctx, nil -} diff --git a/_attic/modules/roles/middleware_test.go b/_attic/modules/roles/middleware_test.go deleted file mode 100644 index 459405cf9c..0000000000 --- a/_attic/modules/roles/middleware_test.go +++ /dev/null @@ -1,109 +0,0 @@ -package roles_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/tendermint/go-wire/data" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/roles" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -// shortcut for the lazy -type ba []sdk.Actor - -func createRole(app sdk.Handler, store state.SimpleDB, - name []byte, min uint32, sigs ...sdk.Actor) (sdk.Actor, error) { - tx := roles.NewCreateRoleTx(name, min, sigs) - ctx := stack.MockContext("foo", 1) - _, err := app.DeliverTx(ctx, store, tx) - return roles.NewPerm(name), err -} - -func TestAssumeRole(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - // one handle to add a role, another to check permissions - disp := stack.NewDispatcher( - stack.WrapHandler(roles.NewHandler()), - stack.WrapHandler(stack.CheckHandler{}), - ) - // and wrap with the roles middleware - app := stack.New(roles.NewMiddleware()).Use(disp) - - // basic state for the app - ctx := stack.MockContext("role-chain", 123) - store := state.NewMemKVStore() - - // potential actors - a := sdk.Actor{App: "sig", Address: []byte("jae")} - b := sdk.Actor{App: "sig", Address: []byte("bucky")} - c := sdk.Actor{App: "sig", Address: []byte("ethan")} - d := sdk.Actor{App: "tracko", Address: []byte("rigel")} - - // devs is a 2-of-3 multisig - devs := data.Bytes{0, 1, 0, 1} - pdev, err := createRole(app, store, devs, 2, b, c, d) - require.Nil(err) - - // deploy requires a dev role, or supreme authority - // shows how we can build larger constructs, eg. (A and B) OR C - deploy := data.Bytes("deploy") - pdeploy, err := createRole(app, store, deploy, 1, a, pdev) - require.Nil(err) - - // now, let's test the roles are set properly - cases := []struct { - valid bool - // which roles we try to assume (can be multiple!) - // note: that wrapping is FILO, so tries to assume last role first - roles []data.Bytes - signers []sdk.Actor // which people sign the tx - required []sdk.Actor // which permission we require to succeed - }{ - // basic checks to see logic works - {true, nil, nil, nil}, - {true, nil, ba{b, c}, ba{b}}, - {false, nil, ba{b}, ba{b, c}}, - - // simple role check - {false, []data.Bytes{devs}, ba{a, b}, ba{pdev}}, // not enough sigs - {false, nil, ba{b, c}, ba{pdev}}, // must explicitly request group status - {true, []data.Bytes{devs}, ba{b, c}, ba{pdev}}, // ahh... better - {true, []data.Bytes{deploy}, ba{a, b}, ba{b, pdeploy}}, // deploy also works - - // multiple levels of roles - must be in correct order - assume dev, then deploy - {false, []data.Bytes{devs, deploy}, ba{c, d}, ba{pdeploy}}, - {true, []data.Bytes{deploy, devs}, ba{c, d}, ba{pdev, pdeploy}}, - } - - for i, tc := range cases { - // set the signers, the required check - myCtx := ctx.WithPermissions(tc.signers...) - tx := stack.NewCheckTx(tc.required) - // and the roles we attempt to assume - for _, r := range tc.roles { - tx = roles.NewAssumeRoleTx(r, tx) - } - - // try CheckTx and DeliverTx and make sure they both assert permissions - cres, err := app.CheckTx(myCtx, store, tx) - _, err2 := app.DeliverTx(myCtx, store, tx) - if tc.valid { - assert.Nil(err, "%d: %+v", i, err) - assert.Nil(err2, "%d: %+v", i, err2) - // make sure we charge for each role - assert.Equal(roles.CostAssume*uint64(len(tc.roles)), cres.GasAllocated) - assert.Equal(uint64(0), cres.GasPayment) - } else { - assert.NotNil(err, "%d", i) - assert.NotNil(err2, "%d", i) - } - } -} diff --git a/_attic/modules/roles/rest/handlers.go b/_attic/modules/roles/rest/handlers.go deleted file mode 100644 index 1943634a34..0000000000 --- a/_attic/modules/roles/rest/handlers.go +++ /dev/null @@ -1,82 +0,0 @@ -package rest - -import ( - "encoding/hex" - "net/http" - - "github.com/gorilla/mux" - - abci "github.com/tendermint/abci/types" - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/modules/base" - "github.com/cosmos/cosmos-sdk/modules/nonce" - "github.com/cosmos/cosmos-sdk/modules/roles" - "github.com/tendermint/tmlibs/common" -) - -// RoleInput encapsulates the fields needed to create a role -type RoleInput struct { - // Role is a hex encoded string of the role name - // for example, instead of "role" as the name, its - // hex encoded version "726f6c65". - Role string `json:"role" validate:"required,min=2"` - - MinimumSigners uint32 `json:"min_sigs" validate:"required,min=1"` - - Signers []sdk.Actor `json:"signers" validate:"required,min=1"` - - // Sequence is the user defined field whose purpose is to - // prevent replay attacks when creating a role, since it - // ensures that for a successful role creation, the previous - // sequence number should have been looked up by the caller. - Sequence uint32 `json:"seq" validate:"required,min=1"` -} - -func decodeRoleHex(roleInHex string) ([]byte, error) { - parsedRole, err := hex.DecodeString(common.StripHex(roleInHex)) - if err != nil { - err = errors.WithMessage("invalid hex", err, abci.CodeType_EncodingError) - return nil, err - } - return parsedRole, nil -} - -// mux.Router registrars - -// RegisterCreateRole is a mux.Router handler that exposes POST -// method access on route /build/create_role to create a role. -func RegisterCreateRole(r *mux.Router) error { - r.HandleFunc("/build/create_role", doCreateRole).Methods("POST") - return nil -} - -func doCreateRole(w http.ResponseWriter, r *http.Request) { - ri := new(RoleInput) - if err := common.ParseRequestAndValidateJSON(r, ri); err != nil { - common.WriteError(w, err) - return - } - - parsedRole, err := decodeRoleHex(ri.Role) - if err != nil { - common.WriteError(w, err) - return - } - - // Note the ordering of Tx wrapping matters: - // 1. NonceTx - tx := (nonce.Tx{}).Wrap() - tx = nonce.NewTx(ri.Sequence, ri.Signers, tx) - - // 2. CreateRoleTx - tx = roles.NewCreateRoleTx(parsedRole, ri.MinimumSigners, ri.Signers) - - // 3. ChainTx - tx = base.NewChainTx(commands.GetChainID(), 0, tx) - - common.WriteSuccess(w, tx) -} - -// End of mux.Router registrars diff --git a/_attic/modules/roles/store.go b/_attic/modules/roles/store.go deleted file mode 100644 index 6268d40971..0000000000 --- a/_attic/modules/roles/store.go +++ /dev/null @@ -1,87 +0,0 @@ -package roles - -import ( - "fmt" - - wire "github.com/tendermint/go-wire" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -// NewPerm creates a role permission with the given label -func NewPerm(role []byte) sdk.Actor { - return sdk.Actor{ - App: NameRole, - Address: role, - } -} - -// Role - structure to hold permissioning -type Role struct { - MinSigs uint32 `json:"min_sigs"` - Signers []sdk.Actor `json:"signers"` -} - -// NewRole creates a Role structure to store the permissioning -func NewRole(min uint32, signers []sdk.Actor) Role { - return Role{ - MinSigs: min, - Signers: signers, - } -} - -// IsSigner checks if the given Actor is allowed to sign this role -func (r Role) IsSigner(a sdk.Actor) bool { - for _, s := range r.Signers { - if a.Equals(s) { - return true - } - } - return false -} - -// IsAuthorized checks if the context has permission to assume the role -func (r Role) IsAuthorized(ctx sdk.Context) bool { - needed := r.MinSigs - for _, s := range r.Signers { - if ctx.HasPermission(s) { - needed-- - if needed <= 0 { - return true - } - } - } - return false -} - -func loadRole(store state.SimpleDB, key []byte) (role Role, err error) { - data := store.Get(key) - if len(data) == 0 { - return role, ErrNoRole() - } - err = wire.ReadBinaryBytes(data, &role) - if err != nil { - msg := fmt.Sprintf("Error reading role %X", key) - return role, errors.ErrInternal(msg) - } - return role, nil -} - -func checkNoRole(store state.SimpleDB, key []byte) error { - if _, err := loadRole(store, key); !IsNoRoleErr(err) { - return ErrRoleExists() - } - return nil -} - -// we only have create here, no update, since we don't allow update yet -func createRole(store state.SimpleDB, key []byte, role Role) error { - if err := checkNoRole(store, key); err != nil { - return err - } - bin := wire.BinaryBytes(role) - store.Set(key, bin) - return nil // real stores can return error... -} diff --git a/_attic/modules/roles/store_test.go b/_attic/modules/roles/store_test.go deleted file mode 100644 index 445a93c726..0000000000 --- a/_attic/modules/roles/store_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package roles_test - -import ( - "strconv" - "testing" - - "github.com/stretchr/testify/assert" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/roles" - "github.com/cosmos/cosmos-sdk/stack" -) - -func TestRole(t *testing.T) { - assert := assert.New(t) - - // prepare some actors... - a := sdk.Actor{App: "foo", Address: []byte("bar")} - b := sdk.Actor{ChainID: "eth", App: "foo", Address: []byte("bar")} - c := sdk.Actor{App: "foo", Address: []byte("baz")} - d := sdk.Actor{App: "si-ly", Address: []byte("bar")} - e := sdk.Actor{App: "si-ly", Address: []byte("big")} - f := sdk.Actor{App: "sig", Address: []byte{1}} - g := sdk.Actor{App: "sig", Address: []byte{2, 3, 4}} - - cases := []struct { - sigs uint32 - allowed []sdk.Actor - signers []sdk.Actor - valid bool - }{ - // make sure simple compare is correct - {1, []sdk.Actor{a}, []sdk.Actor{a}, true}, - {1, []sdk.Actor{a}, []sdk.Actor{b}, false}, - {1, []sdk.Actor{a}, []sdk.Actor{c}, false}, - {1, []sdk.Actor{a}, []sdk.Actor{d}, false}, - // make sure multi-sig counts to 1 - {1, []sdk.Actor{a, b, c}, []sdk.Actor{d, e, a, f}, true}, - {1, []sdk.Actor{a, b, c}, []sdk.Actor{a, b, c, d}, true}, - {1, []sdk.Actor{a, b, c}, []sdk.Actor{d, e, f}, false}, - // make sure multi-sig counts higher - {2, []sdk.Actor{b, e, g}, []sdk.Actor{g, c, a, d, b}, true}, - {2, []sdk.Actor{b, e, g}, []sdk.Actor{c, a, d, b}, false}, - {3, []sdk.Actor{a, b, c}, []sdk.Actor{g}, false}, - } - - for idx, tc := range cases { - i := strconv.Itoa(idx) - // make sure IsSigner works - role := roles.NewRole(tc.sigs, tc.allowed) - for _, a := range tc.allowed { - assert.True(role.IsSigner(a), i) - } - // make sure IsAuthorized works - ctx := stack.MockContext("chain-id", 100).WithPermissions(tc.signers...) - allowed := role.IsAuthorized(ctx) - assert.Equal(tc.valid, allowed, i) - } - -} diff --git a/_attic/modules/roles/tx.go b/_attic/modules/roles/tx.go deleted file mode 100644 index c059478834..0000000000 --- a/_attic/modules/roles/tx.go +++ /dev/null @@ -1,98 +0,0 @@ -package roles - -import ( - "github.com/tendermint/go-wire/data" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" -) - -var ( - // MaxMembers it the maximum number of members in a Role. Used to avoid - // extremely large roles. - // Value is arbitrary, please adjust as needed - MaxMembers = 20 -) - -//nolint -const ( - ByteAssumeRoleTx = 0x23 - ByteCreateRoleTx = 0x24 - - TypeAssumeRoleTx = NameRole + "/assume" // no prefix needed as it is middleware - TypeCreateRoleTx = NameRole + "/create" // prefix needed for dispatcher -) - -func init() { - sdk.TxMapper. - RegisterImplementation(AssumeRoleTx{}, TypeAssumeRoleTx, ByteAssumeRoleTx). - RegisterImplementation(CreateRoleTx{}, TypeCreateRoleTx, ByteCreateRoleTx) -} - -// AssumeRoleTx is a layered tx that can wrap your normal tx to give it -// the authority to use a given role. -type AssumeRoleTx struct { - Role data.Bytes `json:"role"` - Tx sdk.Tx `json:"tx"` -} - -// NewAssumeRoleTx creates a new wrapper to add a role to a tx execution -func NewAssumeRoleTx(role []byte, tx sdk.Tx) sdk.Tx { - return AssumeRoleTx{Role: role, Tx: tx}.Wrap() -} - -// ValidateBasic - validate nothing is empty -func (tx AssumeRoleTx) ValidateBasic() error { - if len(tx.Role) == 0 { - return ErrNoRole() - } - if tx.Tx.Empty() { - return errors.ErrUnknownTxType(tx.Tx) - } - return nil -} - -// Wrap - used to satisfy TxInner -func (tx AssumeRoleTx) Wrap() sdk.Tx { - return sdk.Tx{tx} -} - -// CreateRoleTx is used to construct a new role -// -// TODO: add ability to update signers on a role... but that adds a lot -// more complexity to the permissions -type CreateRoleTx struct { - Role data.Bytes `json:"role"` - MinSigs uint32 `json:"min_sigs"` - Signers []sdk.Actor `json:"signers"` -} - -// NewCreateRoleTx creates a new role, which we can later use -func NewCreateRoleTx(role []byte, minSigs uint32, signers []sdk.Actor) sdk.Tx { - return CreateRoleTx{Role: role, MinSigs: minSigs, Signers: signers}.Wrap() -} - -// ValidateBasic - validate nothing is empty -func (tx CreateRoleTx) ValidateBasic() error { - if len(tx.Role) == 0 { - return ErrNoRole() - } - if tx.MinSigs == 0 { - return ErrNoMembers() - } - if len(tx.Signers) == 0 { - return ErrNoMembers() - } - if len(tx.Signers) < int(tx.MinSigs) { - return ErrNotEnoughMembers() - } - if len(tx.Signers) > MaxMembers { - return ErrTooManyMembers() - } - return nil -} - -// Wrap - used to satisfy TxInner -func (tx CreateRoleTx) Wrap() sdk.Tx { - return sdk.Tx{tx} -} diff --git a/_attic/modules/stack/checkpoint.go b/_attic/modules/stack/checkpoint.go deleted file mode 100644 index 53c32b88bb..0000000000 --- a/_attic/modules/stack/checkpoint.go +++ /dev/null @@ -1,52 +0,0 @@ -package stack - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" -) - -//nolint -const ( - NameCheckpoint = "check" -) - -// Checkpoint isolates all data store below this -type Checkpoint struct { - OnCheck bool - OnDeliver bool - PassInitState - PassInitValidate -} - -// Name of the module - fulfills Middleware interface -func (Checkpoint) Name() string { - return NameCheckpoint -} - -var _ Middleware = Checkpoint{} - -// CheckTx reverts all data changes if there was an error -func (c Checkpoint) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) { - if !c.OnCheck { - return next.CheckTx(ctx, store, tx) - } - ps := store.Checkpoint() - res, err = next.CheckTx(ctx, ps, tx) - if err == nil { - err = store.Commit(ps) - } - return res, err -} - -// DeliverTx reverts all data changes if there was an error -func (c Checkpoint) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) { - if !c.OnDeliver { - return next.DeliverTx(ctx, store, tx) - } - ps := store.Checkpoint() - res, err = next.DeliverTx(ctx, ps, tx) - if err == nil { - err = store.Commit(ps) - } - return res, err -} diff --git a/_attic/modules/stack/checkpoint_test.go b/_attic/modules/stack/checkpoint_test.go deleted file mode 100644 index 1cad0121e4..0000000000 --- a/_attic/modules/stack/checkpoint_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package stack - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/tendermint/iavl" - db "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" -) - -func makeState() state.SimpleDB { - // return state.NewMemKVStore() - - return state.NewBonsai(iavl.NewVersionedTree(0, db.NewMemDB())) - - // tree with persistence.... - // tmpDir, err := ioutil.TempDir("", "state-tests") - // if err != nil { - // panic(err) - // } - // db := dbm.NewDB("test-get-dbs", dbm.LevelDBBackendStr, tmpDir) - // persist := iavl.NewIAVLTree(500, db) - // return state.NewBonsai(persist) -} - -func TestCheckpointer(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - good := writerHand{name: "foo", key: []byte{1, 2}, value: []byte("bar")} - bad := FailHandler{Err: errors.New("no go")} - - app := New( - Checkpoint{OnCheck: true}, - writerMid{name: "bing", key: []byte{1, 2}, value: []byte("bang")}, - Checkpoint{OnDeliver: true}, - ).Use( - NewDispatcher( - WrapHandler(good), - WrapHandler(bad), - )) - - sdk.TxMapper.RegisterImplementation(RawTx{}, good.Name(), byte(80)) - - mid := state.Model{ - Key: []byte{'b', 'i', 'n', 'g', 0, 1, 2}, - Value: []byte("bang"), - } - end := state.Model{ - Key: []byte{'f', 'o', 'o', 0, 1, 2}, - Value: []byte("bar"), - } - - cases := []struct { - // tx to send down the line - tx sdk.Tx - // expect no error? - valid bool - // models to check afterwards - toGetCheck []state.Model - // models to check afterwards - toGetDeliver []state.Model - }{ - // everything writen on success - { - tx: NewRawTx([]byte{45, 67}), - valid: true, - toGetCheck: []state.Model{mid, end}, - toGetDeliver: []state.Model{mid, end}, - }, - // mostly reverted on failure - { - tx: NewFailTx(), - valid: false, - toGetCheck: []state.Model{}, - toGetDeliver: []state.Model{mid}, - }, - } - - for i, tc := range cases { - ctx := NewContext("foo", 100, log.NewNopLogger()) - - store := makeState() - _, err := app.CheckTx(ctx, store, tc.tx) - if tc.valid { - require.Nil(err, "%+v", err) - } else { - require.NotNil(err) - } - for _, m := range tc.toGetCheck { - val := store.Get(m.Key) - assert.EqualValues(m.Value, val, "%d: %#v", i, m) - } - - store = makeState() - _, err = app.DeliverTx(ctx, store, tc.tx) - if tc.valid { - require.Nil(err, "%+v", err) - } else { - require.NotNil(err) - } - for _, m := range tc.toGetDeliver { - val := store.Get(m.Key) - assert.EqualValues(m.Value, val, "%d: %#v", i, m) - } - - } -} diff --git a/_attic/modules/stack/context.go b/_attic/modules/stack/context.go deleted file mode 100644 index f923e89ad9..0000000000 --- a/_attic/modules/stack/context.go +++ /dev/null @@ -1,124 +0,0 @@ -package stack - -import ( - "github.com/pkg/errors" - - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" -) - -// store nonce as it's own type so no one can even try to fake it -type nonce int64 - -type secureContext struct { - app string - ibc bool - // this exposes the log.Logger and all other methods we don't override - naiveContext -} - -// NewContext - create a new secureContext -func NewContext(chain string, height uint64, logger log.Logger) sdk.Context { - mock := MockContext(chain, height).(naiveContext) - mock.Logger = logger - return secureContext{ - naiveContext: mock, - } -} - -var _ sdk.Context = secureContext{} - -// WithPermissions will panic if they try to set permission without the proper app -func (c secureContext) WithPermissions(perms ...sdk.Actor) sdk.Context { - // the guard makes sure you only set permissions for the app you are inside - for _, p := range perms { - if !c.validPermission(p) { - err := errors.Errorf("Cannot set permission for %s/%s on (app=%s, ibc=%b)", - p.ChainID, p.App, c.app, c.ibc) - panic(err) - } - } - - return secureContext{ - app: c.app, - ibc: c.ibc, - naiveContext: c.naiveContext.WithPermissions(perms...).(naiveContext), - } -} - -func (c secureContext) validPermission(p sdk.Actor) bool { - // if app is set, then it must match - if c.app != "" && c.app != p.App { - return false - } - // if ibc, chain must be set, otherwise it must not - return c.ibc == (p.ChainID != "") -} - -// Reset should clear out all permissions, -// but carry on knowledge that this is a child -func (c secureContext) Reset() sdk.Context { - return secureContext{ - app: c.app, - ibc: c.ibc, - naiveContext: c.naiveContext.Reset().(naiveContext), - } -} - -// IsParent ensures that this is derived from the given secureClient -func (c secureContext) IsParent(other sdk.Context) bool { - so, ok := other.(secureContext) - if !ok { - return false - } - return c.naiveContext.IsParent(so.naiveContext) -} - -// withApp is a private method that we can use to properly set the -// app controls in the middleware -func withApp(ctx sdk.Context, app string) sdk.Context { - sc, ok := ctx.(secureContext) - if !ok { - return ctx - } - return secureContext{ - app: app, - ibc: false, - naiveContext: sc.naiveContext, - } -} - -// withIBC is a private method so we can securely allow IBC permissioning -func withIBC(ctx sdk.Context) sdk.Context { - sc, ok := ctx.(secureContext) - if !ok { - return ctx - } - return secureContext{ - app: "", - ibc: true, - naiveContext: sc.naiveContext, - } -} - -func secureCheck(h sdk.Checker, parent sdk.Context) sdk.Checker { - next := func(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - if !parent.IsParent(ctx) { - return res, errors.New("Passing in non-child Context") - } - return h.CheckTx(ctx, store, tx) - } - return sdk.CheckerFunc(next) -} - -func secureDeliver(h sdk.Deliver, parent sdk.Context) sdk.Deliver { - next := func(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - if !parent.IsParent(ctx) { - return res, errors.New("Passing in non-child Context") - } - return h.DeliverTx(ctx, store, tx) - } - return sdk.DeliverFunc(next) -} diff --git a/_attic/modules/stack/dispatcher.go b/_attic/modules/stack/dispatcher.go deleted file mode 100644 index 89c489696d..0000000000 --- a/_attic/modules/stack/dispatcher.go +++ /dev/null @@ -1,170 +0,0 @@ -package stack - -import ( - "fmt" - "sort" - "strings" - - abci "github.com/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -// nolint -const ( - NameDispatcher = "disp" -) - -// Dispatcher grabs a bunch of Dispatchables and groups them into one Handler. -// -// It will route tx to the proper locations and also allows them to call each -// other synchronously through the same tx methods. -// -// Please note that iterating through a map is a non-deteministic operation -// and, as such, should never be done in the context of an ABCI app. Only -// use this map to look up an exact route by name. -type Dispatcher struct { - routes map[string]Dispatchable -} - -// NewDispatcher creates a dispatcher and adds the given routes. -// You can also add routes later with .AddRoutes() -func NewDispatcher(routes ...Dispatchable) *Dispatcher { - d := &Dispatcher{ - routes: map[string]Dispatchable{}, - } - d.AddRoutes(routes...) - return d -} - -var _ sdk.Handler = new(Dispatcher) - -// AddRoutes registers all these dispatchable choices under their subdomains -// -// Panics on attempt to double-register a route name, as this is a configuration error. -// Should I retrun an error instead? -func (d *Dispatcher) AddRoutes(routes ...Dispatchable) { - for _, r := range routes { - name := r.Name() - if _, ok := d.routes[name]; ok { - panic(fmt.Sprintf("%s already registered with dispatcher", name)) - } - d.routes[name] = r - } -} - -// Name - defines the name of this module -func (d *Dispatcher) Name() string { - return NameDispatcher -} - -// CheckTx - implements Handler interface -// -// Tries to find a registered module (Dispatchable) based on the name of the tx. -// The tx name (as registered with go-data) should be in the form `/XXXX`, -// where `module name` must match the name of a dispatchable and XXX can be any string. -func (d *Dispatcher) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - r, err := d.lookupTx(tx) - if err != nil { - return res, err - } - - // make sure no monkey business with the context - cb := secureCheck(d, ctx) - - // and isolate the permissions and the data store for this app - ctx = withApp(ctx, r.Name()) - store = stateSpace(store, r.Name()) - - return r.CheckTx(ctx, store, tx, cb) -} - -// DeliverTx - implements Handler interface -// -// Tries to find a registered module (Dispatchable) based on the name of the tx. -// The tx name (as registered with go-data) should be in the form `/XXXX`, -// where `module name` must match the name of a dispatchable and XXX can be any string. -func (d *Dispatcher) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - r, err := d.lookupTx(tx) - if err != nil { - return res, err - } - - // make sure no monkey business with the context - cb := secureDeliver(d, ctx) - - // and isolate the permissions and the data store for this app - ctx = withApp(ctx, r.Name()) - store = stateSpace(store, r.Name()) - - return r.DeliverTx(ctx, store, tx, cb) -} - -// InitState - implements Handler interface -// -// Tries to find a registered module (Dispatchable) based on the -// module name from InitState of the tx. -func (d *Dispatcher) InitState(l log.Logger, store state.SimpleDB, module, key, value string) (string, error) { - r, err := d.lookupModule(module) - if err != nil { - return "", err - } - - // no ctx, so secureCheck not needed - cb := d - // but isolate data space - store = stateSpace(store, r.Name()) - - return r.InitState(l, store, module, key, value, cb) -} - -// InitValidate makes sure all modules are informed -func (d *Dispatcher) InitValidate(log log.Logger, store state.SimpleDB, vals []*abci.Validator) { - for _, mod := range d.sortedModules() { - // no ctx, so secureCheck not needed - cb := d - space := stateSpace(store, mod.Name()) - mod.InitValidate(log, space, vals, cb) - } -} - -func (d *Dispatcher) lookupTx(tx sdk.Tx) (Dispatchable, error) { - kind, err := tx.GetKind() - if err != nil { - return nil, err - } - // grab everything before the / - name := strings.SplitN(kind, "/", 2)[0] - r, ok := d.routes[name] - if !ok { - return nil, errors.ErrUnknownTxType(tx) - } - return r, nil -} - -func (d *Dispatcher) lookupModule(name string) (Dispatchable, error) { - r, ok := d.routes[name] - if !ok { - return nil, errors.ErrUnknownModule(name) - } - return r, nil -} - -func (d *Dispatcher) sortedModules() []Dispatchable { - // order all routes names - size := len(d.routes) - names := make([]string, 0, size) - for k := range d.routes { - names = append(names, k) - } - sort.Strings(names) - - res := make([]Dispatchable, size) - for i, k := range names { - res[i] = d.routes[k] - } - return res -} diff --git a/_attic/modules/stack/helpers.go b/_attic/modules/stack/helpers.go deleted file mode 100644 index 000b82fcfc..0000000000 --- a/_attic/modules/stack/helpers.go +++ /dev/null @@ -1,239 +0,0 @@ -package stack - -import ( - "github.com/tendermint/go-wire/data" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -//nolint -const ( - NameOK = "ok" - NameFail = "fail" - NamePanic = "panic" - NameEcho = "echo" -) - -//nolint -const ( - ByteRawTx = 0xF0 - ByteCheckTx = 0xF1 - ByteFailTx = 0xF2 - - TypeRawTx = NameOK + "/raw" // this will just say a-ok to RawTx - TypeCheckTx = NameCheck + "/tx" - TypeFailTx = NameFail + "/tx" - - rawMaxSize = 2000 * 1000 -) - -func init() { - sdk.TxMapper. - RegisterImplementation(RawTx{}, TypeRawTx, ByteRawTx). - RegisterImplementation(CheckTx{}, TypeCheckTx, ByteCheckTx). - RegisterImplementation(FailTx{}, TypeFailTx, ByteFailTx) -} - -// RawTx just contains bytes that can be hex-ified -type RawTx struct { - data.Bytes -} - -var _ sdk.TxInner = RawTx{} - -// nolint -func NewRawTx(d []byte) sdk.Tx { - return RawTx{data.Bytes(d)}.Wrap() -} -func (r RawTx) Wrap() sdk.Tx { - return sdk.Tx{r} -} -func (r RawTx) ValidateBasic() error { - if len(r.Bytes) > rawMaxSize { - return errors.ErrTooLarge() - } - return nil -} - -// CheckTx contains a list of permissions to be tested -type CheckTx struct { - Required []sdk.Actor -} - -var _ sdk.TxInner = CheckTx{} - -// nolint -func NewCheckTx(req []sdk.Actor) sdk.Tx { - return CheckTx{req}.Wrap() -} -func (c CheckTx) Wrap() sdk.Tx { - return sdk.Tx{c} -} -func (CheckTx) ValidateBasic() error { - return nil -} - -// FailTx just gets routed to filaure -type FailTx struct{} - -var _ sdk.TxInner = FailTx{} - -func NewFailTx() sdk.Tx { - return FailTx{}.Wrap() -} - -func (f FailTx) Wrap() sdk.Tx { - return sdk.Tx{f} -} -func (r FailTx) ValidateBasic() error { - return nil -} - -// OKHandler just used to return okay to everything -type OKHandler struct { - Log string - sdk.NopInitState - sdk.NopInitValidate -} - -var _ sdk.Handler = OKHandler{} - -// Name - return handler's name -func (OKHandler) Name() string { - return NameOK -} - -// CheckTx always returns an empty success tx -func (ok OKHandler) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - return sdk.CheckResult{Log: ok.Log}, nil -} - -// DeliverTx always returns an empty success tx -func (ok OKHandler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - return sdk.DeliverResult{Log: ok.Log}, nil -} - -// EchoHandler returns success, echoing res.Data = tx bytes -type EchoHandler struct { - sdk.NopInitState - sdk.NopInitValidate -} - -var _ sdk.Handler = EchoHandler{} - -// Name - return handler's name -func (EchoHandler) Name() string { - return NameEcho -} - -// CheckTx always returns an empty success tx -func (EchoHandler) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - data, err := data.ToWire(tx) - return sdk.CheckResult{Data: data}, err -} - -// DeliverTx always returns an empty success tx -func (EchoHandler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - data, err := data.ToWire(tx) - return sdk.DeliverResult{Data: data}, err -} - -// FailHandler always returns an error -type FailHandler struct { - Err error - sdk.NopInitState - sdk.NopInitValidate -} - -var _ sdk.Handler = FailHandler{} - -// Name - return handler's name -func (FailHandler) Name() string { - return NameFail -} - -// CheckTx always returns the given error -func (f FailHandler) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - return res, errors.Wrap(f.Err) -} - -// DeliverTx always returns the given error -func (f FailHandler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - return res, errors.Wrap(f.Err) -} - -// PanicHandler always panics, using the given error (first choice) or msg (fallback) -type PanicHandler struct { - Msg string - Err error - sdk.NopInitState - sdk.NopInitValidate -} - -var _ sdk.Handler = PanicHandler{} - -// Name - return handler's name -func (PanicHandler) Name() string { - return NamePanic -} - -// CheckTx always panics -func (p PanicHandler) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - if p.Err != nil { - panic(p.Err) - } - panic(p.Msg) -} - -// DeliverTx always panics -func (p PanicHandler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - if p.Err != nil { - panic(p.Err) - } - panic(p.Msg) -} - -// CheckHandler accepts CheckTx and verifies the permissions -type CheckHandler struct { - sdk.NopInitState - sdk.NopInitValidate -} - -var _ sdk.Handler = CheckHandler{} - -// Name - return handler's name -func (CheckHandler) Name() string { - return NameCheck -} - -// CheckTx verifies the permissions -func (c CheckHandler) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.CheckResult, err error) { - check, ok := tx.Unwrap().(CheckTx) - if !ok { - return res, errors.ErrUnknownTxType(tx) - } - - for _, perm := range check.Required { - if !ctx.HasPermission(perm) { - return res, errors.ErrUnauthorized() - } - } - return res, nil -} - -// DeliverTx verifies the permissions -func (c CheckHandler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - check, ok := tx.Unwrap().(CheckTx) - if !ok { - return res, errors.ErrUnknownTxType(tx) - } - - for _, perm := range check.Required { - if !ctx.HasPermission(perm) { - return res, errors.ErrUnauthorized() - } - } - return res, nil -} diff --git a/_attic/modules/stack/helpers_test.go b/_attic/modules/stack/helpers_test.go deleted file mode 100644 index d28c0ce21d..0000000000 --- a/_attic/modules/stack/helpers_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package stack - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" -) - -func TestOK(t *testing.T) { - assert := assert.New(t) - - ctx := NewContext("test-chain", 20, log.NewNopLogger()) - store := state.NewMemKVStore() - data := "this looks okay" - tx := sdk.Tx{} - - ok := OKHandler{Log: data} - res, err := ok.CheckTx(ctx, store, tx) - assert.Nil(err, "%+v", err) - assert.Equal(data, res.Log) - - dres, err := ok.DeliverTx(ctx, store, tx) - assert.Nil(err, "%+v", err) - assert.Equal(data, dres.Log) -} - -func TestFail(t *testing.T) { - assert := assert.New(t) - - ctx := NewContext("test-chain", 20, log.NewNopLogger()) - store := state.NewMemKVStore() - msg := "big problem" - tx := sdk.Tx{} - - fail := FailHandler{Err: errors.New(msg)} - _, err := fail.CheckTx(ctx, store, tx) - if assert.NotNil(err) { - assert.Equal(msg, err.Error()) - } - - _, err = fail.DeliverTx(ctx, store, tx) - if assert.NotNil(err) { - assert.Equal(msg, err.Error()) - } -} - -func TestPanic(t *testing.T) { - assert := assert.New(t) - - ctx := NewContext("test-chain", 20, log.NewNopLogger()) - store := state.NewMemKVStore() - msg := "system crash!" - tx := sdk.Tx{} - - fail := PanicHandler{Msg: msg} - assert.Panics(func() { fail.CheckTx(ctx, store, tx) }) - assert.Panics(func() { fail.DeliverTx(ctx, store, tx) }) -} - -func TestCheck(t *testing.T) { - assert := assert.New(t) - - ctx := MockContext("check-chain", 123) - store := state.NewMemKVStore() - h := CheckHandler{} - - a := sdk.Actor{App: "foo", Address: []byte("baz")} - b := sdk.Actor{App: "si-ly", Address: []byte("bar")} - - cases := []struct { - valid bool - signers, required []sdk.Actor - }{ - {true, nil, nil}, - {true, []sdk.Actor{a}, []sdk.Actor{a}}, - {true, []sdk.Actor{a, b}, []sdk.Actor{a}}, - {false, []sdk.Actor{a}, []sdk.Actor{a, b}}, - {false, []sdk.Actor{a}, []sdk.Actor{b}}, - } - - for i, tc := range cases { - tx := CheckTx{tc.required}.Wrap() - myCtx := ctx.WithPermissions(tc.signers...) - _, err := h.CheckTx(myCtx, store, tx) - _, err2 := h.DeliverTx(myCtx, store, tx) - if tc.valid { - assert.Nil(err, "%d: %+v", i, err) - assert.Nil(err2, "%d: %+v", i, err2) - } else { - assert.NotNil(err, "%d", i) - assert.NotNil(err2, "%d", i) - } - } -} diff --git a/_attic/modules/stack/helperware.go b/_attic/modules/stack/helperware.go deleted file mode 100644 index 65e40842cc..0000000000 --- a/_attic/modules/stack/helperware.go +++ /dev/null @@ -1,64 +0,0 @@ -//nolint -package stack - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -const ( - NameCheck = "check" - NameGrant = "grant" -) - -// CheckMiddleware returns an error if the tx doesn't have auth of this -// Required Actor, otherwise passes along the call untouched -type CheckMiddleware struct { - Required sdk.Actor - PassInitState - PassInitValidate -} - -var _ Middleware = CheckMiddleware{} - -func (_ CheckMiddleware) Name() string { - return NameCheck -} - -func (p CheckMiddleware) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) { - if !ctx.HasPermission(p.Required) { - return res, errors.ErrUnauthorized() - } - return next.CheckTx(ctx, store, tx) -} - -func (p CheckMiddleware) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) { - if !ctx.HasPermission(p.Required) { - return res, errors.ErrUnauthorized() - } - return next.DeliverTx(ctx, store, tx) -} - -// GrantMiddleware tries to set the permission to this Actor, which may be prohibited -type GrantMiddleware struct { - Auth sdk.Actor - PassInitState - PassInitValidate -} - -var _ Middleware = GrantMiddleware{} - -func (_ GrantMiddleware) Name() string { - return NameGrant -} - -func (g GrantMiddleware) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) { - ctx = ctx.WithPermissions(g.Auth) - return next.CheckTx(ctx, store, tx) -} - -func (g GrantMiddleware) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) { - ctx = ctx.WithPermissions(g.Auth) - return next.DeliverTx(ctx, store, tx) -} diff --git a/_attic/modules/stack/interface.go b/_attic/modules/stack/interface.go deleted file mode 100644 index db2542797f..0000000000 --- a/_attic/modules/stack/interface.go +++ /dev/null @@ -1,147 +0,0 @@ -//nolint -package stack - -import ( - abci "github.com/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" -) - -// Middleware is anything that wraps another handler to enhance functionality. -// -// You can use utilities in handlers to construct them, the interfaces -// are exposed in the top-level package to avoid import loops. -type Middleware interface { - CheckerMiddle - DeliverMiddle - InitStaterMiddle - InitValidaterMiddle - sdk.Named -} - -type CheckerMiddle interface { - CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, next sdk.Checker) (sdk.CheckResult, error) -} - -type CheckerMiddleFunc func(sdk.Context, state.SimpleDB, - sdk.Tx, sdk.Checker) (sdk.CheckResult, error) - -func (c CheckerMiddleFunc) CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, next sdk.Checker) (sdk.CheckResult, error) { - return c(ctx, store, tx, next) -} - -type DeliverMiddle interface { - DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, - next sdk.Deliver) (sdk.DeliverResult, error) -} - -type DeliverMiddleFunc func(sdk.Context, state.SimpleDB, - sdk.Tx, sdk.Deliver) (sdk.DeliverResult, error) - -func (d DeliverMiddleFunc) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, next sdk.Deliver) (sdk.DeliverResult, error) { - return d(ctx, store, tx, next) -} - -type InitStaterMiddle interface { - InitState(l log.Logger, store state.SimpleDB, module, - key, value string, next sdk.InitStater) (string, error) -} - -type InitStaterMiddleFunc func(log.Logger, state.SimpleDB, - string, string, string, sdk.InitStater) (string, error) - -func (c InitStaterMiddleFunc) InitState(l log.Logger, store state.SimpleDB, - module, key, value string, next sdk.InitStater) (string, error) { - return c(l, store, module, key, value, next) -} - -type InitValidaterMiddle interface { - InitValidate(l log.Logger, store state.SimpleDB, vals []*abci.Validator, next sdk.InitValidater) -} - -type InitValidaterMiddleFunc func(log.Logger, state.SimpleDB, - []*abci.Validator, sdk.InitValidater) - -func (c InitValidaterMiddleFunc) InitValidate(l log.Logger, store state.SimpleDB, - vals []*abci.Validator, next sdk.InitValidater) { - c(l, store, vals, next) -} - -// holders -type PassCheck struct{} - -func (_ PassCheck) CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, next sdk.Checker) (sdk.CheckResult, error) { - return next.CheckTx(ctx, store, tx) -} - -type PassDeliver struct{} - -func (_ PassDeliver) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, next sdk.Deliver) (sdk.DeliverResult, error) { - return next.DeliverTx(ctx, store, tx) -} - -type PassInitState struct{} - -func (_ PassInitState) InitState(l log.Logger, store state.SimpleDB, module, - key, value string, next sdk.InitStater) (string, error) { - return next.InitState(l, store, module, key, value) -} - -type PassInitValidate struct{} - -func (_ PassInitValidate) InitValidate(l log.Logger, store state.SimpleDB, - vals []*abci.Validator, next sdk.InitValidater) { - next.InitValidate(l, store, vals) -} - -// Dispatchable is like middleware, except the meaning of "next" is different. -// Whereas in the middleware, it is the next handler that we should pass the same tx into, -// for dispatchers, it is a dispatcher, which it can use to -type Dispatchable interface { - Middleware - AssertDispatcher() -} - -// WrapHandler turns a sdk.Handler into a Dispatchable interface -func WrapHandler(h sdk.Handler) Dispatchable { - return wrapped{h} -} - -type wrapped struct { - h sdk.Handler -} - -var _ Dispatchable = wrapped{} - -func (w wrapped) AssertDispatcher() {} - -func (w wrapped) Name() string { - return w.h.Name() -} - -func (w wrapped) CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, _ sdk.Checker) (sdk.CheckResult, error) { - return w.h.CheckTx(ctx, store, tx) -} - -func (w wrapped) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, _ sdk.Deliver) (sdk.DeliverResult, error) { - return w.h.DeliverTx(ctx, store, tx) -} - -func (w wrapped) InitState(l log.Logger, store state.SimpleDB, - module, key, value string, _ sdk.InitStater) (string, error) { - return w.h.InitState(l, store, module, key, value) -} - -func (w wrapped) InitValidate(l log.Logger, store state.SimpleDB, - vals []*abci.Validator, next sdk.InitValidater) { - w.h.InitValidate(l, store, vals) -} diff --git a/_attic/modules/stack/middleware.go b/_attic/modules/stack/middleware.go deleted file mode 100644 index 4c55f7f0af..0000000000 --- a/_attic/modules/stack/middleware.go +++ /dev/null @@ -1,152 +0,0 @@ -package stack - -import ( - abci "github.com/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" -) - -// middleware lets us wrap a whole stack up into one Handler -// -// heavily inspired by negroni's design -type middleware struct { - middleware Middleware - space string - allowIBC bool - next sdk.Handler -} - -var _ sdk.Handler = &middleware{} - -func (m *middleware) Name() string { - return m.middleware.Name() -} - -func (m *middleware) wrapCtx(ctx sdk.Context) sdk.Context { - if m.allowIBC { - return withIBC(ctx) - } - return withApp(ctx, m.space) -} - -// CheckTx always returns an empty success tx -func (m *middleware) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (sdk.CheckResult, error) { - // make sure we pass in proper context to child - next := secureCheck(m.next, ctx) - // set the permissions for this app - ctx = m.wrapCtx(ctx) - store = stateSpace(store, m.space) - - return m.middleware.CheckTx(ctx, store, tx, next) -} - -// DeliverTx always returns an empty success tx -func (m *middleware) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (res sdk.DeliverResult, err error) { - // make sure we pass in proper context to child - next := secureDeliver(m.next, ctx) - // set the permissions for this app - ctx = m.wrapCtx(ctx) - store = stateSpace(store, m.space) - - return m.middleware.DeliverTx(ctx, store, tx, next) -} - -func (m *middleware) InitState(l log.Logger, store state.SimpleDB, module, key, value string) (string, error) { - // set the namespace for the app - store = stateSpace(store, m.space) - - return m.middleware.InitState(l, store, module, key, value, m.next) -} - -func (m *middleware) InitValidate(l log.Logger, store state.SimpleDB, vals []*abci.Validator) { - // set the namespace for the app - store = stateSpace(store, m.space) - m.middleware.InitValidate(l, store, vals, m.next) -} - -// builder is used to associate info with the middleware, so we can build -// it properly -type builder struct { - middleware Middleware - stateSpace string - allowIBC bool -} - -func prep(m Middleware, ibc bool) builder { - return builder{ - middleware: m, - stateSpace: m.Name(), - allowIBC: ibc, - } -} - -// wrap sets up the middleware with the proper options -func (b builder) wrap(next sdk.Handler) sdk.Handler { - return &middleware{ - middleware: b.middleware, - space: b.stateSpace, - allowIBC: b.allowIBC, - next: next, - } -} - -// Stack is the entire application stack -type Stack struct { - middles []builder - handler sdk.Handler - sdk.Handler // the compiled version, which we expose -} - -var _ sdk.Handler = &Stack{} - -// New prepares a middleware stack, you must `.Use()` a Handler -// before you can execute it. -func New(middlewares ...Middleware) *Stack { - stack := new(Stack) - return stack.Apps(middlewares...) -} - -// Apps adds the following Middlewares as typical application -// middleware to the stack (limit permission to one app) -func (s *Stack) Apps(middlewares ...Middleware) *Stack { - // TODO: some wrapper... - for _, m := range middlewares { - s.middles = append(s.middles, prep(m, false)) - } - return s -} - -// IBC add the following middleware with permission to add cross-chain -// permissions -func (s *Stack) IBC(m Middleware) *Stack { - // TODO: some wrapper... - s.middles = append(s.middles, prep(m, true)) - return s -} - -// Use sets the final handler for the stack and prepares it for use -func (s *Stack) Use(handler sdk.Handler) *Stack { - if handler == nil { - panic("Cannot have a Stack without an end handler") - } - s.handler = handler - s.Handler = build(s.middles, s.handler) - return s -} - -// Dispatch is like Use, but a convenience method to construct a -// dispatcher with a set of modules to route. -func (s *Stack) Dispatch(routes ...Dispatchable) *Stack { - d := NewDispatcher(routes...) - return s.Use(d) -} - -func build(mid []builder, end sdk.Handler) sdk.Handler { - if len(mid) == 0 { - return end - } - next := build(mid[1:], end) - return mid[0].wrap(next) -} diff --git a/_attic/modules/stack/middleware_test.go b/_attic/modules/stack/middleware_test.go deleted file mode 100644 index c09c28f524..0000000000 --- a/_attic/modules/stack/middleware_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package stack - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/tendermint/go-wire/data" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -const ( - nameSigner = "signer" -) - -func TestPermissionSandbox(t *testing.T) { - require := require.New(t) - - // generic args - ctx := NewContext("test-chain", 20, log.NewNopLogger()) - store := state.NewMemKVStore() - raw := NewRawTx([]byte{1, 2, 3, 4}) - rawBytes, err := data.ToWire(raw) - require.Nil(err) - - // test cases to make sure permissioning is solid - grantee := sdk.Actor{App: NameGrant, Address: []byte{1}} - grantee2 := sdk.Actor{App: NameGrant, Address: []byte{2}} - // ibc and grantee are the same, just different chains - ibc := sdk.Actor{ChainID: "other", App: NameGrant, Address: []byte{1}} - ibc2 := sdk.Actor{ChainID: "other", App: nameSigner, Address: []byte{21}} - signer := sdk.Actor{App: nameSigner, Address: []byte{21}} - cases := []struct { - asIBC bool - grant sdk.Actor - require sdk.Actor - expectedRes data.Bytes - expected func(error) bool - }{ - // grant as normal app middleware - {false, grantee, grantee, rawBytes, nil}, - {false, grantee, grantee2, nil, errors.IsUnauthorizedErr}, - {false, grantee2, grantee2, rawBytes, nil}, - {false, ibc, grantee, nil, errors.IsInternalErr}, - {false, grantee, ibc, nil, errors.IsUnauthorizedErr}, - {false, grantee, signer, nil, errors.IsUnauthorizedErr}, - {false, signer, signer, nil, errors.IsInternalErr}, - - // grant as ibc middleware - {true, ibc, ibc, rawBytes, nil}, // ibc can set permissions - {true, ibc2, ibc2, rawBytes, nil}, // for any app - // the must match, both app and chain - {true, ibc, ibc2, nil, errors.IsUnauthorizedErr}, - {true, ibc, grantee, nil, errors.IsUnauthorizedErr}, - // cannot set local apps from ibc middleware - {true, grantee, grantee, nil, errors.IsInternalErr}, - } - - for i, tc := range cases { - app := New(Recovery{}) - if tc.asIBC { - app = app.IBC(GrantMiddleware{Auth: tc.grant}) - } else { - app = app.Apps(GrantMiddleware{Auth: tc.grant}) - } - app = app. - Apps(CheckMiddleware{Required: tc.require}). - Use(EchoHandler{}) - - cres, err := app.CheckTx(ctx, store, raw) - checkPerm(t, i, tc.expectedRes, tc.expected, cres, err) - - dres, err := app.DeliverTx(ctx, store, raw) - checkPerm(t, i, tc.expectedRes, tc.expected, dres, err) - } -} - -func checkPerm(t *testing.T, idx int, data []byte, check func(error) bool, res sdk.Result, err error) { - assert := assert.New(t) - - if len(data) > 0 { - assert.Nil(err, "%d: %+v", idx, err) - assert.EqualValues(data, res.GetData()) - } else { - assert.NotNil(err, "%d", idx) - // check error code! - assert.True(check(err), "%d: %+v", idx, err) - } -} diff --git a/_attic/modules/stack/mock.go b/_attic/modules/stack/mock.go deleted file mode 100644 index 7327875f6a..0000000000 --- a/_attic/modules/stack/mock.go +++ /dev/null @@ -1,90 +0,0 @@ -package stack - -import ( - "math/rand" - - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" -) - -type naiveContext struct { - id nonce - chain string - height uint64 - perms []sdk.Actor - log.Logger -} - -// MockContext returns a simple, non-checking context for test cases. -// -// Always use NewContext() for production code to sandbox malicious code better -func MockContext(chain string, height uint64) sdk.Context { - return naiveContext{ - id: nonce(rand.Int63()), - chain: chain, - height: height, - Logger: log.NewNopLogger(), - } -} - -var _ sdk.Context = naiveContext{} - -func (c naiveContext) ChainID() string { - return c.chain -} - -func (c naiveContext) BlockHeight() uint64 { - return c.height -} - -// WithPermissions will panic if they try to set permission without the proper app -func (c naiveContext) WithPermissions(perms ...sdk.Actor) sdk.Context { - return naiveContext{ - id: c.id, - chain: c.chain, - height: c.height, - perms: append(c.perms, perms...), - Logger: c.Logger, - } -} - -func (c naiveContext) HasPermission(perm sdk.Actor) bool { - for _, p := range c.perms { - if p.Equals(perm) { - return true - } - } - return false -} - -func (c naiveContext) GetPermissions(chain, app string) (res []sdk.Actor) { - for _, p := range c.perms { - if chain == p.ChainID { - if app == "" || app == p.App { - res = append(res, p) - } - } - } - return res -} - -// IsParent ensures that this is derived from the given secureClient -func (c naiveContext) IsParent(other sdk.Context) bool { - nc, ok := other.(naiveContext) - if !ok { - return false - } - return c.id == nc.id -} - -// Reset should clear out all permissions, -// but carry on knowledge that this is a child -func (c naiveContext) Reset() sdk.Context { - return naiveContext{ - id: c.id, - chain: c.chain, - height: c.height, - Logger: c.Logger, - } -} diff --git a/_attic/modules/stack/prefixstore.go b/_attic/modules/stack/prefixstore.go deleted file mode 100644 index 86b58ad336..0000000000 --- a/_attic/modules/stack/prefixstore.go +++ /dev/null @@ -1,134 +0,0 @@ -package stack - -import ( - "bytes" - "errors" - - "github.com/cosmos/cosmos-sdk/state" -) - -type prefixStore struct { - prefix []byte - store state.SimpleDB -} - -var _ state.SimpleDB = prefixStore{} - -func (p prefixStore) Set(key, value []byte) { - key = append(p.prefix, key...) - p.store.Set(key, value) -} - -func (p prefixStore) Get(key []byte) (value []byte) { - key = append(p.prefix, key...) - return p.store.Get(key) -} - -func (p prefixStore) Has(key []byte) bool { - key = append(p.prefix, key...) - return p.store.Has(key) -} - -func (p prefixStore) Remove(key []byte) (value []byte) { - key = append(p.prefix, key...) - return p.store.Remove(key) -} - -func (p prefixStore) List(start, end []byte, limit int) []state.Model { - start = append(p.prefix, start...) - end = append(p.prefix, end...) - res := p.store.List(start, end, limit) - - trim := len(p.prefix) - for i := range res { - res[i].Key = res[i].Key[trim:] - } - return res -} - -func (p prefixStore) First(start, end []byte) state.Model { - start = append(p.prefix, start...) - end = append(p.prefix, end...) - res := p.store.First(start, end) - if len(res.Key) > 0 { - res.Key = res.Key[len(p.prefix):] - } - return res -} - -func (p prefixStore) Last(start, end []byte) state.Model { - start = append(p.prefix, start...) - end = append(p.prefix, end...) - res := p.store.Last(start, end) - if len(res.Key) > 0 { - res.Key = res.Key[len(p.prefix):] - } - return res -} - -func (p prefixStore) Checkpoint() state.SimpleDB { - return prefixStore{ - prefix: p.prefix, - store: p.store.Checkpoint(), - } -} - -func (p prefixStore) Commit(sub state.SimpleDB) error { - ps, ok := sub.(prefixStore) - if !ok { - return errors.New("Must commit prefixStore") - } - if !bytes.Equal(ps.prefix, p.prefix) { - return errors.New("Cannot commit sub-tx with different prefix") - } - - // commit the wrapped data, don't worry about the prefix here - p.store.Commit(ps.store) - return nil -} - -func (p prefixStore) Discard() { - p.store.Discard() -} - -// stateSpace will unwrap any prefixStore and then add the prefix -// -// this can be used by the middleware and dispatcher to isolate one space, -// then unwrap and isolate another space -func stateSpace(store state.SimpleDB, app string) state.SimpleDB { - // unwrap one-level if wrapped - if pstore, ok := store.(prefixStore); ok { - store = pstore.store - } - return PrefixedStore(app, store) -} - -func unwrap(store state.SimpleDB) state.SimpleDB { - // unwrap one-level if wrapped - if pstore, ok := store.(prefixStore); ok { - store = pstore.store - } - return store -} - -// PrefixedStore allows one to create an isolated state-space for a given -// app prefix, but it cannot easily be unwrapped -// -// This is useful for tests or utilities that have access to the global -// state to check individual app spaces. Individual apps should not be able -// to use this to read each other's space -func PrefixedStore(app string, store state.SimpleDB) state.SimpleDB { - prefix := append([]byte(app), byte(0)) - return prefixStore{prefix, store} -} - -// PrefixedKey returns the absolute path to a given key in a particular -// app's state-space -// -// This is useful for tests or utilities that have access to the global -// state to check individual app spaces. Individual apps should not be able -// to use this to read each other's space -func PrefixedKey(app string, key []byte) []byte { - prefix := append([]byte(app), byte(0)) - return append(prefix, key...) -} diff --git a/_attic/modules/stack/recovery.go b/_attic/modules/stack/recovery.go deleted file mode 100644 index bfa04b1898..0000000000 --- a/_attic/modules/stack/recovery.go +++ /dev/null @@ -1,81 +0,0 @@ -package stack - -import ( - "fmt" - - abci "github.com/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/state" -) - -// nolint -const ( - NameRecovery = "rcvr" -) - -// Recovery catches any panics and returns them as errors instead -type Recovery struct{} - -// Name of the module - fulfills Middleware interface -func (Recovery) Name() string { - return NameRecovery -} - -var _ Middleware = Recovery{} - -// CheckTx catches any panic and converts to error - fulfills Middlware interface -func (Recovery) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) { - defer func() { - if r := recover(); r != nil { - err = normalizePanic(r) - } - }() - return next.CheckTx(ctx, store, tx) -} - -// DeliverTx catches any panic and converts to error - fulfills Middlware interface -func (Recovery) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) { - defer func() { - if r := recover(); r != nil { - err = normalizePanic(r) - } - }() - return next.DeliverTx(ctx, store, tx) -} - -// InitState catches any panic and converts to error - fulfills Middlware interface -func (Recovery) InitState(l log.Logger, store state.SimpleDB, module, key, value string, next sdk.InitStater) (log string, err error) { - defer func() { - if r := recover(); r != nil { - err = normalizePanic(r) - } - }() - return next.InitState(l, store, module, key, value) -} - -// InitValidate catches any panic and logs it -// TODO: return an error??? -func (Recovery) InitValidate(l log.Logger, store state.SimpleDB, - vals []*abci.Validator, next sdk.InitValidater) { - - defer func() { - if r := recover(); r != nil { - // TODO: return an error??? - err := normalizePanic(r) - l.With("err", err).Error(err.Error()) - } - }() - next.InitValidate(l, store, vals) -} - -// normalizePanic makes sure we can get a nice TMError (with stack) out of it -func normalizePanic(p interface{}) error { - if err, isErr := p.(error); isErr { - return errors.Wrap(err) - } - msg := fmt.Sprintf("%v", p) - return errors.ErrInternal(msg) -} diff --git a/_attic/modules/stack/recovery_test.go b/_attic/modules/stack/recovery_test.go deleted file mode 100644 index 292410ba46..0000000000 --- a/_attic/modules/stack/recovery_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package stack - -import ( - "errors" - "strconv" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" -) - -func TestRecovery(t *testing.T) { - assert := assert.New(t) - - // generic args here... - ctx := NewContext("test-chain", 20, log.NewNopLogger()) - store := state.NewMemKVStore() - tx := sdk.Tx{} - - cases := []struct { - msg string // what to send to panic - err error // what to send to panic - expected string // expected text in panic - }{ - {"buzz", nil, "buzz"}, - {"", errors.New("some text"), "some text"}, - {"text", errors.New("error"), "error"}, - } - - for idx, tc := range cases { - i := strconv.Itoa(idx) - fail := PanicHandler{Msg: tc.msg, Err: tc.err} - rec := Recovery{} - app := New(rec).Use(fail) - - // make sure check returns error, not a panic crash - _, err := app.CheckTx(ctx, store, tx) - if assert.NotNil(err, i) { - assert.Equal(tc.expected, err.Error(), i) - } - - // make sure deliver returns error, not a panic crash - _, err = app.DeliverTx(ctx, store, tx) - if assert.NotNil(err, i) { - assert.Equal(tc.expected, err.Error(), i) - } - - } -} diff --git a/_attic/modules/stack/state_space_test.go b/_attic/modules/stack/state_space_test.go deleted file mode 100644 index 9b471484c9..0000000000 --- a/_attic/modules/stack/state_space_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package stack - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/tendermint/go-wire/data" - "github.com/tendermint/tmlibs/log" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" -) - -// writerMid is a middleware that writes the given bytes on CheckTx and DeliverTx -type writerMid struct { - name string - key, value []byte - PassInitValidate -} - -var _ Middleware = writerMid{} - -func (w writerMid) Name() string { return w.name } - -func (w writerMid) CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, next sdk.Checker) (sdk.CheckResult, error) { - store.Set(w.key, w.value) - return next.CheckTx(ctx, store, tx) -} - -func (w writerMid) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, next sdk.Deliver) (sdk.DeliverResult, error) { - store.Set(w.key, w.value) - return next.DeliverTx(ctx, store, tx) -} - -func (w writerMid) InitState(l log.Logger, store state.SimpleDB, module, - key, value string, next sdk.InitStater) (string, error) { - store.Set([]byte(key), []byte(value)) - return next.InitState(l, store, module, key, value) -} - -// writerHand is a handler that writes the given bytes on CheckTx and DeliverTx -type writerHand struct { - name string - key, value []byte - sdk.NopInitValidate -} - -var _ sdk.Handler = writerHand{} - -func (w writerHand) Name() string { return w.name } - -func (w writerHand) CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx) (sdk.CheckResult, error) { - store.Set(w.key, w.value) - return sdk.CheckResult{}, nil -} - -func (w writerHand) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx) (sdk.DeliverResult, error) { - store.Set(w.key, w.value) - return sdk.DeliverResult{}, nil -} - -func (w writerHand) InitState(l log.Logger, store state.SimpleDB, module, - key, value string) (string, error) { - store.Set([]byte(key), []byte(value)) - return "Success", nil -} - -func TestStateSpace(t *testing.T) { - cases := []struct { - h sdk.Handler - m []Middleware - expected []data.Bytes - }{ - { - writerHand{name: "foo", key: []byte{1, 2}, value: []byte("bar")}, - []Middleware{ - writerMid{name: "bing", key: []byte{1, 2}, value: []byte("bang")}, - }, - []data.Bytes{ - {'f', 'o', 'o', 0, 1, 2}, - {'b', 'i', 'n', 'g', 0, 1, 2}, - }, - }, - } - - for i, tc := range cases { - // make an app with this setup - d := NewDispatcher(WrapHandler(tc.h)) - app := New(tc.m...).Use(d) - - // register so RawTx is routed to this handler - sdk.TxMapper.RegisterImplementation(RawTx{}, tc.h.Name(), byte(50+i)) - - // run various tests on this setup - spaceCheck(t, i, app, tc.expected) - spaceDeliver(t, i, app, tc.expected) - // spaceOption(t, i, app, keys) - } -} - -func spaceCheck(t *testing.T, i int, app sdk.Handler, keys []data.Bytes) { - assert := assert.New(t) - require := require.New(t) - - ctx := MockContext("chain", 100) - store := state.NewMemKVStore() - - // run a tx - _, err := app.CheckTx(ctx, store, NewRawTx([]byte{77})) - require.Nil(err, "%d: %+v", i, err) - - // verify that the data was writen - for j, k := range keys { - v := store.Get(k) - assert.NotEmpty(v, "%d / %d", i, j) - } -} - -func spaceDeliver(t *testing.T, i int, app sdk.Handler, keys []data.Bytes) { - assert := assert.New(t) - require := require.New(t) - - ctx := MockContext("chain", 100) - store := state.NewMemKVStore() - - // run a tx - _, err := app.DeliverTx(ctx, store, NewRawTx([]byte{1, 56})) - require.Nil(err, "%d: %+v", i, err) - - // verify that the data was writen - for j, k := range keys { - v := store.Get(k) - assert.NotEmpty(v, "%d / %d", i, j) - } -} diff --git a/_attic/modules/store/queue.go b/_attic/modules/store/queue.go deleted file mode 100644 index eacd815ca4..0000000000 --- a/_attic/modules/store/queue.go +++ /dev/null @@ -1,106 +0,0 @@ -package store - -// import ( -// "encoding/binary" - -// sdk "github.com/cosmos/cosmos-sdk" -// ) - -// var ( -// headKey = []byte("h") -// tailKey = []byte("t") -// dataKey = []byte("d") -// ) - -// // QueueHeadKey gives us the key for the height at head of the queue -// func QueueHeadKey() []byte { -// return headKey -// } - -// // QueueTailKey gives us the key for the height at tail of the queue -// func QueueTailKey() []byte { -// return tailKey -// } - -// // QueueItemKey gives us the key to look up one item by sequence -// func QueueItemKey(i uint64) []byte { -// return makeKey(i) -// } - -// // Queue allows us to fill up a range of the db, and grab from either end -// type Queue struct { -// store sdk.KVStore -// head uint64 // if Size() > 0, the first element is here -// tail uint64 // this is the first empty slot to Push() to -// } - -// // NewQueue will load or initialize a queue in this state-space -// // -// // Generally, you will want to stack.PrefixStore() the space first -// func NewQueue(store sdk.KVStore) *Queue { -// q := &Queue{store: store} -// q.head = q.getCount(headKey) -// q.tail = q.getCount(tailKey) -// return q -// } - -// // Tail returns the next slot that Push() will use -// func (q *Queue) Tail() uint64 { -// return q.tail -// } - -// // Size returns how many elements are in the queue -// func (q *Queue) Size() int { -// return int(q.tail - q.head) -// } - -// // Push adds an element to the tail of the queue and returns it's location -// func (q *Queue) Push(value []byte) uint64 { -// key := makeKey(q.tail) -// q.store.Set(key, value) -// q.tail++ -// q.setCount(tailKey, q.tail) -// return q.tail - 1 -// } - -// // Pop gets an element from the end of the queue -// func (q *Queue) Pop() []byte { -// if q.Size() <= 0 { -// return nil -// } -// key := makeKey(q.head) -// value := q.store.Get(key) -// q.head++ -// q.setCount(headKey, q.head) -// return value -// } - -// // Item looks at any element in the queue, without modifying anything -// func (q *Queue) Item(seq uint64) []byte { -// if seq >= q.tail || seq < q.head { -// return nil -// } -// return q.store.Get(makeKey(seq)) -// } - -// func (q *Queue) setCount(key []byte, val uint64) { -// b := make([]byte, 8) -// binary.BigEndian.PutUint64(b, val) -// q.store.Set(key, b) -// } - -// func (q *Queue) getCount(key []byte) (val uint64) { -// b := q.store.Get(key) -// if b != nil { -// val = binary.BigEndian.Uint64(b) -// } -// return val -// } - -// // makeKey returns the key for a data point -// func makeKey(val uint64) []byte { -// b := make([]byte, 8+len(dataKey)) -// copy(b, dataKey) -// binary.BigEndian.PutUint64(b[len(dataKey):], val) -// return b -// } diff --git a/_attic/modules/store/queue_test.go b/_attic/modules/store/queue_test.go deleted file mode 100644 index b0320b32fa..0000000000 --- a/_attic/modules/store/queue_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package store - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestQueue(t *testing.T) { - assert := assert.New(t) - - lots := make([][]byte, 500) - for i := range lots { - lots[i] = []byte{1, 8, 7} - } - - cases := []struct { - pushes [][]byte - pops [][]byte - }{ - // fill it up and empty it all - { - [][]byte{{1, 2, 3}, {44}, {3, 0}}, - [][]byte{{1, 2, 3}, {44}, {3, 0}}, - }, - // don't empty everything - size is 1 at the end - { - [][]byte{{77, 22}, {11, 9}, {121}}, - [][]byte{{77, 22}, {11, 9}}, - }, - // empty too much, just get nil, no negative size - { - [][]byte{{1}, {2}, {4}}, - [][]byte{{1}, {2}, {4}, nil, nil, nil}, - }, - // let's play with lots.... - {lots, append(lots, nil)}, - } - - for i, tc := range cases { - store := NewMemKVStore() - - // initialize a queue and add items - q := NewQueue(store) - for j, in := range tc.pushes { - cnt := q.Push(in) - assert.Equal(uint64(j), cnt, "%d", i) - } - assert.EqualValues(len(tc.pushes), q.Size()) - - // load from disk and pop them - r := NewQueue(store) - for _, out := range tc.pops { - val := r.Pop() - assert.Equal(out, val, "%d", i) - } - - // it's empty in memory and on disk - expected := len(tc.pushes) - len(tc.pops) - if expected < 0 { - expected = 0 - } - assert.EqualValues(expected, r.Size()) - s := NewQueue(store) - assert.EqualValues(expected, s.Size()) - } -} diff --git a/_attic/server/commands/init.go b/_attic/server/commands/init.go deleted file mode 100644 index b5ffebf78e..0000000000 --- a/_attic/server/commands/init.go +++ /dev/null @@ -1,202 +0,0 @@ -package commands - -import ( - "encoding/hex" - "encoding/json" - "fmt" - "io/ioutil" - "os" - "strings" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/types" - cmn "github.com/tendermint/tmlibs/common" -) - -var ( - // InitCmd - node initialization command - InitCmd = GetInitCmd("mycoin", []string{}) - - //nolint - flags - FlagChainID = "chain-id" //TODO group with other flags or remove? is this already a flag here? - FlagDenom = "denom" //TODO group with other flags or remove? is this already a flag here? - FlagOption = "option" - FlagStatic = "static" -) - -// GetInitCmd - get the node initialization command, with a custom genesis account denom -func GetInitCmd(defaultDenom string, options []string) *cobra.Command { - initCmd := &cobra.Command{ - Use: "init [address]", - Short: "Initialize genesis files for a blockchain", - RunE: initCmd, - } - initCmd.Flags().String(FlagChainID, "test_chain_id", "Chain ID") - initCmd.Flags().String(FlagDenom, defaultDenom, "Coin denomination for genesis account") - initCmd.Flags().StringSliceP(FlagOption, "p", options, "Genesis option in the format /