Skip to content

Commit

Permalink
1 command testnet (standalone & IBC) (#18)
Browse files Browse the repository at this point in the history
* working imp

* replace wasmd keys cmd

* use path.Join

* Validate, new project alias

* alpha.2 globalfee

* `make testnet-ibc`
  • Loading branch information
Reecepbcups authored Feb 10, 2024
1 parent ea23fca commit e44cb5a
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 56 deletions.
2 changes: 1 addition & 1 deletion cmd/spawn/download-localic.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var LocalICCmd = &cobra.Command{
}

func whereIsLocalICInstalled() string {
for _, path := range []string{"local-ic", "bin/local-ic", "local-interchain/localic"} {
for _, path := range []string{"local-ic", path.Join("bin", "local-ic"), path.Join("local-interchain", "localic")} {
if _, err := os.Stat(path); err == nil {
return path
}
Expand Down
96 changes: 55 additions & 41 deletions cmd/spawn/new-chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
"path"
"strings"

"golang.org/x/text/cases"
"golang.org/x/text/language"

"github.com/cosmos/btcutil/bech32"
"github.com/spf13/cobra"
"github.com/strangelove-ventures/simapp"
Expand All @@ -27,6 +30,14 @@ type SpawnNewConfig struct {
DisabledFeatures []string
}

func (cfg *SpawnNewConfig) Validate() error {
if strings.ContainsAny(cfg.ProjectName, `~!@#$%^&*()_+{}|:"<>?/.,;'[]\=-`) {
return fmt.Errorf("project name cannot contain special characters %s", cfg.ProjectName)
}

return nil
}

const (
FlagWalletPrefix = "bech32"
FlagBinaryName = "bin"
Expand All @@ -39,7 +50,7 @@ const (

var (
IgnoredFiles = []string{"embed.go", "heighliner/"}
SupportedFeatures = []string{"tokenfactory", "poa", "globalfee", "wasm", "ibc", "nft", "group", "circuit"}
SupportedFeatures = []string{"tokenfactory", "poa", "globalfee", "wasm", "icahost", "icacontroller"}
)

func init() {
Expand All @@ -51,18 +62,18 @@ func init() {
newChain.Flags().Bool(FlagNoGit, false, "git init base")
}

// TODO: reduce required inputs here. (or make them flags with defaults?)
var newChain = &cobra.Command{
Use: "new [project-name]",
Short: "List all current chains or outputs a current config information",
Example: fmt.Sprintf(`spawn new project --%s=cosmos --%s=appd`, FlagWalletPrefix, FlagBinaryName),
Use: "new-chain [project-name]",
Short: "Create a new project",
Example: fmt.Sprintf(
`spawn new rollchain --%s=cosmos --%s=appd --%s=token --%s=tokenfactory,poa,globalfee`,
FlagWalletPrefix, FlagBinaryName, FlagTokenDenom, FlagDisabled,
),
Args: cobra.ExactArgs(1),
// ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// return GetFiles(), cobra.ShellCompDirectiveNoFileComp
// },
Aliases: []string{"new"},
Run: func(cmd *cobra.Command, args []string) {
projName := strings.ToLower(args[0])
appName := strings.Title(projName) + "App"
appName := cases.Title(language.AmericanEnglish).String(projName) + "App"

walletPrefix, _ := cmd.Flags().GetString(FlagWalletPrefix)
binName, _ := cmd.Flags().GetString(FlagBinaryName)
Expand All @@ -74,7 +85,7 @@ var newChain = &cobra.Command{

ignoreGitInit, _ := cmd.Flags().GetBool(FlagNoGit)

cfg := SpawnNewConfig{
cfg := &SpawnNewConfig{
ProjectName: projName,
Bech32Prefix: walletPrefix,
AppName: appName,
Expand All @@ -86,12 +97,15 @@ var newChain = &cobra.Command{
// by default everything is on, then we remove what the user wants to disable
DisabledFeatures: disabled,
}
if err := cfg.Validate(); err != nil {
fmt.Println("Error validating config:", err)
return
}

NewChain(cfg)

// Create the base git repo
if !ignoreGitInit {

// if git already exists, don't init
if err := execCommand("git", "init", projName, "--quiet"); err != nil {
fmt.Println("Error initializing git:", err)
Expand All @@ -111,13 +125,14 @@ var newChain = &cobra.Command{
fmt.Printf("\n\n🎉 New blockchain '%s' generated!\n", projName)
fmt.Println("🏅Getting started:")
fmt.Println(" - $ cd " + projName)
fmt.Println(" - $ make testnet # build & start the testnet")
fmt.Println(" - $ make testnet # build & start a testnet")
fmt.Println(" - $ make testnet-ibc # build & start an ibc testnet")
fmt.Printf(" - $ make install # build the %s binary\n", binName)
fmt.Println(" - $ make local-image # build docker image")
},
}

func NewChain(cfg SpawnNewConfig) {
func NewChain(cfg *SpawnNewConfig) {
NewDirName := cfg.ProjectName
bech32Prefix := cfg.Bech32Prefix
projName := cfg.ProjectName
Expand Down Expand Up @@ -176,7 +191,7 @@ func NewChain(cfg SpawnNewConfig) {
return nil
}

if relPath == "scripts/test_node.sh" {
if relPath == path.Join("scripts", "test_node.sh") {
fc = strings.ReplaceAll(fc, "export BINARY=${BINARY:-wasmd}", fmt.Sprintf("export BINARY=${BINARY:-%s}", binaryName))
fc = strings.ReplaceAll(fc, "export DENOM=${DENOM:-token}", fmt.Sprintf("export DENOM=${DENOM:-%s}", cfg.TokenDenom))
}
Expand All @@ -197,9 +212,11 @@ func NewChain(cfg SpawnNewConfig) {
fc = strings.ReplaceAll(fc, "version.AppName=wasmd", fmt.Sprintf("version.AppName=%s", binaryName))
fc = strings.ReplaceAll(fc, "cmd/wasmd", fmt.Sprintf("cmd/%s", binaryName))
fc = strings.ReplaceAll(fc, "build/wasmd", fmt.Sprintf("build/%s", binaryName))
fc = strings.ReplaceAll(fc, "wasmd keys", fmt.Sprintf("%s keys", binaryName)) // testnet

// heighliner (not working atm)
fc = strings.ReplaceAll(fc, "docker build . -t wasmd:local", fmt.Sprintf(`docker build . -t %s:local`, strings.ToLower(projName)))
// TODO: remember to make the below path.Join
// fc = strings.ReplaceAll(fc, "heighliner build -c wasmd --local --dockerfile=cosmos -f chains.yaml", fmt.Sprintf(`heighliner build -c %s --local --dockerfile=cosmos -f chains.yaml`, strings.ToLower(appName)))
// if strings.HasSuffix(relPath, "chains.yaml") {
// fc = strings.ReplaceAll(fc, "myappname", strings.ToLower(appName))
Expand Down Expand Up @@ -253,24 +270,22 @@ func NewChain(cfg SpawnNewConfig) {
// Removes disabled features from the files specified
func removeDisabledFeatures(disabled []string, relativePath string, fileContent []byte) []byte {
for _, name := range disabled {
switch name {
case "tokenfactory":
switch strings.ToLower(name) {
case "tokenfactory", "token-factory", "tf":
fileContent = removeTokenFactory(relativePath, fileContent)
case "poa":
fileContent = removePoa(relativePath, fileContent)
case "globalfee":
fileContent = removeGlobalFee(relativePath, fileContent)
case "ibc": // this would remove all. Including PFM, then we can have others for specifics (i.e. ICAHost, IBCFees)
// fileContent = removeIbc(relativePath, fileContent)
continue
case "wasm":
case "wasm", "cosmwasm":
fileContent = removeWasm(relativePath, fileContent)
continue
case "nft":
// fileContent = removeNft(relativePath, fileContent)
case "icahost":
// what about all ICA?
// fileContent = removeICAHost(relativePath, fileContent)
continue
case "circuit":
// fileContent = removeCircuit(relativePath, fileContent)
case "icacontroller":
// fileContent = removeICAController(relativePath, fileContent)
continue
}
}
Expand All @@ -287,11 +302,11 @@ func removeTokenFactory(relativePath string, fileContent []byte) []byte {
fileContent = RemoveGoModImport("github.com/reecepbcups/tokenfactory", fileContent)
}

if relativePath == "app/app.go" {
if relativePath == path.Join("app", "app.go") {
fileContent = RemoveGeneralModule("tokenfactory", string(fileContent))
}

if relativePath == "scripts/test_node.sh" {
if relativePath == path.Join("scripts", "test_node.sh") {
fileContent = RemoveGeneralModule("tokenfactory", string(fileContent))
}

Expand All @@ -303,11 +318,11 @@ func removePoa(relativePath string, fileContent []byte) []byte {
fileContent = RemoveGoModImport("github.com/strangelove-ventures/poa", fileContent)
}

if relativePath == "app/app.go" || relativePath == "app/ante.go" {
if relativePath == path.Join("app", "app.go") || relativePath == path.Join("app", "ante.go") {
fileContent = RemoveGeneralModule("poa", string(fileContent))
}

if relativePath == "scripts/test_node.sh" {
if relativePath == path.Join("scripts", "test_node.sh") {
fileContent = RemoveGeneralModule("poa", string(fileContent))
}

Expand All @@ -323,12 +338,12 @@ func removeGlobalFee(relativePath string, fileContent []byte) []byte {
fileContent = RemoveGoModImport("github.com/reecepbcups/globalfee", fileContent)
}

if relativePath == "app/app.go" || relativePath == "app/ante.go" {
if relativePath == path.Join("app", "app.go") || relativePath == path.Join("app", "ante.go") {
fileContent = RemoveGeneralModule("globalfee", string(fileContent))
fileContent = RemoveGeneralModule("GlobalFee", string(fileContent))
}

if relativePath == "scripts/test_node.sh" {
if relativePath == path.Join("scripts", "test_node.sh") {
fileContent = RemoveGeneralModule("globalfee", string(fileContent))
}

Expand All @@ -341,13 +356,12 @@ func removeWasm(relativePath string, fileContent []byte) []byte {
// if strings.Contains(string(fileContent), "spawntag:wasm") {}
fileContent = RemoveTaggedLines("wasm", string(fileContent), true)

// TODO: tokenfactory depends on wasm currently.
if relativePath == "go.mod" || relativePath == "go.sum" {
fileContent = RemoveGoModImport("github.com/CosmWasm/wasmd", fileContent)
fileContent = RemoveGoModImport("github.com/CosmWasm/wasmvm", fileContent)
}

if relativePath == "app/app.go" || relativePath == "app/ante.go" {
if relativePath == path.Join("app", "app.go") || relativePath == path.Join("app", "ante.go") {
for _, w := range []string{
"WasmKeeper", "wasmtypes", "wasmStack",
"wasmOpts", "TXCounterStoreService", "WasmConfig",
Expand All @@ -358,45 +372,45 @@ func removeWasm(relativePath string, fileContent []byte) []byte {

}

if relativePath == "app/ante.go" {
if relativePath == path.Join("app", "ante.go") {
fileContent = RemoveGeneralModule("wasm", string(fileContent))
}

if relativePath == "app/encoding.go" {
if relativePath == path.Join("app", "encoding.go") {
fileContent = RemoveGeneralModule("wasmkeeper", string(fileContent))
}

if relativePath == "app/sim_test.go" {
if relativePath == path.Join("app", "sim_test.go") {
fileContent = RemoveGeneralModule("wasm", string(fileContent))
}

if relativePath == "app/app_test.go" {
if relativePath == path.Join("app", "app_test.go") {
fileContent = RemoveGeneralModule("wasmOpts", string(fileContent))
fileContent = RemoveGeneralModule("wasmkeeper", string(fileContent))
}

if relativePath == "app/test_support.go" {
if relativePath == path.Join("app", "test_support.go") {
fileContent = RemoveGeneralModule("wasm", string(fileContent))
}

if relativePath == "app/test_helpers.go" {
if relativePath == path.Join("app", "test_helpers.go") {
for _, w := range []string{"emptyWasmOptions", "wasmkeeper", "WasmOpts", "wasmOpts"} {
fileContent = RemoveGeneralModule(w, string(fileContent))
}

}

if relativePath == "app/wasm.go" {
if relativePath == path.Join("app", "wasm.go") {
fileContent = []byte("REMOVE")
}

if relativePath == "cmd/wasmd/commands.go" {
if relativePath == path.Join("cmd", "wasmd", "commands.go") {
for _, w := range []string{"wasm", "wasmOpts", "wasmcli", "wasmtypes"} {
fileContent = RemoveGeneralModule(w, string(fileContent))
}
}

if relativePath == "cmd/wasmd/root.go" {
if relativePath == path.Join("cmd", "wasmd", "root.go") {
for _, w := range []string{"wasmtypes", "wasmkeeper"} {
fileContent = RemoveGeneralModule(w, string(fileContent))
}
Expand Down
2 changes: 0 additions & 2 deletions cmd/spawn/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import (
// heighliner build latest.
// check if local-ic is found in path, if not, tell the user to download & move to their GOPATH (or do automatically)
// if local-ic is installed, call it here automatically

// TODO: maybe instead we just use local-ic directly? This could just be a builder for docker
var BuildAppImage = &cobra.Command{
Use: "docker-build",
Short: "Build Docker Image for your app",
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/schollz/progressbar/v3 v3.14.1
github.com/spf13/cobra v1.8.0
github.com/strangelove-ventures/simapp v0.0.0-00000000-000000000000
golang.org/x/text v0.14.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
13 changes: 12 additions & 1 deletion simapp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,15 @@ endif
### testnet ###
###############################################################################

testnet: install local-image
setup-testnet: install local-image
# import keys from testnet.json into test keyring
-`echo "decorate bright ozone fork gallery riot bus exhaust worth way bone indoor calm squirrel merry zero scheme cotton until shop any excess stage laundry" | wasmd keys add acc0 --recover`
-`echo "wealth flavor believe regret funny network recall kiss grape useless pepper cram hint member few certain unveil rather brick bargain curious require crowd raise" | wasmd keys add acc1 --recover`

testnet: setup-testnet
spawn local-ic start testnet

testnet-ibc: setup-testnet
spawn local-ic start ibc-testnet

.PHONY: testnet testnet-ibc
2 changes: 1 addition & 1 deletion simapp/app/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type HandlerOptions struct {

GlobalFeeKeeper globalfeekeeper.Keeper
BypassMinFeeMsgTypes []string
StakingKeeper stakingkeeper.Keeper // TODO: save the bond denom instead
StakingKeeper *stakingkeeper.Keeper // TODO: save the bond denom instead
}

// NewAnteHandler constructor
Expand Down
3 changes: 1 addition & 2 deletions simapp/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ import (

const appName = "WasmApp"

// We pull these out so we can set them with LDFLAGS in the Makefile
var (
NodeDir = ".wasmd"
Bech32Prefix = "wasm"
Expand Down Expand Up @@ -950,7 +949,7 @@ func NewChainApp(

GlobalFeeKeeper: app.GlobalFeeKeeper,
BypassMinFeeMsgTypes: GetDefaultBypassFeeMessages(), //spawntag:globalfee
StakingKeeper: *app.StakingKeeper, //spawntag:globalfee
StakingKeeper: app.StakingKeeper, //spawntag:globalfee
},
)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions simapp/chains/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Local Interchain Configurations

INSTALL: `spawn ...`

RUN: `ICTEST_HOME=. local-ic start testnet`
RUN:
- `make testnet` *(full setup: docker image, binary, keys, and testnet start)*
- `spawn local-ic start testnet` *(Standalone start)*

DOCS: TODO:

Expand Down
Loading

0 comments on commit e44cb5a

Please sign in to comment.