Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cosmwasm official app #60

Merged
merged 30 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6088965
Initialized with Ignite CLI
Feb 8, 2024
5960000
add wasm commands
Feb 9, 2024
90caab4
scaffold chain wasm
Feb 9, 2024
f74cd11
remove wasm* from gitignore
Feb 9, 2024
fc642ec
use chain into the scaffold struct
Feb 10, 2024
7c67fcb
add config command
Feb 10, 2024
ba117be
fix client genesis
Feb 10, 2024
a65321b
format code
Feb 10, 2024
1db1795
add tests without test cases
Feb 10, 2024
a252c1a
add some test cases
Feb 10, 2024
603e4fa
add test cases for the goanalysis package
Feb 10, 2024
48462d0
add comments
Feb 10, 2024
6ea09e9
remove unused file
Feb 10, 2024
1132995
remove duplicated .gitignore
Feb 10, 2024
26bff4b
add wasm integration verification
Feb 10, 2024
333491e
add integration tests
Feb 14, 2024
0cb7c95
Update official/wasm/pkg/goanalysis/goanalysis.go
Pantani Feb 16, 2024
32c4c05
Update official/wasm/services/scaffolder/wasm.go
Pantani Feb 16, 2024
923a06f
Update official/wasm/cmd/config.go
Pantani Feb 16, 2024
e36ac42
Update official/wasm/main.go
Pantani Feb 16, 2024
b4642c2
Update official/wasm/go.mod
Pantani Feb 16, 2024
c67b018
Update official/wasm/pkg/config/config_test.go
Pantani Feb 16, 2024
7f55ba0
Merge remote-tracking branch 'origin/main' into feat/cosmwasm-officia…
Feb 16, 2024
50ea09d
usa github.com/ignite/apps/wasm namespace instead only wasm
Feb 16, 2024
6358fe2
apply some comments suggestions
Feb 16, 2024
6d2795e
Merge remote-tracking branch 'origin/main' into feat/cosmwasm-officia…
Feb 16, 2024
518ecf2
run go mod tidy
Feb 16, 2024
4e9b9dd
add configurable wasm version
Feb 21, 2024
d2c8546
add readme
Feb 22, 2024
04dd588
Update wasm/README.md
Pantani Feb 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions wasm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Wasm

