diff --git a/changelog.md b/changelog.md index ed9513f3e1..c2e1ad8c7e 100644 --- a/changelog.md +++ b/changelog.md @@ -35,6 +35,7 @@ - Add nodejs version in the output of ignite version - Removed `handler.go` from scaffolded module template - Migrated to `cosmossdk.io` packages for `errors` and `math` +- Upgraded `spn` version - Vuex stores from the `generate vuex` command use the new TypeScript client - Upgraded frontend Vue template to v0.3.10 diff --git a/go.mod b/go.mod index 6e3ff6fc07..8bffeea28c 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( cosmossdk.io/math v1.0.0-beta.3 github.com/99designs/keyring v1.2.1 github.com/AlecAivazis/survey/v2 v2.1.1 + github.com/aws/smithy-go v1.8.0 github.com/blang/semver v3.5.1+incompatible github.com/briandowns/spinner v1.11.1 github.com/buger/jsonparser v1.1.1 @@ -48,7 +49,7 @@ require ( github.com/stretchr/testify v1.8.0 github.com/takuoki/gocase v1.0.0 github.com/tendermint/flutter/v2 v2.0.4 - github.com/tendermint/spn v0.2.1-0.20220826123316-985b629a92dd + github.com/tendermint/spn v0.2.1-0.20220907161743-aab4d3df1f2b github.com/tendermint/tendermint v0.34.21 github.com/tendermint/tm-db v0.6.7 github.com/vektra/mockery/v2 v2.14.0 @@ -58,7 +59,7 @@ require ( golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 golang.org/x/text v0.3.7 golang.org/x/tools v0.1.12 - google.golang.org/grpc v1.48.0 + google.golang.org/grpc v1.49.0 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v2 v2.4.0 mvdan.cc/gofumpt v0.3.1 @@ -237,7 +238,7 @@ require ( golang.org/x/net v0.0.0-20220726230323-06994584191e // indirect golang.org/x/sys v0.0.0-20220727055044-e65921a090b8 // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect - google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58 // indirect + google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 8525d5c79f..8b95ac0c89 100644 --- a/go.sum +++ b/go.sum @@ -183,6 +183,8 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7 github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/aws/smithy-go v1.8.0 h1:AEwwwXQZtUwP5Mz506FeXXrKBe0jA8gVM+1gEcSRooc= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -288,11 +290,7 @@ github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3h github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -534,7 +532,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -892,6 +889,7 @@ github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHL github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ignite/modules v0.0.0-20220830145312-d006783a7a21 h1:2eqRFOwuBtP5prBIslVokLwLkXqekbY4cENDf2mEyxQ= github.com/ignite/web v0.3.10 h1:WPKQi1a6gjwZPlaizT5Zq+cyUZ6b0p6VSAHr5L4i2p4= github.com/ignite/web v0.3.10/go.mod h1:WZWBaBYF8RazN7dE462BLpvXDY8ScacxcJ07BKwX/jY= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -1475,8 +1473,8 @@ github.com/tendermint/flutter/v2 v2.0.4/go.mod h1:hnaVhWhzv2Od1LqZFWrRKwiOHeMons github.com/tendermint/fundraising v0.3.1 h1:S4uOV/T7YNBqXhsCZnq/TUoHB0d2kM+6tKeTD4WhLN0= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/spn v0.2.1-0.20220826123316-985b629a92dd h1:G50RK8x61pNFGVSAI5UmXaBDA4h/P2+SDdftha9jjSM= -github.com/tendermint/spn v0.2.1-0.20220826123316-985b629a92dd/go.mod h1:5eAAx0g6FEXubQ1Sb7zJcDZqCSjb9yoJMVOQwjEt9qQ= +github.com/tendermint/spn v0.2.1-0.20220907161743-aab4d3df1f2b h1:QqEBIiWRC+uPM8FCXuxcvzTS6isR/lycQJDRHgsmg2c= +github.com/tendermint/spn v0.2.1-0.20220907161743-aab4d3df1f2b/go.mod h1:CMzd3oBkjR9I1h/BEaU1K2V78XqARFWGjxPP9Xy/FIE= github.com/tendermint/tendermint v0.34.21 h1:UiGGnBFHVrZhoQVQ7EfwSOLuCtarqCSsRf8VrklqB7s= github.com/tendermint/tendermint v0.34.21/go.mod h1:XDvfg6U7grcFTDx7VkzxnhazQ/bspGJAn4DZ6DcLLjQ= github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= @@ -1736,7 +1734,7 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c h1:q3gFqPqH7NVofKo3c3yETAP//pPI+G5mvB7qqj1Y5kY= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2056,8 +2054,8 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58 h1:sRT5xdTkj1Kbk30qbYC7VyMj73N5pZYsw6v+Nrzdhno= -google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc h1:Nf+EdcTLHR8qDNN/KfkQL0u0ssxt9OhbaWCl5C0ucEI= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -2086,8 +2084,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= 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= diff --git a/ignite/cmd/network_chain_join.go b/ignite/cmd/network_chain_join.go index 5099a4d20d..fc2a5b7762 100644 --- a/ignite/cmd/network_chain_join.go +++ b/ignite/cmd/network_chain_join.go @@ -5,13 +5,15 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ignite/cli/ignite/pkg/cliui/icons" + "github.com/pkg/errors" "github.com/rdegges/go-ipify" "github.com/spf13/cobra" "github.com/ignite/cli/ignite/pkg/cliui" "github.com/ignite/cli/ignite/pkg/cliui/cliquiz" - "github.com/ignite/cli/ignite/pkg/cliui/icons" "github.com/ignite/cli/ignite/pkg/gitpod" "github.com/ignite/cli/ignite/pkg/xchisel" "github.com/ignite/cli/ignite/services/network" @@ -19,8 +21,9 @@ import ( ) const ( - flagGentx = "gentx" - flagAmount = "amount" + flagGentx = "gentx" + flagAmount = "amount" + flagNoAccount = "no-account" ) // NewNetworkChainJoin creates a new chain join command to join @@ -34,7 +37,8 @@ func NewNetworkChainJoin() *cobra.Command { } c.Flags().String(flagGentx, "", "Path to a gentx json file") - c.Flags().String(flagAmount, "", "Amount of coins for account request") + c.Flags().String(flagAmount, "", "Amount of coins for account request (ignored if coordinator has fixed the account balances or if --no-acount flag is set)") + c.Flags().Bool(flagNoAccount, false, "Prevent sending a request for a genesis account") c.Flags().AddFlagSet(flagNetworkFrom()) c.Flags().AddFlagSet(flagSetHome()) c.Flags().AddFlagSet(flagSetKeyringBackend()) @@ -53,6 +57,7 @@ func networkChainJoinHandler(cmd *cobra.Command, args []string) error { joinOptions []network.JoinOption gentxPath, _ = cmd.Flags().GetString(flagGentx) amount, _ = cmd.Flags().GetString(flagAmount) + noAccount, _ = cmd.Flags().GetBool(flagNoAccount) ) nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) @@ -116,25 +121,33 @@ func networkChainJoinHandler(cmd *cobra.Command, args []string) error { } } - if amount != "" { - // parse the amount. - amountCoins, err := sdk.ParseCoinsNormalized(amount) - if err != nil { - return errors.Wrap(err, "error parsing amount") - } - joinOptions = append(joinOptions, network.WithAccountRequest(amountCoins)) - } else { - if !getYes(cmd) { - question := fmt.Sprintf( - "You haven't set the --%s flag and therefore an account request won't be submitted. Do you confirm", - flagAmount, - ) - if err := session.AskConfirm(question); err != nil { - return session.PrintSaidNo() + // genesis account request + if !noAccount { + switch { + case c.IsAccountBalanceFixed(): + // fixed account balance + joinOptions = append(joinOptions, network.WithAccountRequest(c.AccountBalance())) + case amount != "": + // account balance set by user + amountCoins, err := sdk.ParseCoinsNormalized(amount) + if err != nil { + return errors.Wrap(err, "error parsing amount") + } + joinOptions = append(joinOptions, network.WithAccountRequest(amountCoins)) + default: + // fixed balance and no amount entered by the user, we ask if they want to skip account request + if !getYes(cmd) { + question := fmt.Sprintf( + "You haven't set the --%s flag and therefore an account request won't be submitted. Do you confirm", + flagAmount, + ) + if err := session.AskConfirm(question); err != nil { + return session.PrintSaidNo() + } } - } - _ = session.Printf("%s %s\n", icons.Info, "Account request won't be submitted") + _ = session.Printf("%s %s\n", icons.Info, "Account request won't be submitted") + } } // create the message to add the validator. diff --git a/ignite/cmd/network_chain_launch.go b/ignite/cmd/network_chain_launch.go index 7406bd36b6..10b8ef6943 100644 --- a/ignite/cmd/network_chain_launch.go +++ b/ignite/cmd/network_chain_launch.go @@ -1,6 +1,9 @@ package ignitecmd import ( + "time" + + timeparser "github.com/aws/smithy-go/time" "github.com/spf13/cobra" "github.com/ignite/cli/ignite/pkg/cliui" @@ -8,7 +11,7 @@ import ( ) const ( - flagRemainingTime = "remaining-time" + flagLauchTime = "launch-time" ) // NewNetworkChainLaunch creates a new chain launch command to launch @@ -21,7 +24,11 @@ func NewNetworkChainLaunch() *cobra.Command { RunE: networkChainLaunchHandler, } - c.Flags().Duration(flagRemainingTime, 0, "Duration of time in seconds before the chain is effectively launched") + c.Flags().String( + flagLauchTime, + "", + "Timestamp the chain is effectively launched (example \"2022-01-01T00:00:00Z\")", + ) c.Flags().AddFlagSet(flagNetworkFrom()) c.Flags().AddFlagSet(flagSetKeyringBackend()) c.Flags().AddFlagSet(flagSetKeyringDir()) @@ -44,12 +51,21 @@ func networkChainLaunchHandler(cmd *cobra.Command, args []string) error { return err } - remainingTime, _ := cmd.Flags().GetDuration(flagRemainingTime) + // parse launch time + var launchTime time.Time + launchTimeStr, _ := cmd.Flags().GetString(flagLauchTime) + + if launchTimeStr != "" { + launchTime, err = timeparser.ParseDateTime(launchTimeStr) + if err != nil { + return err + } + } n, err := nb.Network() if err != nil { return err } - return n.TriggerLaunch(cmd.Context(), launchID, remainingTime) + return n.TriggerLaunch(cmd.Context(), launchID, launchTime) } diff --git a/ignite/cmd/network_chain_publish.go b/ignite/cmd/network_chain_publish.go index 78c0fc01ae..38c936dea1 100644 --- a/ignite/cmd/network_chain_publish.go +++ b/ignite/cmd/network_chain_publish.go @@ -17,17 +17,18 @@ import ( ) const ( - flagTag = "tag" - flagBranch = "branch" - flagHash = "hash" - flagGenesis = "genesis" - flagCampaign = "campaign" - flagShares = "shares" - flagNoCheck = "no-check" - flagChainID = "chain-id" - flagMainnet = "mainnet" - flagRewardCoins = "reward.coins" - flagRewardHeight = "reward.height" + flagTag = "tag" + flagBranch = "branch" + flagHash = "hash" + flagGenesis = "genesis" + flagCampaign = "campaign" + flagShares = "shares" + flagNoCheck = "no-check" + flagChainID = "chain-id" + flagMainnet = "mainnet" + flagAccountBalance = "account-balance" + flagRewardCoins = "reward.coins" + flagRewardHeight = "reward.height" ) // NewNetworkChainPublish returns a new command to publish a new chain to start a new network. @@ -51,6 +52,7 @@ func NewNetworkChainPublish() *cobra.Command { c.Flags().String(flagCampaignTotalSupply, "", "Add a total of the mainnet of a campaign") c.Flags().String(flagShares, "", "Add shares for the campaign") c.Flags().Bool(flagMainnet, false, "Initialize a mainnet campaign") + c.Flags().String(flagAccountBalance, "", "Balance for each approved genesis account for the chain") c.Flags().String(flagRewardCoins, "", "Reward coins") c.Flags().Int64(flagRewardHeight, 0, "Last reward height") c.Flags().String(flagAmount, "", "Amount of coins for account request") @@ -80,6 +82,7 @@ func networkChainPublishHandler(cmd *cobra.Command, args []string) error { campaignTotalSupplyStr, _ = cmd.Flags().GetString(flagCampaignTotalSupply) sharesStr, _ = cmd.Flags().GetString(flagShares) isMainnet, _ = cmd.Flags().GetBool(flagMainnet) + accountBalance, _ = cmd.Flags().GetString(flagAccountBalance) rewardCoinsStr, _ = cmd.Flags().GetString(flagRewardCoins) rewardDuration, _ = cmd.Flags().GetInt64(flagRewardHeight) amount, _ = cmd.Flags().GetString(flagAmount) @@ -91,6 +94,11 @@ func networkChainPublishHandler(cmd *cobra.Command, args []string) error { return errors.Wrap(err, "error parsing amount") } + accountBalanceCoins, err := sdk.ParseCoinsNormalized(accountBalance) + if err != nil { + return errors.Wrap(err, "error parsing account balance") + } + source, err := xurl.MightHTTPS(args[0]) if err != nil { return fmt.Errorf("invalid source url format: %w", err) @@ -202,6 +210,10 @@ func networkChainPublishHandler(cmd *cobra.Command, args []string) error { publishOptions = append(publishOptions, network.WithChainID(chainID)) } + if !accountBalanceCoins.IsZero() { + publishOptions = append(publishOptions, network.WithAccountBalance(accountBalanceCoins)) + } + if isMainnet { publishOptions = append(publishOptions, network.Mainnet()) } diff --git a/ignite/pkg/xtime/clock.go b/ignite/pkg/xtime/clock.go new file mode 100644 index 0000000000..55359a9752 --- /dev/null +++ b/ignite/pkg/xtime/clock.go @@ -0,0 +1,49 @@ +package xtime + +import "time" + +// Clock represents a clock that can retrieve current time +type Clock interface { + Now() time.Time + Add(duration time.Duration) +} + +// ClockSystem is a clock that retrieves system time +type ClockSystem struct{} + +// NewClockSystem returns a new ClockSystem +func NewClockSystem() ClockSystem { + return ClockSystem{} +} + +// Now implements Clock +func (ClockSystem) Now() time.Time { + return time.Now() +} + +// Add implements Clock +func (ClockSystem) Add(_ time.Duration) { + panic("Add can't be called for ClockSystem") +} + +// ClockMock is a clock mocking time with an internal counter +type ClockMock struct { + t time.Time +} + +// NewClockMock returns a new ClockMock +func NewClockMock(originalTime time.Time) *ClockMock { + return &ClockMock{ + t: originalTime, + } +} + +// Now implements Clock +func (c ClockMock) Now() time.Time { + return c.t +} + +// Add implements Clock +func (c *ClockMock) Add(duration time.Duration) { + c.t = c.t.Add(duration) +} diff --git a/ignite/pkg/xtime/clock_test.go b/ignite/pkg/xtime/clock_test.go new file mode 100644 index 0000000000..4d2c72f238 --- /dev/null +++ b/ignite/pkg/xtime/clock_test.go @@ -0,0 +1,24 @@ +package xtime_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ignite/cli/ignite/pkg/xtime" +) + +func TestClockSystem(t *testing.T) { + c := xtime.NewClockSystem() + require.False(t, c.Now().IsZero()) + require.Panics(t, func() { c.Add(time.Second) }) +} + +func TestClockMock(t *testing.T) { + timeSample := time.Now() + c := xtime.NewClockMock(timeSample) + require.True(t, c.Now().Equal(timeSample)) + c.Add(time.Second) + require.True(t, c.Now().Equal(timeSample.Add(time.Second))) +} diff --git a/ignite/pkg/xtime/unix_test.go b/ignite/pkg/xtime/unix_test.go index 7b40122ed5..4fc370e234 100644 --- a/ignite/pkg/xtime/unix_test.go +++ b/ignite/pkg/xtime/unix_test.go @@ -1,10 +1,12 @@ -package xtime +package xtime_test import ( "fmt" "testing" "time" + "github.com/ignite/cli/ignite/pkg/xtime" + "github.com/stretchr/testify/require" ) @@ -17,7 +19,7 @@ func TestSeconds(t *testing.T) { } for _, tt := range tests { t.Run(fmt.Sprintf("test %d value", tt), func(t *testing.T) { - got := Seconds(tt) + got := xtime.Seconds(tt) require.Equal(t, time.Duration(tt)*time.Second, got) }) } @@ -32,7 +34,7 @@ func TestNowAfter(t *testing.T) { } for _, tt := range tests { t.Run(fmt.Sprintf("test %d value", tt), func(t *testing.T) { - got := NowAfter(Seconds(tt)) + got := xtime.NowAfter(xtime.Seconds(tt)) date := time.Now().Add(time.Duration(tt) * time.Second) require.Equal(t, date.Format(time.UnixDate), got) }) @@ -59,7 +61,7 @@ func TestFormatUnix(t *testing.T) { } for _, tt := range tests { t.Run("test date "+tt.date.String(), func(t *testing.T) { - got := FormatUnix(tt.date) + got := xtime.FormatUnix(tt.date) require.Equal(t, tt.want, got) }) } diff --git a/ignite/services/network/join.go b/ignite/services/network/join.go index 1dea9592c9..da706a366d 100644 --- a/ignite/services/network/join.go +++ b/ignite/services/network/join.go @@ -106,14 +106,17 @@ func (n Network) sendValidatorRequest( return err } - msg := launchtypes.NewMsgRequestAddValidator( + msg := launchtypes.NewMsgSendRequest( addr, launchID, - valAddress, - gentx, - gentxInfo.PubKey, - gentxInfo.SelfDelegation, - peer, + launchtypes.NewGenesisValidator( + launchID, + valAddress, + gentx, + gentxInfo.PubKey, + gentxInfo.SelfDelegation, + peer, + ), ) n.ev.Send(events.New(events.StatusOngoing, "Broadcasting validator transaction")) @@ -123,7 +126,7 @@ func (n Network) sendValidatorRequest( return err } - var requestRes launchtypes.MsgRequestAddValidatorResponse + var requestRes launchtypes.MsgSendRequestResponse if err := res.Decode(&requestRes); err != nil { return err } diff --git a/ignite/services/network/join_test.go b/ignite/services/network/join_test.go index b5b6910eff..d2780c8e83 100644 --- a/ignite/services/network/join_test.go +++ b/ignite/services/network/join_test.go @@ -44,22 +44,24 @@ func TestJoin(t *testing.T) { On( "BroadcastTx", account, - &launchtypes.MsgRequestAddValidator{ - Creator: addr, - LaunchID: testutil.LaunchID, - ValAddress: addr, - GenTx: gentx.JSON(t), - ConsPubKey: []byte{}, - SelfDelegation: sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), - Peer: launchtypes.Peer{ - Id: testutil.NodeID, - Connection: &launchtypes.Peer_TcpAddress{ - TcpAddress: testutil.TCPAddress, - }, - }, - }, + launchtypes.NewMsgSendRequest( + addr, + testutil.LaunchID, + launchtypes.NewGenesisValidator( + testutil.LaunchID, + addr, + gentx.JSON(t), + []byte{}, + sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), + launchtypes.Peer{ + testutil.NodeID, + &launchtypes.Peer_TcpAddress{ + TcpAddress: testutil.TCPAddress, + }, + }), + ), ). - Return(testutil.NewResponse(&launchtypes.MsgRequestAddValidatorResponse{ + Return(testutil.NewResponse(&launchtypes.MsgSendRequestResponse{ RequestID: TestGenesisValidatorRequestID, AutoApproved: false, }), nil). @@ -95,22 +97,25 @@ func TestJoin(t *testing.T) { On( "BroadcastTx", account, - &launchtypes.MsgRequestAddValidator{ - Creator: addr, - LaunchID: testutil.LaunchID, - ValAddress: addr, - GenTx: gentx.JSON(t), - ConsPubKey: []byte{}, - SelfDelegation: sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), - Peer: launchtypes.Peer{ - Id: testutil.NodeID, - Connection: &launchtypes.Peer_TcpAddress{ - TcpAddress: testutil.TCPAddress, + launchtypes.NewMsgSendRequest( + addr, + testutil.LaunchID, + launchtypes.NewGenesisValidator( + testutil.LaunchID, + addr, + gentx.JSON(t), + []byte{}, + sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), + launchtypes.Peer{ + Id: testutil.NodeID, + Connection: &launchtypes.Peer_TcpAddress{ + TcpAddress: testutil.TCPAddress, + }, }, - }, - }, + ), + ), ). - Return(testutil.NewResponse(&launchtypes.MsgRequestAddValidatorResponse{ + Return(testutil.NewResponse(&launchtypes.MsgSendRequestResponse{ RequestID: TestGenesisValidatorRequestID, AutoApproved: false, }), nil). @@ -142,23 +147,26 @@ func TestJoin(t *testing.T) { On( "BroadcastTx", account, - &launchtypes.MsgRequestAddValidator{ - Creator: addr, - LaunchID: testutil.LaunchID, - ValAddress: addr, - GenTx: gentx.JSON(t), - ConsPubKey: []byte{}, - SelfDelegation: sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), - Peer: launchtypes.Peer{ - Id: testutil.NodeID, - Connection: &launchtypes.Peer_TcpAddress{ - TcpAddress: testutil.TCPAddress, + launchtypes.NewMsgSendRequest( + addr, + testutil.LaunchID, + launchtypes.NewGenesisValidator( + testutil.LaunchID, + addr, + gentx.JSON(t), + []byte{}, + sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), + launchtypes.Peer{ + Id: testutil.NodeID, + Connection: &launchtypes.Peer_TcpAddress{ + TcpAddress: testutil.TCPAddress, + }, }, - }, - }, + ), + ), ). Return( - testutil.NewResponse(&launchtypes.MsgRequestAddValidatorResponse{}), + testutil.NewResponse(&launchtypes.MsgSendRequestResponse{}), expectedError, ). Once() @@ -195,22 +203,25 @@ func TestJoin(t *testing.T) { On( "BroadcastTx", account, - &launchtypes.MsgRequestAddValidator{ - Creator: addr, - LaunchID: testutil.LaunchID, - ValAddress: addr, - GenTx: gentx.JSON(t), - ConsPubKey: []byte{}, - SelfDelegation: sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), - Peer: launchtypes.Peer{ - Id: testutil.NodeID, - Connection: &launchtypes.Peer_TcpAddress{ - TcpAddress: testutil.TCPAddress, + launchtypes.NewMsgSendRequest( + addr, + testutil.LaunchID, + launchtypes.NewGenesisValidator( + testutil.LaunchID, + addr, + gentx.JSON(t), + []byte{}, + sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), + launchtypes.Peer{ + Id: testutil.NodeID, + Connection: &launchtypes.Peer_TcpAddress{ + TcpAddress: testutil.TCPAddress, + }, }, - }, - }, + ), + ), ). - Return(testutil.NewResponse(&launchtypes.MsgRequestAddValidatorResponse{ + Return(testutil.NewResponse(&launchtypes.MsgSendRequestResponse{ RequestID: TestGenesisValidatorRequestID, AutoApproved: false, }), nil). @@ -219,14 +230,17 @@ func TestJoin(t *testing.T) { On( "BroadcastTx", account, - &launchtypes.MsgRequestAddAccount{ - Creator: addr, - LaunchID: testutil.LaunchID, - Address: addr, - Coins: sdk.NewCoins(sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt))), - }, + launchtypes.NewMsgSendRequest( + addr, + testutil.LaunchID, + launchtypes.NewGenesisAccount( + testutil.LaunchID, + addr, + sdk.NewCoins(sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt))), + ), + ), ). - Return(testutil.NewResponse(&launchtypes.MsgRequestAddAccountResponse{ + Return(testutil.NewResponse(&launchtypes.MsgSendRequestResponse{ RequestID: TestAccountRequestID, AutoApproved: false, }), nil). diff --git a/ignite/services/network/launch.go b/ignite/services/network/launch.go index 98cf7f8058..ca559b8d09 100644 --- a/ignite/services/network/launch.go +++ b/ignite/services/network/launch.go @@ -8,10 +8,15 @@ import ( launchtypes "github.com/tendermint/spn/x/launch/types" "github.com/ignite/cli/ignite/pkg/events" - "github.com/ignite/cli/ignite/pkg/xtime" "github.com/ignite/cli/ignite/services/network/networktypes" ) +// MinLaunchTimeOffset represents an offset used when minimum launch time is used +// minimum launch time will be block time + minimum launch time duration param +// block time when tx is executed is not predicable, therefore we add few seconds +// to ensure the minimum duration is reached +const MinLaunchTimeOffset = time.Second * 30 + // LaunchParams fetches the chain launch module params from SPN func (n Network) LaunchParams(ctx context.Context) (launchtypes.Params, error) { res, err := n.launchQuery.Params(ctx, &launchtypes.QueryParamsRequest{}) @@ -22,7 +27,7 @@ func (n Network) LaunchParams(ctx context.Context) (launchtypes.Params, error) { } // TriggerLaunch launches a chain as a coordinator -func (n Network) TriggerLaunch(ctx context.Context, launchID uint64, remainingTime time.Duration) error { +func (n Network) TriggerLaunch(ctx context.Context, launchID uint64, launchTime time.Time) error { n.ev.Send(events.New(events.StatusOngoing, fmt.Sprintf("Launching chain %d", launchID))) params, err := n.LaunchParams(ctx) if err != nil { @@ -30,29 +35,34 @@ func (n Network) TriggerLaunch(ctx context.Context, launchID uint64, remainingTi } var ( - minLaunch = xtime.Seconds(params.LaunchTimeRange.MinLaunchTime) - maxLaunch = xtime.Seconds(params.LaunchTimeRange.MaxLaunchTime) + minLaunchTime = n.clock.Now().Add(params.LaunchTimeRange.MinLaunchTime).Add(MinLaunchTimeOffset) + maxLaunchTime = n.clock.Now().Add(params.LaunchTimeRange.MaxLaunchTime) ) address, err := n.account.Address(networktypes.SPN) if err != nil { return err } - switch { - case remainingTime == 0: - // if the user does not specify the remaining time, use the minimal one - remainingTime = minLaunch - case remainingTime < minLaunch: - return fmt.Errorf("remaining time %s lower than minimum %s", - xtime.NowAfter(remainingTime), - xtime.NowAfter(minLaunch)) - case remainingTime > maxLaunch: - return fmt.Errorf("remaining time %s greater than maximum %s", - xtime.NowAfter(remainingTime), - xtime.NowAfter(maxLaunch)) + if launchTime.IsZero() { + // Use minimum launch time by default + launchTime = minLaunchTime + } else { + // check launch time is in range + switch { + case launchTime.Before(minLaunchTime): + return fmt.Errorf("launch time %s lower than minimum %s", + launchTime.String(), + minLaunchTime.String(), + ) + case launchTime.After(maxLaunchTime): + return fmt.Errorf("launch time %s bigger than maximum %s", + launchTime.String(), + maxLaunchTime.String(), + ) + } } - msg := launchtypes.NewMsgTriggerLaunch(address, launchID, int64(remainingTime.Seconds())) + msg := launchtypes.NewMsgTriggerLaunch(address, launchID, launchTime) n.ev.Send(events.New(events.StatusOngoing, "Setting launch time")) res, err := n.cosmos.BroadcastTx(n.account, msg) if err != nil { @@ -65,7 +75,7 @@ func (n Network) TriggerLaunch(ctx context.Context, launchID uint64, remainingTi } n.ev.Send(events.New(events.StatusDone, - fmt.Sprintf("Chain %d will be launched on %s", launchID, xtime.NowAfter(remainingTime)), + fmt.Sprintf("Chain %d will be launched on %s", launchID, launchTime.String()), )) return nil } diff --git a/ignite/services/network/launch_test.go b/ignite/services/network/launch_test.go index ec21c0ff11..5c51523fb4 100644 --- a/ignite/services/network/launch_test.go +++ b/ignite/services/network/launch_test.go @@ -10,15 +10,14 @@ import ( "github.com/stretchr/testify/require" launchtypes "github.com/tendermint/spn/x/launch/types" - "github.com/ignite/cli/ignite/pkg/xtime" "github.com/ignite/cli/ignite/services/network/networktypes" "github.com/ignite/cli/ignite/services/network/testutil" ) const ( - TestMinRemainingTime = 3600 - TestMaxRemainingTime = 86400 - TestRevertDelay = 3600 + TestMinRemainingTime = time.Second * 3600 + TestMaxRemainingTime = time.Second * 86400 + TestRevertDelay = time.Second * 3600 ) func TestTriggerLaunch(t *testing.T) { @@ -41,14 +40,14 @@ func TestTriggerLaunch(t *testing.T) { On("BroadcastTx", account, &launchtypes.MsgTriggerLaunch{ - Coordinator: addr, - LaunchID: testutil.LaunchID, - RemainingTime: TestMaxRemainingTime, + Coordinator: addr, + LaunchID: testutil.LaunchID, + LaunchTime: sampleTime.Add(TestMaxRemainingTime), }). Return(testutil.NewResponse(&launchtypes.MsgTriggerLaunchResponse{}), nil). Once() - launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, TestMaxRemainingTime*time.Second) + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, sampleTime.Add(TestMaxRemainingTime)) require.NoError(t, launchError) suite.AssertAllMocks(t) }) @@ -57,7 +56,7 @@ func TestTriggerLaunch(t *testing.T) { var ( account = testutil.NewTestAccount(t, testutil.TestAccountName) suite, network = newSuite(account) - remainingTimeLowerThanMinimum = (TestMinRemainingTime - 60) * time.Second + remainingTimeLowerThanMinimum = sampleTime ) suite.LaunchQueryMock. @@ -72,8 +71,8 @@ func TestTriggerLaunch(t *testing.T) { t, launchError, "remaining time %s lower than minimum %s", - xtime.NowAfter(remainingTimeLowerThanMinimum), - xtime.NowAfter(TestMinRemainingTime), + remainingTimeLowerThanMinimum.String(), + sampleTime.Add(TestMinRemainingTime).Add(MinLaunchTimeOffset).String(), ) suite.AssertAllMocks(t) }) @@ -82,7 +81,7 @@ func TestTriggerLaunch(t *testing.T) { var ( account = testutil.NewTestAccount(t, testutil.TestAccountName) suite, network = newSuite(account) - remainingTimeGreaterThanMaximum = (TestMaxRemainingTime + 60) * time.Hour + remainingTimeGreaterThanMaximum = sampleTime.Add(TestMaxRemainingTime).Add(time.Second) ) suite.LaunchQueryMock. @@ -97,8 +96,8 @@ func TestTriggerLaunch(t *testing.T) { t, launchError, "remaining time %s greater than maximum %s", - xtime.NowAfter(remainingTimeGreaterThanMaximum), - xtime.NowAfter(TestMaxRemainingTime), + remainingTimeGreaterThanMaximum.String(), + sampleTime.Add(TestMaxRemainingTime).String(), ) suite.AssertAllMocks(t) }) @@ -123,14 +122,14 @@ func TestTriggerLaunch(t *testing.T) { On("BroadcastTx", account, &launchtypes.MsgTriggerLaunch{ - Coordinator: addr, - LaunchID: testutil.LaunchID, - RemainingTime: TestMaxRemainingTime, + Coordinator: addr, + LaunchID: testutil.LaunchID, + LaunchTime: sampleTime.Add(TestMaxRemainingTime), }). Return(testutil.NewResponse(&launchtypes.MsgTriggerLaunch{}), expectedError). Once() - launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, TestMaxRemainingTime*time.Second) + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, sampleTime.Add(TestMaxRemainingTime)) require.Error(t, launchError) require.Equal(t, expectedError, launchError) suite.AssertAllMocks(t) @@ -156,14 +155,14 @@ func TestTriggerLaunch(t *testing.T) { On("BroadcastTx", account, &launchtypes.MsgTriggerLaunch{ - Coordinator: addr, - LaunchID: testutil.LaunchID, - RemainingTime: TestMaxRemainingTime, + Coordinator: addr, + LaunchID: testutil.LaunchID, + LaunchTime: sampleTime.Add(TestMaxRemainingTime), }). Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{}), expectedError). Once() - launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, TestMaxRemainingTime*time.Second) + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, sampleTime.Add(TestMaxRemainingTime)) require.Error(t, launchError) require.Equal(t, expectedError, launchError) suite.AssertAllMocks(t) @@ -183,7 +182,7 @@ func TestTriggerLaunch(t *testing.T) { }, expectedError). Once() - launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, (TestMaxRemainingTime+60)*time.Second) + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, sampleTime.Add(TestMaxRemainingTime)) require.Error(t, launchError) require.Equal(t, expectedError, launchError) suite.AssertAllMocks(t) diff --git a/ignite/services/network/network.go b/ignite/services/network/network.go index a6f6a66633..59234b5392 100644 --- a/ignite/services/network/network.go +++ b/ignite/services/network/network.go @@ -19,6 +19,7 @@ import ( "github.com/ignite/cli/ignite/pkg/cosmosaccount" "github.com/ignite/cli/ignite/pkg/cosmosclient" "github.com/ignite/cli/ignite/pkg/events" + "github.com/ignite/cli/ignite/pkg/xtime" ) //go:generate mockery --name CosmosClient --case underscore @@ -42,6 +43,7 @@ type Network struct { stakingQuery stakingtypes.QueryClient bankQuery banktypes.QueryClient monitoringConsumerQuery monitoringctypes.QueryClient + clock xtime.Clock } //go:generate mockery --name Chain --case underscore @@ -105,6 +107,12 @@ func WithBankQueryClient(client banktypes.QueryClient) Option { } } +func WithCustomClock(clock xtime.Clock) Option { + return func(n *Network) { + n.clock = clock + } +} + // CollectEvents collects events from the network builder. func CollectEvents(ev events.Bus) Option { return func(n *Network) { @@ -125,6 +133,7 @@ func New(cosmos CosmosClient, account cosmosaccount.Account, options ...Option) stakingQuery: stakingtypes.NewQueryClient(cosmos.Context()), bankQuery: banktypes.NewQueryClient(cosmos.Context()), monitoringConsumerQuery: monitoringctypes.NewQueryClient(cosmos.Context()), + clock: xtime.NewClockSystem(), } for _, opt := range options { opt(&n) diff --git a/ignite/services/network/network_test.go b/ignite/services/network/network_test.go index c9b4ded2e9..26f98c7a57 100644 --- a/ignite/services/network/network_test.go +++ b/ignite/services/network/network_test.go @@ -3,13 +3,17 @@ package network import ( "errors" "testing" + "time" "github.com/stretchr/testify/require" "github.com/ignite/cli/ignite/pkg/cosmosaccount" + "github.com/ignite/cli/ignite/pkg/xtime" "github.com/ignite/cli/ignite/services/network/testutil" ) +var sampleTime = time.Unix(1000, 1000) + func newSuite(account cosmosaccount.Account) (testutil.Suite, Network) { suite := testutil.NewSuite() return suite, New( @@ -22,6 +26,7 @@ func newSuite(account cosmosaccount.Account) (testutil.Suite, Network) { WithStakingQueryClient(suite.StakingClient), WithMonitoringConsumerQueryClient(suite.MonitoringConsumerClient), WithBankQueryClient(suite.BankClient), + WithCustomClock(xtime.NewClockMock(sampleTime)), ) } diff --git a/ignite/services/network/networkchain/networkchain.go b/ignite/services/network/networkchain/networkchain.go index de4a9b275c..e06c284be2 100644 --- a/ignite/services/network/networkchain/networkchain.go +++ b/ignite/services/network/networkchain/networkchain.go @@ -5,7 +5,9 @@ import ( "errors" "os" "os/exec" + "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" @@ -33,7 +35,9 @@ type Chain struct { hash string genesisURL string genesisHash string - launchTime int64 + launchTime time.Time + + accountBalance sdk.Coins keyringBackend chaincmd.KeyringBackend @@ -95,6 +99,7 @@ func SourceLaunch(launch networktypes.ChainLaunch) SourceOption { c.genesisHash = launch.GenesisHash c.home = ChainHome(launch.ID) c.launchTime = launch.LaunchTime + c.accountBalance = launch.AccountBalance } } @@ -240,6 +245,14 @@ func (c Chain) SourceHash() string { return c.hash } +func (c Chain) IsAccountBalanceFixed() bool { + return !c.accountBalance.IsZero() +} + +func (c Chain) AccountBalance() sdk.Coins { + return c.accountBalance +} + func (c Chain) IsHomeDirExist() (ok bool, err error) { home, err := c.chain.Home() if err != nil { diff --git a/ignite/services/network/networkchain/prepare.go b/ignite/services/network/networkchain/prepare.go index 3b4284de76..f505e77603 100644 --- a/ignite/services/network/networkchain/prepare.go +++ b/ignite/services/network/networkchain/prepare.go @@ -136,7 +136,7 @@ func (c Chain) buildGenesis( // set genesis time and chain id genesisFields := []cosmosutil.GenesisField{ cosmosutil.WithKeyValue(cosmosutil.FieldChainID, c.id), - cosmosutil.WithKeyValueTimestamp(cosmosutil.FieldGenesisTime, c.launchTime), + cosmosutil.WithKeyValueTimestamp(cosmosutil.FieldGenesisTime, c.launchTime.Unix()), } // TODO: implement a single option for all reward related fields diff --git a/ignite/services/network/networktypes/chainlaunch.go b/ignite/services/network/networktypes/chainlaunch.go index 82deea657c..633344e46c 100644 --- a/ignite/services/network/networktypes/chainlaunch.go +++ b/ignite/services/network/networktypes/chainlaunch.go @@ -1,6 +1,12 @@ package networktypes -import launchtypes "github.com/tendermint/spn/x/launch/types" +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + + launchtypes "github.com/tendermint/spn/x/launch/types" +) type ( NetworkType string @@ -14,11 +20,12 @@ type ( SourceHash string `json:"SourceHash"` GenesisURL string `json:"GenesisURL"` GenesisHash string `json:"GenesisHash"` - LaunchTime int64 `json:"LaunchTime"` + LaunchTime time.Time `json:"LaunchTime"` CampaignID uint64 `json:"CampaignID"` LaunchTriggered bool `json:"LaunchTriggered"` Network NetworkType `json:"Network"` Reward string `json:"Reward,omitempty"` + AccountBalance sdk.Coins `json:"AccountBalance"` } ) @@ -33,9 +40,9 @@ func (n NetworkType) String() string { // ToChainLaunch converts a chain launch data from SPN and returns a ChainLaunch object func ToChainLaunch(chain launchtypes.Chain) ChainLaunch { - var launchTime int64 + var launchTime time.Time if chain.LaunchTriggered { - launchTime = chain.LaunchTimestamp + launchTime = chain.LaunchTime } network := NetworkTypeTestnet @@ -53,6 +60,7 @@ func ToChainLaunch(chain launchtypes.Chain) ChainLaunch { CampaignID: chain.CampaignID, LaunchTriggered: chain.LaunchTriggered, Network: network, + AccountBalance: chain.AccountBalance, } // check if custom genesis URL is provided. diff --git a/ignite/services/network/networktypes/chainlaunch_test.go b/ignite/services/network/networktypes/chainlaunch_test.go index 15cb79e8fd..71c657ca79 100644 --- a/ignite/services/network/networktypes/chainlaunch_test.go +++ b/ignite/services/network/networktypes/chainlaunch_test.go @@ -2,6 +2,7 @@ package networktypes_test import ( "testing" + "time" "github.com/stretchr/testify/require" launchtypes "github.com/tendermint/spn/x/launch/types" @@ -46,7 +47,7 @@ func TestToChainLaunch(t *testing.T) { SourceURL: "bar.com", SourceHash: "0xbbb", LaunchTriggered: true, - LaunchTimestamp: 100, + LaunchTime: time.Unix(100, 100).UTC(), InitialGenesis: launchtypes.NewGenesisURL( "genesisfoo.com", "0xccc", @@ -60,7 +61,7 @@ func TestToChainLaunch(t *testing.T) { GenesisURL: "genesisfoo.com", GenesisHash: "0xccc", LaunchTriggered: true, - LaunchTime: 100, + LaunchTime: time.Unix(100, 100).UTC(), CampaignID: 0, Network: "testnet", }, diff --git a/ignite/services/network/publish.go b/ignite/services/network/publish.go index 39deaf8649..84902a46aa 100644 --- a/ignite/services/network/publish.go +++ b/ignite/services/network/publish.go @@ -24,6 +24,7 @@ type publishOptions struct { totalSupply sdk.Coins sharePercentages SharePercents mainnet bool + accountBalance sdk.Coins } // PublishOption configures chain creation. @@ -78,6 +79,13 @@ func WithPercentageShares(sharePercentages []SharePercent) PublishOption { } } +// WithAccountBalance set a balance used for all genesis account of the chain +func WithAccountBalance(accountBalance sdk.Coins) PublishOption { + return func(c *publishOptions) { + c.accountBalance = accountBalance + } +} + // Mainnet initialize a published chain into the mainnet func Mainnet() PublishOption { return func(o *publishOptions) { @@ -221,6 +229,7 @@ func (n Network) Publish(ctx context.Context, c Chain, options ...PublishOption) genesisHash, campaignID != 0, campaignID, + o.accountBalance, nil, ) res, err := n.cosmos.BroadcastTx(n.account, msgCreateChain) @@ -260,11 +269,14 @@ func (n Network) sendAccountRequest( return err } - msg := launchtypes.NewMsgRequestAddAccount( + msg := launchtypes.NewMsgSendRequest( addr, launchID, - address, - amount, + launchtypes.NewGenesisAccount( + launchID, + address, + amount, + ), ) n.ev.Send(events.New(events.StatusOngoing, "Broadcasting account transactions")) @@ -273,7 +285,7 @@ func (n Network) sendAccountRequest( return err } - var requestRes launchtypes.MsgRequestAddAccountResponse + var requestRes launchtypes.MsgSendRequestResponse if err := res.Decode(&requestRes); err != nil { return err } diff --git a/ignite/services/network/publish_test.go b/ignite/services/network/publish_test.go index 2f33b043b5..883572edee 100644 --- a/ignite/services/network/publish_test.go +++ b/ignite/services/network/publish_test.go @@ -90,6 +90,69 @@ func TestPublish(t *testing.T) { suite.AssertAllMocks(t) }) + t.Run("publish chain with custom account balance", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + accountBalance, err := sdk.ParseCoinsNormalized("1000foo,500bar") + require.NoError(t, err) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "CoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + CoordinatorByAddress: profiletypes.CoordinatorByAddress{ + Address: addr, + CoordinatorID: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainID: testutil.ChainID, + SourceURL: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + GenesisURL: "", + GenesisHash: "", + HasCampaign: false, + CampaignID: 0, + AccountBalance: accountBalance, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchID: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, campaignID, publishError := network.Publish( + context.Background(), + suite.ChainMock, + WithAccountBalance(accountBalance), + ) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, uint64(0), campaignID) + suite.AssertAllMocks(t) + }) + t.Run("publish chain with pre created campaign", func(t *testing.T) { var ( account = testutil.NewTestAccount(t, testutil.TestAccountName)