feegiver to santa

add testcode

attach codecov badge
This commit is contained in:
Yun 2019-08-08 12:47:26 +09:00
parent e190a7c08c
commit 7298512113
31 changed files with 462 additions and 253 deletions

24
.circleci/config.yml Normal file
View File

@ -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

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
*.dylib
.DS_Store
.vscode
# Test binary, build with `go test -c`
*.test

17
.vscode/launch.json vendored Normal file
View File

@ -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": []
}
]
}

0
MOTIVATION.md Normal file
View File

View File

@ -1,4 +1,4 @@
BINARY = feegiver
BINARY = santa
GITHUB_USERNAME = terra-project
VERSION = v0.1.0
GOARCH = amd64

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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)
}

View File

@ -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)
},
}

1
coverage.txt Normal file
View File

@ -0,0 +1 @@
mode: set

2
go.mod
View File

@ -1,4 +1,4 @@
module github.com/terra-project/feegiver
module github.com/terra-project/santa
go 1.12

4
go.sum
View File

@ -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=

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +0,0 @@
MANIFEST-000011

View File

@ -1 +0,0 @@
MANIFEST-000009

View File

@ -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

Binary file not shown.

View File

@ -14,7 +14,7 @@
package main
import "github.com/terra-project/feegiver/cmd"
import "github.com/terra-project/santa/cmd"
func main() {
cmd.Execute()

View File

@ -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
}

48
utils/app_test.go Normal file
View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

128
utils/keys_test.go Normal file
View File

@ -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)
}

View File

@ -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
}

110
utils/test_common.go Normal file
View File

@ -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
}

View File

@ -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

24
utils/websocket_test.go Normal file
View File

@ -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]"))
}