diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..65cef85 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,24 @@ +version: 2.1 + +jobs: + build: + docker: + - image: circleci/golang:1.11 + steps: + - checkout + - run: + name: install + command: make install + - run: + name: codecov report + command: | + go test -timeout 3600s ./utils/... -coverprofile=coverage.txt + - run: + name: upload + command: bash <(curl -s https://codecov.io/bash) -f coverage.txt + +workflows: + version: 2 + test-suite: + jobs: + - build \ No newline at end of file diff --git a/.gitignore b/.gitignore index dfce386..53a6eb6 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.dylib .DS_Store +.vscode # Test binary, build with `go test -c` *.test diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..0ec831d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "env": {}, + "args": [] + } + ] +} \ No newline at end of file diff --git a/keys/keys.db/LOCK b/MANDATE.md similarity index 100% rename from keys/keys.db/LOCK rename to MANDATE.md diff --git a/MOTIVATION.md b/MOTIVATION.md new file mode 100644 index 0000000..e69de29 diff --git a/Makefile b/Makefile index 826b4ae..9817b73 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -BINARY = feegiver +BINARY = santa GITHUB_USERNAME = terra-project VERSION = v0.1.0 GOARCH = amd64 diff --git a/README.md b/README.md index a86595b..d2c397a 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,55 @@ -# Build & Install +# Santa Claus + +![banner](docs/terra-core.png) + +Santa Claus subsidizes block rewards for Terra's Columbus mainnet. It is intended to subsidize the security of the network until Terra transaction volume (and attendent staking returns from transaction fees) has had sufficient time to mature. A detailed explanation on the [motivation](./MOTIVATION.md) for starting Santa Claus is explained. + +## Build & Install + +First, check out the rep + ``` -$ git clone https://github.com/terra-project/feegiver.git +$ git clone https://github.com/terra-project/santa.git $ git checkout master ``` -## Install +### Install ``` $ make install ``` -## make config +### Make config ``` -$ feegiver config +$ santa config ``` -## change config +### Change config ``` -$ vim ~/.feegiver/config.yaml +$ vim ~/.santa/config.yaml ``` -## Add Key +### Add / Recover Key ``` -$ feegiver keys add yun -Enter a passphrase to encrypt your key to disk: -Repeat the passphrase: -{"name":"yun","type":"local","address":"terra1a26sc2vqs20hfx239kejhd88v6cl87yfswvk0t","pubkey":"terrapub1addwnpepqwspkmsl724h9azfvgqgs8jkyuyyr3d6eme432afvlvulk3al0mwwnxwlxv","mnemonic":"decade urge pond sustain unit film milk sunny wash accuse profit staff what black problem treat velvet metal leg review math history juice soccer"} +$ feegiver keys add yun ``` + ## Recover Key ``` $ feegiver keys add yun --recover -Enter a passphrase to encrypt your key to disk: -Repeat the passphrase: -> Enter your bip39 mnemonic -theory fat merge under hungry utility toss much trend turkey degree glare bread connect trend grain silk toe pupil crouch innocent pause zero shove - -{"name":"yun","type":"local","address":"terra1gn37dh0jl4zu4fp48d8y4c0hqs9cel83x7st7v","pubkey":"terrapub1addwnpepqfukqlgu8chxwwqns6adgjxvfny6y6tcvqmqkkn2xk6e6kefdaggvh4j7f0","mnemonic":"spatial fantasy weekend romance entire million celery final moon solid route theory way hockey north trigger advice balcony melody fabric alter bullet twice push"} ``` -## Add Key with Old HD Path -``` -$ feegiver keys add yun --recover --old-hd-path -Enter a passphrase to encrypt your key to disk: -Repeat the passphrase: -> Enter your bip39 mnemonic -flash until glimpse chase cradle adjust brick view uncover analyst test pact sponsor example item victory memory attract visual hover pink meadow mosquito torch -{"name":"yun","type":"local","address":"terra1gn37dh0jl4zu4fp48d8y4c0hqs9cel83x7st7v","pubkey":"terrapub1addwnpepqfukqlgu8chxwwqns6adgjxvfny6y6tcvqmqkkn2xk6e6kefdaggvh4j7f0","mnemonic":"spatial fantasy weekend romance entire million celery final moon solid route theory way hockey north trigger advice balcony melody fabric alter bullet twice push"} -``` ## Start Server ``` -$ feegiver start yun +$ santa start yun Enter the passphrase: ``` + + +## Status + + + +## Mechanism + + diff --git a/cmd/config.go b/cmd/config.go index 2a6c845..4fb8ad5 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -6,7 +6,7 @@ import ( homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" - "github.com/terra-project/feegiver/utils" + "github.com/terra-project/santa/utils" yaml "gopkg.in/yaml.v2" ) @@ -21,8 +21,8 @@ var configCmd = &cobra.Command{ return } - g := utils.Generator{ - KeyDir: fmt.Sprintf("%s/.feegiver", home), + g := utils.SantaApp{ + KeyDir: fmt.Sprintf("%s/.santa", home), Node: "http://localhost:26657", TriggerInterval: "5", diff --git a/cmd/keys.go b/cmd/keys.go index 7b7fd18..92c45c4 100644 --- a/cmd/keys.go +++ b/cmd/keys.go @@ -29,7 +29,7 @@ var keysList = &cobra.Command{ Use: "list", Short: "Fetch all keys managed by the server", Run: func(cmd *cobra.Command, args []string) { - out, err := generator.GetKeys() + out, err := app.GetKeys() if err != nil { log.Fatalf("Failed: %s", err.Error()) return @@ -76,7 +76,7 @@ var keysAdd = &cobra.Command{ return } - out, err := generator.AddNewKey(args[0], password, mnemonic, oldHdPath) + out, err := app.AddNewKey(args[0], password, mnemonic, oldHdPath) if err != nil { log.Fatalf("Failed: %s", err.Error()) @@ -92,7 +92,7 @@ var keyShow = &cobra.Command{ Args: cobra.ExactArgs(1), Short: "Fetch details for one key", Run: func(cmd *cobra.Command, args []string) { - out, err := generator.GetKey(args[0], viper.GetString(flagBech)) + out, err := app.GetKey(args[0], viper.GetString(flagBech)) if err != nil { log.Fatalf("Failed: %s", err.Error()) @@ -123,7 +123,7 @@ var keyPut = &cobra.Command{ log.Fatalf("failed reading new password: %s", err.Error()) return } - err = generator.UpdateKey(args[0], password, newPassword) + err = app.UpdateKey(args[0], password, newPassword) if err != nil { log.Fatalf("Failed: %s", err.Error()) return @@ -145,7 +145,7 @@ var keyDelete = &cobra.Command{ return } - err = generator.DeleteKey(args[0], password) + err = app.DeleteKey(args[0], password) if err != nil { log.Fatalf("Failed: %s", err.Error()) return diff --git a/cmd/root.go b/cmd/root.go index f192639..b5e7df6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,7 +7,7 @@ import ( homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" - "github.com/terra-project/feegiver/utils" + "github.com/terra-project/santa/utils" yaml "gopkg.in/yaml.v2" ) @@ -16,7 +16,7 @@ var ( cfgFile string // The actual app config - generator utils.Generator + app utils.SantaApp // Version for the application. Set via ldflags Version = "undefined" @@ -30,7 +30,7 @@ var ( // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "feegiver", + Use: "santa", Short: "An fee giver server for terra", } @@ -45,12 +45,12 @@ func Execute() { func init() { cobra.OnInitialize(initConfig) - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.feegiver/config.yaml)") + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.santa/config.yaml)") rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } func initConfig() { - generator = utils.Generator{ + app = utils.SantaApp{ Version: Version, Commit: Commit, Branch: Branch, @@ -72,13 +72,16 @@ func initConfig() { os.Exit(1) } - cfgFile = fmt.Sprintf("%s/.feegiver/config.yaml", home) - bz, err = ioutil.ReadFile(cfgFile) - if err != nil { - fmt.Println(err) - os.Exit(1) + cfgFile = fmt.Sprintf("%s/.santa/config.yaml", home) + if _, err := os.Stat(cfgFile); err == nil { + bz, err = ioutil.ReadFile(cfgFile) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + yaml.Unmarshal(bz, &app) } } - yaml.Unmarshal(bz, &generator) } diff --git a/cmd/start.go b/cmd/start.go index dfb02f1..44ff7f6 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -24,24 +24,22 @@ var startCmd = &cobra.Command{ return } - generator.KeyName = args[0] - generator.KeyPassword = password + app.KeyName = args[0] + app.KeyPassword = password - kb, err := keys.NewKeyBaseFromDir(generator.KeyDir) + kb, err := keys.NewKeyBaseFromDir(app.KeyDir) if err != nil { log.Fatalf("failed to open keybase: %s", err.Error()) return } - _, err = kb.Get(generator.KeyName) + _, err = kb.Get(app.KeyName) if err != nil { log.Fatalf("failed to get account: %s", err.Error()) return } - generator.ListenNewBLock() - // err := generator.SendTx(10000, "vodka") - // fmt.Println(err) + app.ListenNewBLock(false) }, } diff --git a/coverage.txt b/coverage.txt new file mode 100644 index 0000000..5f02b11 --- /dev/null +++ b/coverage.txt @@ -0,0 +1 @@ +mode: set diff --git a/go.mod b/go.mod index 8417f04..a9adfb9 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/terra-project/feegiver +module github.com/terra-project/santa go 1.12 diff --git a/go.sum b/go.sum index 607b145..6a4b09b 100644 --- a/go.sum +++ b/go.sum @@ -103,6 +103,7 @@ github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bz github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -128,8 +129,10 @@ github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM52 github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -318,6 +321,7 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/keys/keys.db/000004.ldb b/keys/keys.db/000004.ldb deleted file mode 100644 index c4be06b..0000000 Binary files a/keys/keys.db/000004.ldb and /dev/null differ diff --git a/keys/keys.db/000007.ldb b/keys/keys.db/000007.ldb deleted file mode 100644 index 0e45803..0000000 Binary files a/keys/keys.db/000007.ldb and /dev/null differ diff --git a/keys/keys.db/000010.log b/keys/keys.db/000010.log deleted file mode 100644 index e08bd0d..0000000 Binary files a/keys/keys.db/000010.log and /dev/null differ diff --git a/keys/keys.db/CURRENT b/keys/keys.db/CURRENT deleted file mode 100644 index 5b54010..0000000 --- a/keys/keys.db/CURRENT +++ /dev/null @@ -1 +0,0 @@ -MANIFEST-000011 diff --git a/keys/keys.db/CURRENT.bak b/keys/keys.db/CURRENT.bak deleted file mode 100644 index 6ba31a3..0000000 --- a/keys/keys.db/CURRENT.bak +++ /dev/null @@ -1 +0,0 @@ -MANIFEST-000009 diff --git a/keys/keys.db/LOG b/keys/keys.db/LOG deleted file mode 100644 index ccfdf87..0000000 --- a/keys/keys.db/LOG +++ /dev/null @@ -1,54 +0,0 @@ -=============== Aug 7, 2019 (KST) =============== -16:56:58.211679 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed -16:56:58.225722 db@open opening -16:56:58.226696 version@stat F·[] S·0B[] Sc·[] -16:56:58.232353 db@janitor F·2 G·0 -16:56:58.233004 db@open done T·7.237371ms -16:56:58.233111 db@close closing -16:56:58.233208 db@close done T·94.717µs -=============== Aug 7, 2019 (KST) =============== -16:56:58.233404 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed -16:56:58.233637 version@stat F·[] S·0B[] Sc·[] -16:56:58.233664 db@open opening -16:56:58.233756 journal@recovery F·1 -16:56:58.233897 journal@recovery recovering @1 -16:56:58.234452 version@stat F·[] S·0B[] Sc·[] -16:56:58.252330 db@janitor F·2 G·0 -16:56:58.252363 db@open done T·18.674729ms -16:56:58.498076 db@close closing -16:56:58.498173 db@close done T·92.831µs -=============== Aug 7, 2019 (KST) =============== -16:57:24.410988 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed -16:57:24.411185 version@stat F·[] S·0B[] Sc·[] -16:57:24.411205 db@open opening -16:57:24.411267 journal@recovery F·1 -16:57:24.411556 journal@recovery recovering @2 -16:57:24.420661 memdb@flush created L0@4 N·2 S·484B "ter..ess,v2":"yun.info,v1" -16:57:24.421713 version@stat F·[1] S·484B[484B] Sc·[0.25] -16:57:24.441941 db@janitor F·3 G·0 -16:57:24.447859 db@open done T·36.631766ms -16:57:24.690607 db@close closing -16:57:24.691097 db@close done T·486.088µs -=============== Aug 7, 2019 (KST) =============== -16:57:32.561788 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed -16:57:32.562041 version@stat F·[1] S·484B[484B] Sc·[0.25] -16:57:32.562066 db@open opening -16:57:32.562137 journal@recovery F·1 -16:57:32.562405 journal@recovery recovering @5 -16:57:32.569663 memdb@flush created L0@7 N·2 S·184B "ter..ess,d4":"yun.info,d5" -16:57:32.570358 version@stat F·[2] S·668B[668B] Sc·[0.50] -16:57:32.595987 db@janitor F·4 G·0 -16:57:32.596026 db@open done T·33.942315ms -16:57:32.596181 db@close closing -16:57:32.596288 db@close done T·102.884µs -=============== Aug 7, 2019 (KST) =============== -16:57:32.596436 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed -16:57:32.596622 version@stat F·[2] S·668B[668B] Sc·[0.50] -16:57:32.596642 db@open opening -16:57:32.596721 journal@recovery F·1 -16:57:32.596980 journal@recovery recovering @8 -16:57:32.599133 version@stat F·[2] S·668B[668B] Sc·[0.50] -16:57:32.617657 db@janitor F·4 G·0 -16:57:32.617706 db@open done T·21.049788ms -16:57:32.863658 db@close closing -16:57:32.864305 db@close done T·642.212µs diff --git a/keys/keys.db/MANIFEST-000011 b/keys/keys.db/MANIFEST-000011 deleted file mode 100644 index d6b3013..0000000 Binary files a/keys/keys.db/MANIFEST-000011 and /dev/null differ diff --git a/main.go b/main.go index 7878cac..375aedd 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,7 @@ package main -import "github.com/terra-project/feegiver/cmd" +import "github.com/terra-project/santa/cmd" func main() { cmd.Execute() diff --git a/utils/generator.go b/utils/app.go similarity index 75% rename from utils/generator.go rename to utils/app.go index 474710e..1b85929 100644 --- a/utils/generator.go +++ b/utils/app.go @@ -11,13 +11,13 @@ import ( txbldr "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/terra-project/core/app" + core "github.com/terra-project/core/app" ) var cdc *codec.Codec func init() { - cdc = app.MakeCodec() + cdc = core.MakeCodec() config := sdk.GetConfig() config.SetCoinType(330) @@ -28,8 +28,8 @@ func init() { config.Seal() } -// Generator tx generator -type Generator struct { +// SantaApp tx app +type SantaApp struct { KeyDir string `json:"key_dir" yaml:"key_dir"` Node string `json:"node" yaml:"node"` @@ -44,25 +44,24 @@ type Generator struct { Branch string `yaml:"branch,omitempty"` } -// BankSend handles the /tx/bank/send route -func (g Generator) SendTx(height int64, chainID string) (err error) { - - kb, err := keys.NewKeyBaseFromDir(g.KeyDir) +// Send BankSend Tx +func (app SantaApp) SendTx(chainID string) (txHash string, err error) { + kb, err := keys.NewKeyBaseFromDir(app.KeyDir) if err != nil { return } - info, err := kb.Get(g.KeyName) + info, err := kb.Get(app.KeyName) if err != nil { return } - acc, err := g.QueryAccount(cdc, info.GetAddress()) + acc, err := app.QueryAccount(cdc, info.GetAddress()) if err != nil { return } - targetFeeCoin, err := sdk.ParseCoin(g.FeeAmount) + targetFeeCoin, err := sdk.ParseCoin(app.FeeAmount) if err != nil { return } @@ -87,16 +86,15 @@ func (g Generator) SendTx(height int64, chainID string) (err error) { "", ) - signedTx, err := g.signTx(stdTx, acc, chainID) + signedTx, err := app.signTx(stdTx, acc, chainID) - txHash, err := g.BroadcastTx(signedTx) - fmt.Println(txHash) - return nil + txHash, err = app.BroadcastTx(signedTx) + return } -func (g Generator) signTx(stdTx auth.StdTx, acc auth.Account, chainID string) (signedTx auth.StdTx, err error) { +func (app SantaApp) signTx(stdTx auth.StdTx, acc auth.Account, chainID string) (signedTx auth.StdTx, err error) { - kb, err := keys.NewKeyBaseFromDir(g.KeyDir) + kb, err := keys.NewKeyBaseFromDir(app.KeyDir) if err != nil { return } @@ -113,7 +111,7 @@ func (g Generator) signTx(stdTx auth.StdTx, acc auth.Account, chainID string) (s }, } - sigBytes, pubkey, err := kb.Sign(g.KeyName, g.KeyPassword, sdk.MustSortJSON(cdc.MustMarshalJSON(stdSign))) + sigBytes, pubkey, err := kb.Sign(app.KeyName, app.KeyPassword, sdk.MustSortJSON(cdc.MustMarshalJSON(stdSign))) if err != nil { return } diff --git a/utils/app_test.go b/utils/app_test.go new file mode 100644 index 0000000..c701f7b --- /dev/null +++ b/utils/app_test.go @@ -0,0 +1,48 @@ +package utils + +import ( + "os" + "testing" + "github.com/stretchr/testify/require" +) + +func TestBuildSendTx(t *testing.T) { + //---------------------------------------- + app := setupWithNotExistsAccount(t) + defer os.RemoveAll(app.KeyDir) + + // not exists + _, err := app.SendTx(testChainID) + require.Error(t, err) + + //---------------------------------------- + app2 := setup(t) + defer os.RemoveAll(app2.KeyDir) + + // not exist key + _, err = app2.SendTx(testChainID) + require.Error(t, err) + + //---------------------------------------- + app3 := setupWithNoBalanceAccount(t) + defer os.RemoveAll(app3.KeyDir) + + // not enough balance to pay fee + _, err = app3.SendTx(testChainID) + require.Error(t, err) + + //---------------------------------------- + app4 := setupWithPlentyBalanceAccount(t) + defer os.RemoveAll(app4.KeyDir) + + // invalid fee amount + app4.FeeAmount = "1" + _, err = app4.SendTx(testChainID) + require.Error(t, err) + + //---------------------------------------- + app5 := setupWithPlentyBalanceAccount(t) + defer os.RemoveAll(app5.KeyDir) + _, err = app5.SendTx(testChainID) + require.NoError(t, err) +} \ No newline at end of file diff --git a/utils/errors.go b/utils/errors.go deleted file mode 100644 index bef0c4c..0000000 --- a/utils/errors.go +++ /dev/null @@ -1,19 +0,0 @@ -package utils - -import "encoding/json" - -type restError struct { - Error string `json:"error"` -} - -func newError(err error) restError { - return restError{err.Error()} -} - -func (e restError) marshal() []byte { - out, err := json.Marshal(e) - if err != nil { - panic(err) - } - return out -} diff --git a/utils/keys.go b/utils/keys.go index ea05652..8142603 100644 --- a/utils/keys.go +++ b/utils/keys.go @@ -11,9 +11,9 @@ import ( ) // GetKeys returns key list -func (g Generator) GetKeys() (out []byte, err error) { +func (app SantaApp) GetKeys() (out []byte, err error) { - kb, err := keys.NewKeyBaseFromDir(g.KeyDir) + kb, err := keys.NewKeyBaseFromDir(app.KeyDir) if err != nil { return nil, err } @@ -36,8 +36,8 @@ func (g Generator) GetKeys() (out []byte, err error) { } // AddNewKey appends new key -func (g Generator) AddNewKey(name, password, mnemonic string, oldHdPath bool) (out []byte, err error) { - kb, err := keys.NewKeyBaseFromDir(g.KeyDir) +func (app SantaApp) AddNewKey(name, password, mnemonic string, oldHdPath bool) (out []byte, err error) { + kb, err := keys.NewKeyBaseFromDir(app.KeyDir) if err != nil { return } @@ -93,8 +93,8 @@ func (g Generator) AddNewKey(name, password, mnemonic string, oldHdPath bool) (o } // GetKey is the handler for the GET /keys/{name} -func (g Generator) GetKey(name, bechPrefix string) (out []byte, err error) { - kb, err := keys.NewKeyBaseFromDir(g.KeyDir) +func (app SantaApp) GetKey(name, bechPrefix string) (out []byte, err error) { + kb, err := keys.NewKeyBaseFromDir(app.KeyDir) if err != nil { return } @@ -142,9 +142,13 @@ func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) { } // UpdateKey update key password -func (g Generator) UpdateKey(name, newPassword, oldPassword string) (err error) { +func (app SantaApp) UpdateKey(name, oldPassword, newPassword string) (err error) { + if name == "" || oldPassword == "" || newPassword == "" { + err = fmt.Errorf("must include name, oldPassword, and newPassword with request") + return + } - kb, err := keys.NewKeyBaseFromDir(g.KeyDir) + kb, err := keys.NewKeyBaseFromDir(app.KeyDir) if err != nil { return } @@ -158,8 +162,8 @@ func (g Generator) UpdateKey(name, newPassword, oldPassword string) (err error) } // DeleteKey is the handler for the DELETE /keys/{name} -func (g Generator) DeleteKey(name, password string) (err error) { - kb, err := keys.NewKeyBaseFromDir(g.KeyDir) +func (app SantaApp) DeleteKey(name, password string) (err error) { + kb, err := keys.NewKeyBaseFromDir(app.KeyDir) if err != nil { return } diff --git a/utils/keys_test.go b/utils/keys_test.go new file mode 100644 index 0000000..fde39d2 --- /dev/null +++ b/utils/keys_test.go @@ -0,0 +1,128 @@ +package utils + +import ( + "os" + "encoding/json" + + "testing" + "github.com/stretchr/testify/require" + + ckeys "github.com/cosmos/cosmos-sdk/crypto/keys" +) + +func TestAddKey(t *testing.T) { + app := setup(t) + defer os.RemoveAll(app.KeyDir) + + out, err := app.GetKeys() + require.NoError(t, err) + require.Equal(t, 0, len(out)) + + // invalid name + _, err = app.AddNewKey(testInvalidName, testPassword, testMnemonic, false) + require.Error(t, err) + + // invalid password + _, err = app.AddNewKey(testName, testInvalidPassword, testMnemonic, false) + require.Error(t, err) + + // invalid mnemonic + _, err = app.AddNewKey(testName, testPassword, testInvalidMnemonic, false) + require.Error(t, err) + + // valid add + out, err = app.AddNewKey(testName, testPassword, testMnemonic, false) + require.NoError(t, err) + + var output ckeys.KeyOutput + err = json.Unmarshal(out, &output) + require.NoError(t, err) + + require.Equal(t, testName, output.Name) + require.Equal(t, "terra1ch5ezwqftx8z8969l30j634wzs8772xfp5wur4", output.Address) + require.Equal(t, "terrapub1addwnpepqvgqm0lpmjn4dga903dugvmw8qtzcush2agl8lx3xz2mxcm8vvwf2adw7e3", output.PubKey) + require.Equal(t, testMnemonic, output.Mnemonic) +} + +func TestGetKey(t *testing.T) { + app := setup(t) + defer os.RemoveAll(app.KeyDir) + + out, err := app.GetKey(testName, "acc") + require.Error(t, err) + require.Equal(t, 0, len(out)) + + out, err = app.AddNewKey(testName, testPassword, testMnemonic, false) + require.NoError(t, err) + + _, err = app.GetKey(testName, "acc") + require.NoError(t, err) +} + +func TestDeleteKey(t *testing.T) { + app := setup(t) + defer os.RemoveAll(app.KeyDir) + + out, err := app.AddNewKey(testName, testPassword, testMnemonic, false) + require.NoError(t, err) + + out, err = app.GetKeys() + require.NoError(t, err) + + var outputs []ckeys.KeyOutput + err = json.Unmarshal(out, &outputs) + require.Equal(t, 1, len(outputs)) + + // not exist name + err = app.DeleteKey(testInvalidName, testPassword) + require.Error(t, err) + + // invalid password + err = app.DeleteKey(testName, testInvalidPassword) + require.Error(t, err) + + // valid + err = app.DeleteKey(testName, testPassword) + require.NoError(t, err) + + out, err = app.GetKeys() + require.NoError(t, err) + + var outputs2 []ckeys.KeyOutput + err = json.Unmarshal(out, &outputs2) + require.Equal(t, 0, len(outputs2)) +} + +func TestUpdateKey(t *testing.T) { + app := setup(t) + defer os.RemoveAll(app.KeyDir) + + out, err := app.AddNewKey(testName, testPassword, testMnemonic, false) + require.NoError(t, err) + + out, err = app.GetKeys() + require.NoError(t, err) + + var outputs []ckeys.KeyOutput + err = json.Unmarshal(out, &outputs) + + // not exist name + err = app.UpdateKey(testInvalidName, testPassword, testUpdatePassword) + require.Error(t, err) + + // invalid password + err = app.UpdateKey(testName, testInvalidPassword, testUpdatePassword) + require.Error(t, err) + + // valid + err = app.UpdateKey(testName, testPassword, testUpdatePassword) + require.NoError(t, err) + + // with old password + err = app.DeleteKey(testName, testPassword) + require.Error(t, err) + + // valid + err = app.DeleteKey(testName, testUpdatePassword) + require.NoError(t, err) +} diff --git a/utils/rpc.go b/utils/rpc.go index 0d4846d..2133e30 100644 --- a/utils/rpc.go +++ b/utils/rpc.go @@ -2,50 +2,22 @@ package utils import ( "errors" - "fmt" "github.com/cosmos/cosmos-sdk/codec" - cmn "github.com/tendermint/tendermint/libs/common" rpcclient "github.com/tendermint/tendermint/rpc/client" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - - "github.com/terra-project/core/x/treasury" ) -// SimulateGas simulates gas for a transaction -func (g Generator) SimulateGas(cdc *codec.Codec, txbytes []byte) (res uint64, err error) { - result, err := rpcclient.NewHTTP(g.Node, "/websocket").ABCIQueryWithOptions( - "/app/simulate", - cmn.HexBytes(txbytes), - rpcclient.ABCIQueryOptions{}, - ) - - if err != nil { - return - } - - if !result.Response.IsOK() { - return 0, errors.New(result.Response.Log) - } - - var simulationResult sdk.Result - if err := cdc.UnmarshalBinaryLengthPrefixed(result.Response.Value, &simulationResult); err != nil { - return 0, err - } - - return simulationResult.GasUsed, nil -} - // QueryAccount query account info -func (g Generator) QueryAccount(cdc *codec.Codec, accAddr sdk.AccAddress) (acc auth.Account, err error) { +func (app SantaApp) QueryAccount(cdc *codec.Codec, accAddr sdk.AccAddress) (acc auth.Account, err error) { bz, err := cdc.MarshalJSON(auth.NewQueryAccountParams(accAddr)) if err != nil { return } - result, err := rpcclient.NewHTTP(g.Node, "/websocket").ABCIQueryWithOptions( + result, err := rpcclient.NewHTTP(app.Node, "/websocket").ABCIQueryWithOptions( "custom/acc/account", bz, rpcclient.ABCIQueryOptions{}, @@ -67,66 +39,14 @@ func (g Generator) QueryAccount(cdc *codec.Codec, accAddr sdk.AccAddress) (acc a return } -// QueryTaxRate query tax rate -func (g Generator) QueryTaxRate(cdc *codec.Codec, epoch int64) (taxRate sdk.Dec, err error) { - result, err := rpcclient.NewHTTP(g.Node, "/websocket").ABCIQueryWithOptions( - fmt.Sprintf("custom/treasury/tax-rate/%d", epoch), - []byte{}, - rpcclient.ABCIQueryOptions{}, - ) - - if err != nil { - return - } - - if !result.Response.IsOK() { - err = errors.New(result.Response.Log) - return - } - - var resp treasury.QueryTaxRateResponse - if err = cdc.UnmarshalJSON(result.Response.Value, &resp); err != nil { - return - } - - taxRate = resp.TaxRate - return -} - -// QueryTaxCap query tax cap -func (g Generator) QueryTaxCap(cdc *codec.Codec, denom string) (taxCap sdk.Int, err error) { - result, err := rpcclient.NewHTTP(g.Node, "/websocket").ABCIQueryWithOptions( - fmt.Sprintf("custom/treasury/tax-cap/%s", denom), - []byte{}, - rpcclient.ABCIQueryOptions{}, - ) - - if err != nil { - return - } - - if !result.Response.IsOK() { - err = errors.New(result.Response.Log) - return - } - - var resp treasury.QueryTaxCapResponse - if err = cdc.UnmarshalJSON(result.Response.Value, &resp); err != nil { - return - } - - taxCap = resp.TaxCap - return -} - // BroadcastTx broadcast tx -func (g Generator) BroadcastTx(tx auth.StdTx) (txHash string, err error) { +func (app SantaApp) BroadcastTx(tx auth.StdTx) (txHash string, err error) { txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) if err != nil { return } - result, err := rpcclient.NewHTTP(g.Node, "/websocket").BroadcastTxSync(txBytes) + result, err := rpcclient.NewHTTP(app.Node, "/websocket").BroadcastTxSync(txBytes) if err != nil { return } diff --git a/utils/test_common.go b/utils/test_common.go new file mode 100644 index 0000000..13535e0 --- /dev/null +++ b/utils/test_common.go @@ -0,0 +1,110 @@ +package utils + + +import ( + "io/ioutil" + + "testing" + "github.com/stretchr/testify/require" + +) +const ( + testChainID = "vodka" + + testInvalidName = "" + testName = "keyname" + testName2 = "keyname2" + testName3= "keyname3" + + testInvalidPassword = "" + testPassword = "12345678" + testPassword2 = "12345678910" + testPassword3 = "1234567891011" + testUpdatePassword = "123456789" + + testInvalidMnemonic = "crop" + testMnemonic = "crop vivid nature drastic duck submit night innocent inflict when know divorce fan concert damp stand depart gauge area vanish legend clarify warfare discover" + + // no balance in vodka network + testMnemonic2 = "baby reduce notice dice eight remember room avoid gravity patient cement unhappy consider exit beyond uncle oblige lamp fault open save rifle airport craft" + + // not exists on vodka network + testMnemonic3 = "rally clarify museum turn slender one fruit october wedding wrong web spike slight domain double connect want flock sport powder gloom yard emerge album" + + + testNode = "http://15.164.0.235:26657" // vodka network + testFeeAmount = "1uluna" +) + + +func setup(t *testing.T) SantaApp { + dir, err := ioutil.TempDir("/tmp", ".santa") + require.NoError(t, err) + + app := SantaApp{ + KeyDir: dir, + } + + return app +} + +func setupWithPlentyBalanceAccount(t *testing.T) SantaApp { + dir, err := ioutil.TempDir("/tmp", ".santa") + require.NoError(t, err) + + app := SantaApp{ + KeyDir: dir, + Node: testNode, // test vodka net + + KeyName: testName, + KeyPassword: testPassword, + + FeeAmount: testFeeAmount, + } + + _, err = app.AddNewKey(testName, testPassword, testMnemonic, false) + require.NoError(t, err) + + return app +} + +func setupWithNoBalanceAccount(t *testing.T) SantaApp { + dir, err := ioutil.TempDir("/tmp", ".santa") + require.NoError(t, err) + + app := SantaApp{ + KeyDir: dir, + Node: testNode, // test vodka net + + KeyName: testName2, + KeyPassword: testPassword2, + + FeeAmount: testFeeAmount, + } + + _, err = app.AddNewKey(testName2, testPassword2, testMnemonic2, false) + require.NoError(t, err) + + return app +} + + +func setupWithNotExistsAccount(t *testing.T) SantaApp { + dir, err := ioutil.TempDir("/tmp", ".santa") + require.NoError(t, err) + + app := SantaApp{ + KeyDir: dir, + Node: testNode, // test vodka net + + KeyName: testName3, + KeyPassword: testPassword3, + + FeeAmount: testFeeAmount, + } + + _, err = app.AddNewKey(testName3, testPassword3, testMnemonic3, false) + require.NoError(t, err) + + return app +} diff --git a/utils/websocket.go b/utils/websocket.go index d1d3341..c4e265e 100644 --- a/utils/websocket.go +++ b/utils/websocket.go @@ -21,21 +21,20 @@ func init() { } // ListenNewBlock listen new block and trigger sendtx -func (g Generator) ListenNewBLock() { - - triggerInterval, err := strconv.ParseInt(g.TriggerInterval, 10, 64) +func (app SantaApp) ListenNewBLock(isTest bool) { + triggerInterval, err := strconv.ParseInt(app.TriggerInterval, 10, 64) if err != nil { log.Fatal("Trigger interval should be number", err) } var scheme string var host string - if strings.HasPrefix(g.Node, "https") { + if strings.HasPrefix(app.Node, "https") { scheme = "wss" - host = strings.TrimPrefix(g.Node, "https://") + host = strings.TrimPrefix(app.Node, "https://") } else { scheme = "ws" - host = strings.TrimPrefix(g.Node, "http://") + host = strings.TrimPrefix(app.Node, "http://") } u := url.URL{Scheme: scheme, Host: host, Path: "/websocket"} @@ -76,14 +75,18 @@ func (g Generator) ListenNewBLock() { } if blockEvent.Block.Height%triggerInterval == 0 { - err := g.SendTx(blockEvent.Block.Height, blockEvent.Block.ChainID) + txHash, err := app.SendTx(blockEvent.Block.ChainID) if err != nil { - log.Fatal("Failed to send tx", err) + log.Fatal("[Fail] to send tx", err) } + + log.Printf("[Success] Height: %d,\tTxHash: %s\n", blockEvent.Block.Height, txHash) } + if isTest { + break + } } - } // no-lint diff --git a/utils/websocket_test.go b/utils/websocket_test.go new file mode 100644 index 0000000..1705074 --- /dev/null +++ b/utils/websocket_test.go @@ -0,0 +1,24 @@ +package utils + +import ( + "os" + "bytes" + "log" + "strings" + + "testing" + "github.com/stretchr/testify/require" +) +func TestWebsocketListen(t *testing.T) { + app := setupWithPlentyBalanceAccount(t) + + var logBuf bytes.Buffer + log.SetOutput(&logBuf) + defer log.SetOutput(os.Stderr) + + app.TriggerInterval = "1" + app.ListenNewBLock(true) + + result := logBuf.String() + require.True(t, strings.Contains(result, "[Success]")) +} \ No newline at end of file