`wasm` is an app developed for [Ignite CLI](https://github.com/ignite/cli).

The app adds `ignite wasm` commands to add a [CosmWasm](https://cosmwasm.com/) integration into a chain.

## How to use

- Install the Wasm app:
```shell
ignite app install -g github.com/ignite/apps/wasm
```

- You must scaffold a new chain with version `v28.2.1` or greater. Or migrate your chain using the [Ignite migration guides](https://docs.ignite.com/migration).

- Now you can add a Wasm support to your chain by running this command into the chain directory:
```shell
ignite wasm add
```

- The command will automatically add the Wasm integration into your code and the Wasm config into your chain config. But if your chain is not initiated yet, the chain config does not exist, so you need to add the Wasm config later running:
```shell
ignite wasm add
```

_All commands should be run in the chain directory._

Pantani marked this conversation as resolved.
Show resolved Hide resolved
## Developer instruction

- clone this repo locally
- Run `ignite app add -g /absolute/path/to/app/wasm` to add the app to global config
- `ignite wasm` command is now available with the local version of the app.

Then repeat the following loop:

- Hack on the app code
- Rerun `ignite wasm` to recompile the app and test
77 changes: 77 additions & 0 deletions wasm/cmd/add.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package cmd

import (
"github.com/blang/semver/v4"
"github.com/ignite/cli/v28/ignite/pkg/cliui"
"github.com/ignite/cli/v28/ignite/pkg/placeholder"
"github.com/ignite/cli/v28/ignite/services/chain"
"github.com/spf13/cobra"

"github.com/ignite/apps/wasm/services/scaffolder"
)

// NewWasmAdd add wasm integration to a chain.
func NewWasmAdd() *cobra.Command {
c := &cobra.Command{
Use: "add",
Short: "Add wasm support",
Args: cobra.NoArgs,
RunE: wasmAddExecuteHandler,
}

flagSetPath(c)
flagSetHome(c)
flagSetWasmConfigs(c)
flagSetWasmVersion(c)

return c
}

func wasmAddExecuteHandler(cmd *cobra.Command, args []string) error {
session := cliui.New(cliui.StartSpinnerWithText(statusScaffolding))
defer session.End()

var (
simulationGasLimit = getSimulationGasLimit(cmd)
smartQueryGasLimit = getSmartQueryGasLimit(cmd)
memoryCacheSize = getMemoryCacheSize(cmd)
wasmVersion = getWasmVersion(cmd)
)

wasmSemVer, err := semver.Parse(wasmVersion)
if err != nil {
return err
}

c, err := newChainWithHomeFlags(cmd, chain.WithOutputer(session), chain.CollectEvents(session.EventBus()))
if err != nil {
return err
}

sc, err := scaffolder.New(c, session)
if err != nil {
return err
}

sm, err := sc.AddWasm(
cmd.Context(),
placeholder.New(),
scaffolder.WithWasmVersion(wasmSemVer),
scaffolder.WithSimulationGasLimit(simulationGasLimit),
scaffolder.WithSmartQueryGasLimit(smartQueryGasLimit),
scaffolder.WithMemoryCacheSize(memoryCacheSize),
)
if err != nil {
return err
}

modificationsStr, err := sourceModificationToString(sm)
if err != nil {
return err
}

session.Println(modificationsStr)
session.Printf("\n🎉 CosmWasm added (`%[1]v`).\n\n", c.AppPath())

return nil
}
161 changes: 161 additions & 0 deletions wasm/cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package cmd

import (
"os"
"path/filepath"
"sort"
"strings"

"github.com/ignite/cli/v28/ignite/pkg/cliui/colors"
"github.com/ignite/cli/v28/ignite/pkg/xgenny"
"github.com/ignite/cli/v28/ignite/services/chain"
"github.com/spf13/cobra"
)

// NewWasm creates a new wasm command that holds
// some other sub commands related to CosmWasm.
func NewWasm() *cobra.Command {
c := &cobra.Command{
Use: "wasm [command]",
Aliases: []string{"w"},
Short: "Ignite wasm integration",
SilenceUsage: true,
SilenceErrors: true,
}

// add sub commands.
c.AddCommand(
NewWasmAdd(),
NewWasmConfig(),
)
return c
}

const (
flagPath = "path"
flagHome = "home"
flagVersion = "version"

statusScaffolding = "Scaffolding..."
statusAddingConfig = "Adding config..."

defaultWasmVersion = "v0.50.0"
)

var (
modifyPrefix = colors.Modified("modify ")
createPrefix = colors.Success("create ")
removePrefix = func(s string) string {
return strings.TrimPrefix(strings.TrimPrefix(s, modifyPrefix), createPrefix)
}
)

func flagSetPath(cmd *cobra.Command) {
cmd.Flags().StringP(flagPath, "p", ".", "path of the app")
}

func flagSetHome(cmd *cobra.Command) {
cmd.Flags().String(flagHome, "", "directory where the blockchain node is initialized")
}

func flagSetWasmVersion(cmd *cobra.Command) {
cmd.Flags().String(flagVersion, defaultWasmVersion, "wasmd semantic version")
}

func flagSetWasmConfigs(cmd *cobra.Command) {
cmd.Flags().Uint64(flagSimulationGasLimit, 0, "the max gas to be used in a tx simulation call. When not set the consensus max block gas is used instead")
cmd.Flags().Uint64(flagSmartQueryGasLimit, 3_000_000, "the max gas to be used in a smart query contract call")
cmd.Flags().Uint64(flagMemoryCacheSize, 100, "memory cache size in MiB not bytes")
}

func getPath(cmd *cobra.Command) string {
path, _ := cmd.Flags().GetString(flagPath)
return path
}

func getHome(cmd *cobra.Command) string {
home, _ := cmd.Flags().GetString(flagHome)
return home
}

func getWasmVersion(cmd *cobra.Command) string {
version, _ := cmd.Flags().GetString(flagVersion)
version = strings.Replace(version, "v", "", 1)
return version
}

func getSimulationGasLimit(cmd *cobra.Command) uint64 {
simulationGasLimit, _ := cmd.Flags().GetUint64(flagSimulationGasLimit)
return simulationGasLimit
}

func getSmartQueryGasLimit(cmd *cobra.Command) uint64 {
smartQueryGasLimit, _ := cmd.Flags().GetUint64(flagSmartQueryGasLimit)
return smartQueryGasLimit
}

func getMemoryCacheSize(cmd *cobra.Command) uint64 {
memoryCacheSize, _ := cmd.Flags().GetUint64(flagMemoryCacheSize)
return memoryCacheSize
}

// newChainWithHomeFlags create new *chain.Chain with home and path flags.
func newChainWithHomeFlags(cmd *cobra.Command, chainOption ...chain.Option) (*chain.Chain, error) {
// Check if custom home is provided
if home := getHome(cmd); home != "" {
chainOption = append(chainOption, chain.HomePath(home))
}

appPath := getPath(cmd)
absPath, err := filepath.Abs(appPath)
if err != nil {
return nil, err
}

return chain.New(absPath, chainOption...)
}

// sourceModificationToString output the modifications into a readable text.
func sourceModificationToString(sm xgenny.SourceModification) (string, error) {
// get file names and add prefix
var files []string
for _, modified := range sm.ModifiedFiles() {
// get the relative app path from the current directory
relativePath, err := relativePath(modified)
if err != nil {
return "", err
}
files = append(files, modifyPrefix+relativePath)
}
for _, created := range sm.CreatedFiles() {
// get the relative app path from the current directory
relativePath, err := relativePath(created)
if err != nil {
return "", err
}
files = append(files, createPrefix+relativePath)
}

// sort filenames without prefix
sort.Slice(files, func(i, j int) bool {
s1 := removePrefix(files[i])
s2 := removePrefix(files[j])

return strings.Compare(s1, s2) == -1
})

return "\n" + strings.Join(files, "\n"), nil
}

// relativePath return the relative app path from the current directory.
func relativePath(appPath string) (string, error) {
pwd, err := os.Getwd()
if err != nil {
return "", err
}
path, err := filepath.Rel(pwd, appPath)
if err != nil {
return "", err
}
return path, nil
}
46 changes: 46 additions & 0 deletions wasm/cmd/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cmd

import (
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
)

func Test_relativePath(t *testing.T) {
tests := []struct {
name string
appPath string
want string
}{
{
name: "Relative path within current directory",
appPath: "subdir/file.txt",
want: "subdir/file.txt",
},
{
name: "Relative path outside current directory",
appPath: "/path/file.txt",
want: "../../../../../../../../../../../path/file.txt",
},
{
name: "App path is current directory",
appPath: ".",
want: ".",
},
{
name: "App path is parent directory",
appPath: "..",
want: "..",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
absPath, err := filepath.Abs(tt.appPath)
require.NoError(t, err)
got, err := relativePath(absPath)
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
71 changes: 71 additions & 0 deletions wasm/cmd/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package cmd

import (
"os"

"github.com/ignite/cli/v28/ignite/pkg/cliui"
"github.com/ignite/cli/v28/ignite/pkg/errors"
"github.com/ignite/cli/v28/ignite/services/chain"
"github.com/spf13/cobra"

"github.com/ignite/apps/wasm/pkg/config"
)

const (
// flagSimulationGasLimit is the max gas to be used in a tx simulation call.
// When not set the consensus max block gas is used instead
flagSimulationGasLimit = "simulation-gas-limit"
// flagSmartQueryGasLimit is the max gas to be used in a smart query contract call
flagSmartQueryGasLimit = "query-gas-limit"
// flagMemoryCacheSize in MiB not bytes
flagMemoryCacheSize = "memory-cache-size"
)

// NewWasmConfig add wasm config to a chain.
func NewWasmConfig() *cobra.Command {
c := &cobra.Command{
Use: "config",
Short: "Add wasm config support",
Args: cobra.NoArgs,
RunE: wasmConfigExecuteHandler,
}

flagSetPath(c)
flagSetHome(c)
flagSetWasmConfigs(c)

return c
}

func wasmConfigExecuteHandler(cmd *cobra.Command, args []string) error {
session := cliui.New(cliui.StartSpinnerWithText(statusAddingConfig))
defer session.End()

var (
simulationGasLimit = getSimulationGasLimit(cmd)
smartQueryGasLimit = getSmartQueryGasLimit(cmd)
memoryCacheSize = getMemoryCacheSize(cmd)
)

c, err := newChainWithHomeFlags(cmd, chain.WithOutputer(session), chain.CollectEvents(session.EventBus()))
if err != nil {
return err
}

configTOML, err := c.ConfigTOMLPath()
if _, err := os.Stat(configTOML); os.IsNotExist(err) {
return errors.Errorf("chain %s not initialized yet (%s)", c.Name(), c.AppPath())
}

if err := config.AddWasm(
configTOML,
config.WithSimulationGasLimit(simulationGasLimit),
config.WithSmartQueryGasLimit(smartQueryGasLimit),
config.WithMemoryCacheSize(memoryCacheSize),
); err != nil {
return err
}
session.Printf("\n🎉 CosmWasm config added at `%[1]v`.\n\n", configTOML)

return nil
}
Loading
Loading