diff --git a/CHANGELOG.md b/CHANGELOG.md index 9971aac9..a4dbf1ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ``` [\#598](https://github.com/Kava-Labs/kava/pulls/598) CLI and REST queries for committee proposals (ie `kvcli q committee proposal 1`) now query the historical state to return the proposal object before it was deleted from state +[\#625](https://github.com/Kava-Labs/kava/pull/625) The Cosmos SDK has been updated to v0.39.1. This brings with it several breaking changes detailed [in their changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.39.1/CHANGELOG.md). Notably account JSON serialization has been modified to use amino instead of the Go stdlib, so numbers are serialized to strings, and public keys are no longer encoded into bech32 strings. Also pruning config has changed: `pruning=everything` and `pruning=nothing` still work but there are different flags for custom pruning configuration. ## [v0.8.1](https://github.com/Kava-Labs/kava/releases/tag/v0.8.1) kava-3 Patch Release diff --git a/Makefile b/Makefile index 46a7f6a4..1dec3dd8 100644 --- a/Makefile +++ b/Makefile @@ -162,7 +162,7 @@ test: @go test $$(go list ./... | grep -v 'migrate\|contrib') test-rest: - rest_test/./run_all_tests_from_make.sh + rest_test/run_all_tests_from_make.sh # Run cli integration tests # `-p 4` to use 4 cores, `-tags cli_test` to tell go not to ignore the cli package diff --git a/cli_test/cli_test.go b/cli_test/cli_test.go index e60723ab..0f49a216 100644 --- a/cli_test/cli_test.go +++ b/cli_test/cli_test.go @@ -302,6 +302,40 @@ func TestKvCLISend(t *testing.T) { f.Cleanup() } +func TestKvCLISendMultiplePerBlock(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + // start kvd server + proc := f.GDStart() + defer proc.Stop(false) + + // Save key addresses for later use + fooAddr := f.KeyAddress(keyFoo) + barAddr := f.KeyAddress(keyBar) + + fooAcc := f.QueryAccount(fooAddr) + startTokens := fooAcc.GetCoins().AmountOf(fooDenom) + + sendTokens := sdk.TokensFromConsensusPower(1) + + numTxsToSend := 30 + for i := 0; i < numTxsToSend; i++ { + seq := fooAcc.GetSequence() + uint64(i) + f.TxSend(keyFoo, barAddr, sdk.NewCoin(fooDenom, sendTokens), "-y", fmt.Sprintf("--sequence=%d", seq), "--broadcast-mode=sync") + } + tests.WaitForNextNBlocksTM(1, f.Port) + + // Ensure account balances match expected + totalSent := sendTokens.MulRaw(int64(numTxsToSend)) + barAcc := f.QueryAccount(barAddr) + require.Equal(t, totalSent, barAcc.GetCoins().AmountOf(fooDenom)) + fooAcc = f.QueryAccount(fooAddr) + require.Equal(t, startTokens.Sub(totalSent), fooAcc.GetCoins().AmountOf(fooDenom)) + + f.Cleanup() +} + func TestKvCLIGasAuto(t *testing.T) { // https://github.com/cosmos/cosmos-sdk/pull/5179 t.Skip() diff --git a/cmd/kvd/main.go b/cmd/kvd/main.go index 3146225d..2b1337d9 100644 --- a/cmd/kvd/main.go +++ b/cmd/kvd/main.go @@ -2,7 +2,6 @@ package main import ( "encoding/json" - "fmt" "io" "github.com/spf13/cobra" @@ -46,7 +45,7 @@ func main() { rootCmd := &cobra.Command{ Use: "kvd", Short: "Kava Daemon (server)", - PersistentPreRunE: persistentPreRunEFn(ctx), + PersistentPreRunE: server.PersistentPreRunEFn(ctx), } rootCmd.AddCommand( @@ -91,9 +90,14 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application skipUpgradeHeights[int64(h)] = true } + pruningOpts, err := server.GetPruningOptionsFromFlags() + if err != nil { + panic(err) + } + return app.NewApp( logger, db, traceStore, true, skipUpgradeHeights, invCheckPeriod, - baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))), + baseapp.SetPruning(pruningOpts), baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)), baseapp.SetHaltHeight(viper.GetUint64(server.FlagHaltHeight)), baseapp.SetHaltTime(viper.GetUint64(server.FlagHaltTime)), @@ -116,27 +120,3 @@ func exportAppStateAndTMValidators( tempApp := app.NewApp(logger, db, traceStore, true, map[int64]bool{}, uint(1)) return tempApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) } - -// persistentPreRunEFn wraps the sdk function server.PersistentPreRunEFn to error on invaid pruning config. -func persistentPreRunEFn(ctx *server.Context) func(*cobra.Command, []string) error { - - originalFunc := server.PersistentPreRunEFn(ctx) - - return func(cmd *cobra.Command, args []string) error { - - if err := originalFunc(cmd, args); err != nil { - return err - } - - // check pruning config for `kvd start` - if cmd.Name() == "start" { - if viper.GetString("pruning") == store.PruningStrategySyncable { - return fmt.Errorf( - "invalid app config: pruning == '%s'. Update config (%s) with pruning set to '%s' or '%s'.", - store.PruningStrategySyncable, viper.ConfigFileUsed(), store.PruningStrategyNothing, store.PruningStrategyEverything, - ) - } - } - return nil - } -} diff --git a/go.mod b/go.mod index 98abdc35..3dab775b 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,14 @@ module github.com/kava-labs/kava go 1.13 require ( - github.com/cosmos/cosmos-sdk v0.38.5 - github.com/gorilla/mux v1.7.3 + github.com/cosmos/cosmos-sdk v0.39.1 + github.com/gorilla/mux v1.7.4 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.6.3 - github.com/stretchr/testify v1.5.1 - github.com/tendermint/tendermint v0.33.6 + github.com/stretchr/testify v1.6.1 + github.com/tendermint/tendermint v0.33.7 github.com/tendermint/tm-db v0.5.1 - gopkg.in/yaml.v2 v2.2.8 + gopkg.in/yaml.v2 v2.3.0 ) // patch bech32 decoding to enable larger string lengths diff --git a/go.sum b/go.sum index 96bfb5f2..15c74311 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/99designs/keyring v1.1.3 h1:mEV3iyZWjkxQ7R8ia8GcG97vCX5zQQ7n4o8R2Bylw github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f h1:4O1om+UVU+Hfcihr1timk8YNXHxzZWgCo7ofnrZRApw= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= @@ -70,10 +68,8 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/cosmos-sdk v0.38.4 h1:jPZOvhMQkm7wwwzcLxuluhVpKfuIgddNGt999pAiz/Y= -github.com/cosmos/cosmos-sdk v0.38.4/go.mod h1:rzWOofbKfRt3wxiylmYWEFHnxxGj0coyqgWl2I9obAw= -github.com/cosmos/cosmos-sdk v0.38.5 h1:hLSrm4pvhqbA+zhyY+ltEfpynjLGeKFefctK8kHG6TE= -github.com/cosmos/cosmos-sdk v0.38.5/go.mod h1:o5V2eXScgPWh8BkKr2Z2Zq+NEt1RFW8l1HBk87JG+PY= +github.com/cosmos/cosmos-sdk v0.39.1 h1:vhjf9PZh9ph8btAj9aBpHoVITgVVjNBpM3x5Gl/Vwac= +github.com/cosmos/cosmos-sdk v0.39.1/go.mod h1:ry2ROl5n+f2/QXpKJo3rdWNJwll00z7KhIVcxNcl16M= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= @@ -103,8 +99,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= @@ -150,8 +144,6 @@ github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -177,13 +169,15 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -340,8 +334,6 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.5.0 h1:Ctq0iGpCmr3jeP77kbF2UxgvRwzWWz+4Bh9/vJTyg1A= -github.com/prometheus/client_golang v1.5.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -396,8 +388,6 @@ github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -408,8 +398,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= -github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -424,6 +412,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= @@ -437,16 +427,11 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ= github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk= -github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= -github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= -github.com/tendermint/tendermint v0.33.3 h1:6lMqjEoCGejCzAghbvfQgmw87snGSqEhDTo/jw+W8CI= -github.com/tendermint/tendermint v0.33.3/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= -github.com/tendermint/tendermint v0.33.6 h1:W4UOsXY4ROJZ3TLLGVVv71VXD4WK2gJRb3gzeced+mg= -github.com/tendermint/tendermint v0.33.6/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= -github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY= -github.com/tendermint/tm-db v0.5.0 h1:qtM5UTr1dlRnHtDY6y7MZO5Di8XAE2j3lc/pCnKJ5hQ= -github.com/tendermint/tm-db v0.5.0/go.mod h1:lSq7q5WRR/njf1LnhiZ/lIJHk2S8Y1Zyq5oP/3o9C2U= +github.com/tendermint/iavl v0.14.0 h1:Jkff+IFrXxRWtH9Jn/ga/2cxNnzMTv58xEKgCJsKUBg= +github.com/tendermint/iavl v0.14.0/go.mod h1:QmfViflFiXzxKLQE4tAUuWQHq+RSuQFxablW5oJZ6sE= +github.com/tendermint/tendermint v0.33.5/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= +github.com/tendermint/tendermint v0.33.7 h1:b5CQD8ggDtl4u0EbXzabi0MaOw9NrcXker6ijEkAE74= +github.com/tendermint/tendermint v0.33.7/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= github.com/tendermint/tm-db v0.5.1 h1:H9HDq8UEA7Eeg13kdYckkgwwkQLBnJGgX4PgLJRhieY= github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpXVVBaK4f4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -484,6 +469,8 @@ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vK golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y= golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -589,11 +576,12 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.28.1 h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k= google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -621,8 +609,10 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/x/validator-vesting/types/test_common.go b/x/validator-vesting/types/test_common.go index b34c14b2..74e24df7 100644 --- a/x/validator-vesting/types/test_common.go +++ b/x/validator-vesting/types/test_common.go @@ -84,3 +84,6 @@ func NewPubKey(pk string) (res crypto.PubKey) { copy(pkEd[:], pkBytes[:]) return pkEd } + +func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) } +func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) } diff --git a/x/validator-vesting/types/validator_vesting_account.go b/x/validator-vesting/types/validator_vesting_account.go index 686b52c0..b07697eb 100644 --- a/x/validator-vesting/types/validator_vesting_account.go +++ b/x/validator-vesting/types/validator_vesting_account.go @@ -1,13 +1,13 @@ package types import ( - "encoding/json" "errors" "fmt" "time" yaml "gopkg.in/yaml.v2" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -207,16 +207,40 @@ func (vva ValidatorVestingAccount) Validate() error { return vva.PeriodicVestingAccount.Validate() } -type validatorVestingAccountPretty struct { - Address sdk.AccAddress `json:"address" yaml:"address"` - Coins sdk.Coins `json:"coins" yaml:"coins"` - PubKey string `json:"public_key" yaml:"public_key"` - AccountNumber uint64 `json:"account_number" yaml:"account_number"` - Sequence uint64 `json:"sequence" yaml:"sequence"` - OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` - DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` - DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` - EndTime int64 `json:"end_time" yaml:"end_time"` +type validatorVestingAccountYAML struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` + PubKey string `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` + OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` + DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` + DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` + EndTime int64 `json:"end_time" yaml:"end_time"` + + // non-base vesting account fields + StartTime int64 `json:"start_time" yaml:"start_time"` + VestingPeriods vestingtypes.Periods `json:"vesting_periods" yaml:"vesting_periods"` + ValidatorAddress sdk.ConsAddress `json:"validator_address" yaml:"validator_address"` + ReturnAddress sdk.AccAddress `json:"return_address" yaml:"return_address"` + SigningThreshold int64 `json:"signing_threshold" yaml:"signing_threshold"` + CurrentPeriodProgress CurrentPeriodProgress `json:"current_period_progress" yaml:"current_period_progress"` + VestingPeriodProgress []VestingProgress `json:"vesting_period_progress" yaml:"vesting_period_progress"` + DebtAfterFailedVesting sdk.Coins `json:"debt_after_failed_vesting" yaml:"debt_after_failed_vesting"` +} + +type validatorVestingAccountJSON struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` + PubKey crypto.PubKey `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` + OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` + DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` + DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` + EndTime int64 `json:"end_time" yaml:"end_time"` + + // non-base vesting account fields StartTime int64 `json:"start_time" yaml:"start_time"` VestingPeriods vestingtypes.Periods `json:"vesting_periods" yaml:"vesting_periods"` ValidatorAddress sdk.ConsAddress `json:"validator_address" yaml:"validator_address"` @@ -229,15 +253,17 @@ type validatorVestingAccountPretty struct { // MarshalJSON returns the JSON representation of a PeriodicVestingAccount. func (vva ValidatorVestingAccount) MarshalJSON() ([]byte, error) { - alias := validatorVestingAccountPretty{ - Address: vva.Address, - Coins: vva.Coins, - AccountNumber: vva.AccountNumber, - Sequence: vva.Sequence, - OriginalVesting: vva.OriginalVesting, - DelegatedFree: vva.DelegatedFree, - DelegatedVesting: vva.DelegatedVesting, - EndTime: vva.EndTime, + alias := validatorVestingAccountJSON{ + Address: vva.Address, + Coins: vva.Coins, + PubKey: vva.GetPubKey(), + AccountNumber: vva.AccountNumber, + Sequence: vva.Sequence, + OriginalVesting: vva.OriginalVesting, + DelegatedFree: vva.DelegatedFree, + DelegatedVesting: vva.DelegatedVesting, + EndTime: vva.EndTime, + StartTime: vva.StartTime, VestingPeriods: vva.VestingPeriods, ValidatorAddress: vva.ValidatorAddress, @@ -248,38 +274,17 @@ func (vva ValidatorVestingAccount) MarshalJSON() ([]byte, error) { DebtAfterFailedVesting: vva.DebtAfterFailedVesting, } - if vva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, vva.PubKey) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - return json.Marshal(alias) + return codec.Cdc.MarshalJSON(alias) } -// UnmarshalJSON unmarshals raw JSON bytes into a PeriodicVestingAccount. +// UnmarshalJSON unmarshals raw JSON bytes into a ValidatorVestingAccount. func (vva *ValidatorVestingAccount) UnmarshalJSON(bz []byte) error { - var alias validatorVestingAccountPretty - if err := json.Unmarshal(bz, &alias); err != nil { + var alias validatorVestingAccountJSON + if err := codec.Cdc.UnmarshalJSON(bz, &alias); err != nil { return err } - var ( - pk crypto.PubKey - err error - ) - - if alias.PubKey != "" { - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) - if err != nil { - return err - } - } - - ba := authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence) + ba := authtypes.NewBaseAccount(alias.Address, alias.Coins, alias.PubKey, alias.AccountNumber, alias.Sequence) bva := &vestingtypes.BaseVestingAccount{ BaseAccount: ba, OriginalVesting: alias.OriginalVesting, @@ -300,45 +305,17 @@ func (vva *ValidatorVestingAccount) UnmarshalJSON(bz []byte) error { // MarshalYAML returns the YAML representation of an account. func (vva ValidatorVestingAccount) MarshalYAML() (interface{}, error) { - var bs []byte - var err error - var pubkey string + alias := validatorVestingAccountYAML{ + Address: vva.Address, + Coins: vva.Coins, + // no Pubkey + AccountNumber: vva.AccountNumber, + Sequence: vva.Sequence, + OriginalVesting: vva.OriginalVesting, + DelegatedFree: vva.DelegatedFree, + DelegatedVesting: vva.DelegatedVesting, + EndTime: vva.EndTime, - if vva.PubKey != nil { - pubkey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, vva.PubKey) - if err != nil { - return nil, err - } - } - - bs, err = yaml.Marshal(struct { - Address sdk.AccAddress - Coins sdk.Coins - PubKey string - AccountNumber uint64 - Sequence uint64 - OriginalVesting sdk.Coins - DelegatedFree sdk.Coins - DelegatedVesting sdk.Coins - EndTime int64 - StartTime int64 - VestingPeriods vestingtypes.Periods - ValidatorAddress sdk.ConsAddress - ReturnAddress sdk.AccAddress - SigningThreshold int64 - CurrentPeriodProgress CurrentPeriodProgress - VestingPeriodProgress []VestingProgress - DebtAfterFailedVesting sdk.Coins - }{ - Address: vva.Address, - Coins: vva.Coins, - PubKey: pubkey, - AccountNumber: vva.AccountNumber, - Sequence: vva.Sequence, - OriginalVesting: vva.OriginalVesting, - DelegatedFree: vva.DelegatedFree, - DelegatedVesting: vva.DelegatedVesting, - EndTime: vva.EndTime, StartTime: vva.StartTime, VestingPeriods: vva.VestingPeriods, ValidatorAddress: vva.ValidatorAddress, @@ -347,10 +324,24 @@ func (vva ValidatorVestingAccount) MarshalYAML() (interface{}, error) { CurrentPeriodProgress: vva.CurrentPeriodProgress, VestingPeriodProgress: vva.VestingPeriodProgress, DebtAfterFailedVesting: vva.DebtAfterFailedVesting, - }) + } + pk := vva.GetPubKey() + if pk != nil { + pubkey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) + if err != nil { + return nil, err + } + alias.PubKey = pubkey + } + + bz, err := yaml.Marshal(alias) if err != nil { return nil, err } - - return string(bs), err + return string(bz), err +} + +func (vva ValidatorVestingAccount) String() string { + out, _ := vva.MarshalYAML() + return out.(string) } diff --git a/x/validator-vesting/types/validator_vesting_account_test.go b/x/validator-vesting/types/validator_vesting_account_test.go index 89146d11..a6d680e6 100644 --- a/x/validator-vesting/types/validator_vesting_account_test.go +++ b/x/validator-vesting/types/validator_vesting_account_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/multisig" tmtime "github.com/tendermint/tendermint/types/time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,15 +25,15 @@ func TestNewAccount(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour).Unix() periods := vestingtypes.Periods{ - vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, } testAddr := CreateTestAddrs(1)[0] testPk := CreateTestPubKeys(1)[0] testConsAddr := sdk.ConsAddress(testPk.Address()) - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + origCoins := cs(c(feeDenom, 1000), c(stakeDenom, 100)) bacc := auth.NewBaseAccountWithAddress(testAddr) bacc.SetCoins(origCoins) bva, _ := vesting.NewBaseVestingAccount(&bacc, origCoins, endTime) @@ -46,15 +47,15 @@ func TestNewAccount(t *testing.T) { func TestGetVestedCoinsValidatorVestingAcc(t *testing.T) { now := tmtime.Now() periods := vestingtypes.Periods{ - vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, } testAddr := CreateTestAddrs(1)[0] testPk := CreateTestPubKeys(1)[0] testConsAddr := sdk.ConsAddress(testPk.Address()) - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + origCoins := cs(c(feeDenom, 1000), c(stakeDenom, 100)) bacc := auth.NewBaseAccountWithAddress(testAddr) bacc.SetCoins(origCoins) vva := NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) @@ -70,36 +71,32 @@ func TestGetVestedCoinsValidatorVestingAcc(t *testing.T) { // require 50% of coins vested after successful period 1 vesting vva.VestingPeriodProgress[0] = VestingProgress{true, true} vestedCoins = vva.GetVestedCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestedCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 50)), vestedCoins) // require 50% of coins vested after unsuccessful period 1 vesting // NOTE: There is a fairly important semantic distinction here. It seems tempting to say that a failed vesting period should mean that 'GetVestedCoins' should not return those coins. While the point of a validator vesting account is to 'seize' or 'burn' unsuccessfully vested coins, they do in fact vest and become spendable. The intuition is that they have to be spendable in order for the bank keeper to allow us to send/burn them. If they were not vested, then a validator vesting account that failed all of it's vesting periods would never return/burn the coins because it would never have a spendable balance by which to do so. They way we prevent them from being spent in a way other than return/burn is by sending them in the BeginBlock and thus beating any other transfers that would otherwise occur. vva.VestingPeriodProgress[0] = VestingProgress{true, false} vestedCoins = vva.GetVestedCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestedCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 50)), vestedCoins) // require period 2 coins don't vest until period is over vva.VestingPeriodProgress[0] = VestingProgress{true, true} // even if the vesting period was somehow successful, should still only return 50% of coins as vested, since the second vesting period hasn't completed. vva.VestingPeriodProgress[1] = VestingProgress{true, true} vestedCoins = vva.GetVestedCoins(now.Add(15 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestedCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 50)), vestedCoins) // require 75% of coins vested after successful period 2 vva.VestingPeriodProgress[0] = VestingProgress{true, true} vva.VestingPeriodProgress[1] = VestingProgress{true, true} vestedCoins = vva.GetVestedCoins(now.Add(18 * time.Hour)) - require.Equal(t, - sdk.Coins{ - sdk.NewInt64Coin(feeDenom, 750), sdk.NewInt64Coin(stakeDenom, 75)}, vestedCoins) + require.Equal(t, cs(c(feeDenom, 750), c(stakeDenom, 75)), vestedCoins) // require 75% of coins vested after successful period 1 and unsuccessful period 2. vva.VestingPeriodProgress[0] = VestingProgress{true, true} vva.VestingPeriodProgress[1] = VestingProgress{true, false} vestedCoins = vva.GetVestedCoins(now.Add(18 * time.Hour)) - require.Equal(t, - sdk.Coins{ - sdk.NewInt64Coin(feeDenom, 750), sdk.NewInt64Coin(stakeDenom, 75)}, vestedCoins) + require.Equal(t, cs(c(feeDenom, 750), c(stakeDenom, 75)), vestedCoins) // require 100% of coins vested after all periods complete successfully vva.VestingPeriodProgress[0] = VestingProgress{true, true} @@ -121,15 +118,15 @@ func TestGetVestedCoinsValidatorVestingAcc(t *testing.T) { func TestGetVestingCoinsValidatorVestingAcc(t *testing.T) { now := tmtime.Now() periods := vestingtypes.Periods{ - vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, } testAddr := CreateTestAddrs(1)[0] testPk := CreateTestPubKeys(1)[0] testConsAddr := sdk.ConsAddress(testPk.Address()) - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + origCoins := cs(c(feeDenom, 1000), c(stakeDenom, 100)) bacc := auth.NewBaseAccountWithAddress(testAddr) bacc.SetCoins(origCoins) vva := NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) @@ -145,33 +142,31 @@ func TestGetVestingCoinsValidatorVestingAcc(t *testing.T) { // require 50% of coins vesting after successful period 1 vesting vva.VestingPeriodProgress[0] = VestingProgress{true, true} vestingCoins = vva.GetVestingCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestingCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 50)), vestingCoins) // require 50% of coins vesting after unsuccessful period 1 vesting vva.VestingPeriodProgress[0] = VestingProgress{true, false} vestingCoins = vva.GetVestingCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestingCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 50)), vestingCoins) // require period 2 coins still vesting until period is over vva.VestingPeriodProgress[0] = VestingProgress{true, true} // should never happen, but still won't affect vesting balance vva.VestingPeriodProgress[1] = VestingProgress{true, true} vestingCoins = vva.GetVestingCoins(now.Add(15 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestingCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 50)), vestingCoins) // require 25% of coins vesting after successful period 2 vva.VestingPeriodProgress[0] = VestingProgress{true, true} vva.VestingPeriodProgress[1] = VestingProgress{true, true} vestingCoins = vva.GetVestingCoins(now.Add(18 * time.Hour)) - require.Equal(t, - sdk.Coins{ - sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}, vestingCoins) + require.Equal(t, cs(c(feeDenom, 250), c(stakeDenom, 25)), vestingCoins) // require 25% of coins vesting after successful period 1 and unsuccessful period 2 vva.VestingPeriodProgress[0] = VestingProgress{true, true} vva.VestingPeriodProgress[1] = VestingProgress{true, false} vestingCoins = vva.GetVestingCoins(now.Add(18 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}, vestingCoins) + require.Equal(t, cs(c(feeDenom, 250), c(stakeDenom, 25)), vestingCoins) // require no coins vesting after all periods complete successfully vva.VestingPeriodProgress[0] = VestingProgress{true, true} @@ -193,15 +188,15 @@ func TestGetVestingCoinsValidatorVestingAcc(t *testing.T) { func TestSpendableCoinsValidatorVestingAccount(t *testing.T) { now := tmtime.Now() periods := vestingtypes.Periods{ - vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, } testAddr := CreateTestAddrs(1)[0] testPk := CreateTestPubKeys(1)[0] testConsAddr := sdk.ConsAddress(testPk.Address()) - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + origCoins := cs(c(feeDenom, 1000), c(stakeDenom, 100)) bacc := auth.NewBaseAccountWithAddress(testAddr) bacc.SetCoins(origCoins) vva := NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) @@ -213,21 +208,21 @@ func TestSpendableCoinsValidatorVestingAccount(t *testing.T) { // require that all vested coins (50%) are spendable when period 1 completes successfully vva.VestingPeriodProgress[0] = VestingProgress{true, true} spendableCoins = vva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, spendableCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 50)), spendableCoins) // require that 50% of coins are spendable after period 1 completes unsuccessfully. See note above. The reason the coins are still 'spendable' is that we need to be able to transfer the coins to the return address/burn them. Making them not spendable means that it would be impossible to recover the debt for a validator vesting account for which all periods failed. vva.VestingPeriodProgress[0] = VestingProgress{true, false} spendableCoins = vva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, spendableCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 50)), spendableCoins) // receive some coins - recvAmt := sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)} + recvAmt := cs(c(stakeDenom, 50)) vva.SetCoins(vva.GetCoins().Add(recvAmt...)) // require that all vested coins (50%) are spendable plus any received after period 1 completes successfully vva.VestingPeriodProgress[0] = VestingProgress{true, true} spendableCoins = vva.SpendableCoins(now.Add(12 * time.Hour)) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 100)}, spendableCoins) + require.Equal(t, cs(c(feeDenom, 500), c(stakeDenom, 100)), spendableCoins) // spend all spendable coins vva.SetCoins(vva.GetCoins().Sub(spendableCoins)) @@ -240,15 +235,15 @@ func TestSpendableCoinsValidatorVestingAccount(t *testing.T) { func TestGetFailedVestedCoins(t *testing.T) { now := tmtime.Now() periods := vestingtypes.Periods{ - vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, } testAddr := CreateTestAddrs(1)[0] testPk := CreateTestPubKeys(1)[0] testConsAddr := sdk.ConsAddress(testPk.Address()) - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + origCoins := cs(c(feeDenom, 1000), c(stakeDenom, 100)) bacc := auth.NewBaseAccountWithAddress(testAddr) bacc.SetCoins(origCoins) vva := NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) @@ -256,7 +251,7 @@ func TestGetFailedVestedCoins(t *testing.T) { vva.VestingPeriodProgress[0] = VestingProgress{true, false} // require that period 1 coins are failed if the period completed unsuccessfully. require.Equal(t, - sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, + cs(c(feeDenom, 500), c(stakeDenom, 50)), vva.GetFailedVestedCoins(), ) @@ -270,15 +265,15 @@ func TestGetFailedVestedCoins(t *testing.T) { func TestTrackDelegationValidatorVestingAcc(t *testing.T) { now := tmtime.Now() periods := vestingtypes.Periods{ - vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, } testAddr := CreateTestAddrs(1)[0] testPk := CreateTestPubKeys(1)[0] testConsAddr := sdk.ConsAddress(testPk.Address()) - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + origCoins := cs(c(feeDenom, 1000), c(stakeDenom, 100)) bacc := auth.NewBaseAccountWithAddress(testAddr) bacc.SetCoins(origCoins) vva := NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) @@ -301,20 +296,20 @@ func TestTrackDelegationValidatorVestingAcc(t *testing.T) { // require the ability to delegate all vesting coins (50%) and all vested coins (50%) bacc.SetCoins(origCoins) vva = NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) - vva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, vva.DelegatedVesting) + vva.TrackDelegation(now.Add(12*time.Hour), cs(c(stakeDenom, 50))) + require.Equal(t, cs(c(stakeDenom, 50)), vva.DelegatedVesting) require.Nil(t, vva.DelegatedFree) vva.VestingPeriodProgress[0] = VestingProgress{true, true} - vva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, vva.DelegatedVesting) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, vva.DelegatedFree) + vva.TrackDelegation(now.Add(12*time.Hour), cs(c(stakeDenom, 50))) + require.Equal(t, cs(c(stakeDenom, 50)), vva.DelegatedVesting) + require.Equal(t, cs(c(stakeDenom, 50)), vva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds bacc.SetCoins(origCoins) vva = NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) require.Panics(t, func() { - vva.TrackDelegation(now.Add(24*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + vva.TrackDelegation(now.Add(24*time.Hour), cs(c(stakeDenom, 1000000))) }) require.Nil(t, vva.DelegatedVesting) require.Nil(t, vva.DelegatedFree) @@ -323,15 +318,15 @@ func TestTrackDelegationValidatorVestingAcc(t *testing.T) { func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { now := tmtime.Now() periods := vestingtypes.Periods{ - vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, } testAddr := CreateTestAddrs(1)[0] testPk := CreateTestPubKeys(1)[0] testConsAddr := sdk.ConsAddress(testPk.Address()) - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + origCoins := cs(c(feeDenom, 1000), c(stakeDenom, 100)) bacc := auth.NewBaseAccountWithAddress(testAddr) bacc.SetCoins(origCoins) vva := NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) @@ -357,7 +352,7 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { bacc.SetCoins(origCoins) vva = NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) require.Panics(t, func() { - vva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) + vva.TrackUndelegation(sdk.Coins{c(stakeDenom, 0)}) }) require.Nil(t, vva.DelegatedFree) require.Nil(t, vva.DelegatedVesting) @@ -365,32 +360,32 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { // successfully vest period 1 and delegate to two validators vva = NewValidatorVestingAccount(&bacc, now.Unix(), periods, testConsAddr, nil, 90) vva.VestingPeriodProgress[0] = VestingProgress{true, true} - vva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) - vva.TrackDelegation(now.Add(12*time.Hour), sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + vva.TrackDelegation(now.Add(12*time.Hour), cs(c(stakeDenom, 50))) + vva.TrackDelegation(now.Add(12*time.Hour), cs(c(stakeDenom, 50))) // undelegate from one validator that got slashed 50% - vva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, vva.DelegatedFree) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, vva.DelegatedVesting) + vva.TrackUndelegation(cs(c(stakeDenom, 25))) + require.Equal(t, cs(c(stakeDenom, 25)), vva.DelegatedFree) + require.Equal(t, cs(c(stakeDenom, 50)), vva.DelegatedVesting) // undelegate from the other validator that did not get slashed - vva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + vva.TrackUndelegation(cs(c(stakeDenom, 50))) require.Nil(t, vva.DelegatedFree) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, vva.DelegatedVesting) + require.Equal(t, cs(c(stakeDenom, 25)), vva.DelegatedVesting) } func TestGenesisAccountValidate(t *testing.T) { now := tmtime.Now() periods := vestingtypes.Periods{ - vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, - vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, } testAddr := CreateTestAddrs(1)[0] testPk := CreateTestPubKeys(1)[0] testConsAddr := sdk.ConsAddress(testPk.Address()) - origCoins := sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 100)} + origCoins := cs(c(feeDenom, 1000), c(stakeDenom, 100)) bacc := auth.NewBaseAccountWithAddress(testAddr) bacc.SetCoins(origCoins) @@ -442,3 +437,76 @@ func TestGenesisAccountValidate(t *testing.T) { } } } + +func TestMarshalJSON(t *testing.T) { + testTime := tmtime.Now() + periods := vestingtypes.Periods{ + vestingtypes.Period{Length: int64(12 * 60 * 60), Amount: cs(c(feeDenom, 500), c(stakeDenom, 50))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + vestingtypes.Period{Length: int64(6 * 60 * 60), Amount: cs(c(feeDenom, 250), c(stakeDenom, 25))}, + } + testAddrs := CreateTestAddrs(2) + testPk := CreateTestPubKeys(1)[0] + testConsAddr := sdk.ConsAddress(testPk.Address()) + testMultisigPk := multisig.NewPubKeyMultisigThreshold(6, CreateTestPubKeys(10)) + + testCases := []struct { + name string + account *ValidatorVestingAccount + }{ + { + name: "normal", + account: NewValidatorVestingAccount( + auth.NewBaseAccount( + testAddrs[0], + cs(c(stakeDenom, 100)), + testPk, + 0, + 1, + ), + testTime.Unix(), + periods, + testConsAddr, + testAddrs[1], + 90, + ), + }, + { + name: "multisig", + account: NewValidatorVestingAccount( + auth.NewBaseAccount( + testAddrs[0], + cs(c(stakeDenom, 1)), + testMultisigPk, + 412, + 67, + ), + testTime.Unix(), + periods, + testConsAddr, + testAddrs[1], + 67, + ), + }, + } + + for _, tc := range testCases { + bz, err := ModuleCdc.MarshalJSON(tc.account) + require.NoError(t, err) + + var reconstructedAccount *ValidatorVestingAccount + err = ModuleCdc.UnmarshalJSON(bz, &reconstructedAccount) + require.NoError(t, err) + + // first check debt coins using coin equality function, then overwrite to avoid problems with testify's Equality check + require.Truef(t, + tc.account.DebtAfterFailedVesting.IsEqual(reconstructedAccount.DebtAfterFailedVesting), + "DebtAfterFailedVesting not equal, expected: %+v, actual: %+v", + tc.account.DebtAfterFailedVesting, + reconstructedAccount.DebtAfterFailedVesting, + ) + reconstructedAccount.DebtAfterFailedVesting = tc.account.DebtAfterFailedVesting + + require.Equal(t, tc.account, reconstructedAccount) + } +}