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: scaffold consumer chain #3660

Merged
merged 67 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
8c3c2a7
feat: add validation kind in config
tbruyelle Sep 12, 2023
d2a5840
Add consumer chain plush scaffolding
Ehsan-saradar Sep 28, 2023
456c28b
update config.yml when scaffold consumer chain
tbruyelle Sep 29, 2023
53334d0
Add hard-coded interchain-security require
Ehsan-saradar Oct 2, 2023
ceb336c
remove comment
tbruyelle Oct 2, 2023
f4a8bd6
fix bad merge go.sum
tbruyelle Nov 27, 2023
9051da1
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
Pantani Dec 1, 2023
d086c5f
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
Pantani Dec 1, 2023
7aea9a7
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
Pantani Dec 1, 2023
6d2cf9b
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Dec 12, 2023
ac59963
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
Pantani Dec 12, 2023
fface77
update ibc to v8
Dec 12, 2023
5208cd5
fix changelog
Dec 12, 2023
15bd86b
Merge remote-tracking branch 'origin/main' into tbruyelle/feat/scaffo…
Dec 12, 2023
66667ec
chore: update interchain-security dependency
tbruyelle Dec 13, 2023
96d38d1
update ccvconsumertypes -> ccvtypes
tbruyelle Dec 13, 2023
dabd4b6
templates: ibc-go/v7 -> ibc-go/v8
tbruyelle Dec 13, 2023
84d06da
fix imports
tbruyelle Dec 13, 2023
17cec4e
fix imports paths
tbruyelle Dec 13, 2023
04a5ef2
do not pass CapabilityKeeper in dep.Inject
tbruyelle Dec 15, 2023
fafe531
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
Ehsan-saradar Dec 19, 2023
5be47a9
Fix lint
Ehsan-saradar Dec 19, 2023
d277e47
fix: add missing ibcconsumer.AppModule (#3848)
Pantani Dec 19, 2023
fc85059
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Jan 10, 2024
8179040
remove ICS dep
tbruyelle Jan 19, 2024
7ce9281
wip exec plugin!
tbruyelle Jan 20, 2024
ee7e2fe
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Jan 21, 2024
33bf8f8
use plugin repo
tbruyelle Jan 22, 2024
134fd71
restore templates/app/files w/o IsConsumerChain condition
tbruyelle Jan 22, 2024
9c77232
create files-consumer alternate template folder
tbruyelle Jan 22, 2024
0e4f793
mark minimal and consumer flags as exclusive
tbruyelle Jan 24, 2024
0853ef6
fix wrong location for consumer_*.go files
tbruyelle Jan 24, 2024
3e026de
fix error handling for IsInitialized
tbruyelle Jan 24, 2024
75ddaf4
revert commit wip plugin exec
tbruyelle Jan 25, 2024
9b51e3e
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Jan 25, 2024
9898959
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Jan 26, 2024
b10e626
use plugin to read & write consumer module genesis
tbruyelle Jan 26, 2024
01d2748
fix linter
tbruyelle Jan 26, 2024
d618ab4
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Jan 31, 2024
46d345b
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Feb 1, 2024
d239f44
backport NFT module #3924 in files-consumer
tbruyelle Feb 1, 2024
66dd5c8
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
julienrbrt Feb 5, 2024
8799334
update app-consumer url
tbruyelle Feb 6, 2024
9ddcf9d
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Feb 7, 2024
32d56a5
move app-consumer address to ignite org
tbruyelle Feb 7, 2024
846852e
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
Pantani Feb 27, 2024
5aa59de
update CL
tbruyelle Feb 28, 2024
6c15e38
use new plugin location
tbruyelle Feb 28, 2024
608a647
use merged version of consumer app
tbruyelle Mar 5, 2024
8ec6987
fix(templates): fix interface check for ibc modules (#3995)
julienrbrt Mar 1, 2024
b4cf865
refactor!: remove oracle support (#3993)
julienrbrt Mar 1, 2024
87f63a9
add invite link to chat shield (#3998)
toschdev Mar 1, 2024
ced7e8c
docs(cli): update generated docs (#3984)
github-actions[bot] Mar 1, 2024
f3c2468
sync fixes
julienrbrt Mar 6, 2024
d8d112c
updates
julienrbrt Mar 7, 2024
4166fe3
fixes
julienrbrt Mar 7, 2024
9025f3a
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
julienrbrt Mar 7, 2024
7345c2f
changelog
julienrbrt Mar 7, 2024
1629c74
feedback
julienrbrt Mar 7, 2024
cc49790
fix linter
tbruyelle Mar 8, 2024
88c8a67
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Mar 8, 2024
275380e
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
tbruyelle Mar 11, 2024
fe06403
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
julienrbrt Mar 11, 2024
b31314b
update ante handlers
julienrbrt Mar 12, 2024
995627c
import
julienrbrt Mar 12, 2024
d70ad66
updates
julienrbrt Mar 12, 2024
9c12049
Merge branch 'main' into tbruyelle/feat/scaffold-consumer-chain
julienrbrt Mar 12, 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
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- [#3770](https://github.com/ignite/cli/pull/3770) Add `scaffold configs` and `scaffold params` commands
- [#3985](https://github.com/ignite/cli/pull/3985) Make some `cmd` pkg functions public
- [#3967](https://github.com/ignite/cli/issues/3967) Add HD wallet parameters `address index` and `account number` to the chain account config
- [#3660](https://github.com/ignite/cli/pull/3660) Add ability to scaffold ICS consumer chain
- [#4004](https://github.com/ignite/cli/pull/4004) Remove all import placeholders using the `xast` pkg

### Changes
Expand Down
20 changes: 20 additions & 0 deletions docs/docs/08-references/02-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,26 @@ to describe the development environment for your blockchain.
Only a default set of parameters is provided. If more nuanced configuration is
required, you can add these parameters to the `config.yml` file.

## Validation

Ignite uses the `validation` field to determine the kind of validation
of your blockchain. There are currently two supported kinds of validation:

- `sovereign` which is the standard kind of validation where your blockchain
has its own validator set. This is the default value when this field is not
in the config file.
- `consumer` indicates your blockchain is a consumer chain, in the sense of
Replicated Security. That means it doesn't have a validator set, but
inherits the one of a provider chain.

While the `sovereign` chain is the default validation when you run the `ignite scaffold
chain`, to scaffold a consumer chain, you have to run `ignite scaffold chain
--consumer`.

This field is, at this time of writing, only used by Ignite at the genesis
generation step, because the genesis of a sovereign chain and a consumer chain
are different.

## Accounts

A list of user accounts created during genesis of the blockchain.
Expand Down
10 changes: 8 additions & 2 deletions ignite/cmd/scaffold_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
flagMinimal = "minimal"
flagNoDefaultModule = "no-module"
flagSkipGit = "skip-git"
flagIsConsumer = "consumer"

tplScaffoldChainSuccess = `
⭐️ Successfully created a new blockchain '%[1]v'.
Expand Down Expand Up @@ -84,6 +85,9 @@
c.Flags().StringSlice(flagModuleConfigs, []string{}, "add module configs")
c.Flags().Bool(flagSkipGit, false, "skip Git repository initialization")
c.Flags().Bool(flagMinimal, false, "create a minimal blockchain (with the minimum required Cosmos SDK modules)")
c.Flags().Bool(flagIsConsumer, false, "scafffold an ICS consumer chain")
// Cannot have both minimal and consumer flag
c.MarkFlagsMutuallyExclusive(flagIsConsumer, flagMinimal)

Check warning on line 90 in ignite/cmd/scaffold_chain.go

View check run for this annotation

Codecov / codecov/patch

ignite/cmd/scaffold_chain.go#L88-L90

Added lines #L88 - L90 were not covered by tests
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved

return c
}
Expand All @@ -99,6 +103,7 @@
noDefaultModule, _ = cmd.Flags().GetBool(flagNoDefaultModule)
skipGit, _ = cmd.Flags().GetBool(flagSkipGit)
minimal, _ = cmd.Flags().GetBool(flagMinimal)
isConsumer, _ = cmd.Flags().GetBool(flagIsConsumer)

Check warning on line 106 in ignite/cmd/scaffold_chain.go

View check run for this annotation

Codecov / codecov/patch

ignite/cmd/scaffold_chain.go#L106

Added line #L106 was not covered by tests
params, _ = cmd.Flags().GetStringSlice(flagParams)
moduleConfigs, _ = cmd.Flags().GetStringSlice(flagModuleConfigs)
)
Expand All @@ -116,7 +121,7 @@
return err
}

appdir, err := scaffolder.Init(
appDir, err := scaffolder.Init(

Check warning on line 124 in ignite/cmd/scaffold_chain.go

View check run for this annotation

Codecov / codecov/patch

ignite/cmd/scaffold_chain.go#L124

Added line #L124 was not covered by tests
cmd.Context(),
cacheStorage,
placeholder.New(),
Expand All @@ -126,14 +131,15 @@
noDefaultModule,
skipGit,
minimal,
isConsumer,

Check warning on line 134 in ignite/cmd/scaffold_chain.go

View check run for this annotation

Codecov / codecov/patch

ignite/cmd/scaffold_chain.go#L134

Added line #L134 was not covered by tests
params,
moduleConfigs,
)
if err != nil {
return err
}

path, err := xfilepath.RelativePath(appdir)
path, err := xfilepath.RelativePath(appDir)

Check warning on line 142 in ignite/cmd/scaffold_chain.go

View check run for this annotation

Codecov / codecov/patch

ignite/cmd/scaffold_chain.go#L142

Added line #L142 was not covered by tests
if err != nil {
return err
}
Expand Down
36 changes: 29 additions & 7 deletions ignite/config/chain/base/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,29 @@
API string `yaml:"api"`
}

// Validation describes the kind of validation the chain has.
type Validation string

const (
// ValidationSovereign is when the chain has his own validator set.
// Note that an empty string is also considered as a sovereign validation,
// because this is the default value.
ValidationSovereign = "sovereign"
// ValidationConsumer is when the chain is validated by a provider chain.
// Such chain is called a consumer chain.
ValidationConsumer = "consumer"
)

// Config defines a struct with the fields that are common to all config versions.
type Config struct {
Version version.Version `yaml:"version"`
Build Build `yaml:"build,omitempty"`
Accounts []Account `yaml:"accounts"`
Faucet Faucet `yaml:"faucet,omitempty"`
Client Client `yaml:"client,omitempty"`
Genesis xyaml.Map `yaml:"genesis,omitempty"`
Minimal bool `yaml:"minimal,omitempty"`
Validation Validation `yaml:"validation,omitempty"`
jeronimoalbi marked this conversation as resolved.
Show resolved Hide resolved
Version version.Version `yaml:"version"`
Build Build `yaml:"build,omitempty"`
Accounts []Account `yaml:"accounts"`
Faucet Faucet `yaml:"faucet,omitempty"`
Client Client `yaml:"client,omitempty"`
Genesis xyaml.Map `yaml:"genesis,omitempty"`
Minimal bool `yaml:"minimal,omitempty"`
}

// GetVersion returns the config version.
Expand All @@ -174,6 +188,14 @@
return c.Minimal
}

func (c Config) IsSovereignChain() bool {
return c.Validation == "" || c.Validation == ValidationSovereign

Check warning on line 192 in ignite/config/chain/base/config.go

View check run for this annotation

Codecov / codecov/patch

ignite/config/chain/base/config.go#L191-L192

Added lines #L191 - L192 were not covered by tests
}

func (c Config) IsConsumerChain() bool {
return c.Validation == ValidationConsumer

Check warning on line 196 in ignite/config/chain/base/config.go

View check run for this annotation

Codecov / codecov/patch

ignite/config/chain/base/config.go#L195-L196

Added lines #L195 - L196 were not covered by tests
}

// SetDefaults assigns default values to empty config fields.
func (c *Config) SetDefaults() error {
return mergo.Merge(c, DefaultConfig())
Expand Down
39 changes: 39 additions & 0 deletions ignite/internal/plugin/consumer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package plugininternal

import (
"context"
"strconv"

"github.com/ignite/cli/v28/ignite/pkg/errors"
"github.com/ignite/cli/v28/ignite/services/plugin"
)

// TODO use released version of app-consumer.
const consumerPlugin = "github.com/ignite/apps/consumer"

// ConsumerWriteGenesis writes validators in the consumer module genesis.
// NOTE(tb): Using a plugin for this task avoids having the interchain-security
// dependency in Ignite.
func ConsumerWriteGenesis(ctx context.Context, c plugin.Chainer) error {
_, err := Execute(ctx, consumerPlugin, []string{"writeGenesis"}, plugin.WithChain(c))
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return errors.Errorf("execute consumer plugin 'writeGenesis': %w", err)
}
return nil

Check warning on line 22 in ignite/internal/plugin/consumer.go

View check run for this annotation

Codecov / codecov/patch

ignite/internal/plugin/consumer.go#L17-L22

Added lines #L17 - L22 were not covered by tests
}

// ConsumerIsInitialized returns true if the consumer chain's genesis c has
// a consumer module entry with an initial validator set.
// NOTE(tb): Using a plugin for this task avoids having the interchain-security
// dependency in Ignite.
func ConsumerIsInitialized(ctx context.Context, c plugin.Chainer) (bool, error) {
out, err := Execute(ctx, consumerPlugin, []string{"isInitialized"}, plugin.WithChain(c))
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return false, errors.Errorf("execute consumer plugin 'isInitialized': %w", err)
}
b, err := strconv.ParseBool(out)
if err != nil {
return false, errors.Errorf("invalid consumer plugin 'isInitialized' output, got '%s': %w", out, err)
}
return b, nil

Check warning on line 38 in ignite/internal/plugin/consumer.go

View check run for this annotation

Codecov / codecov/patch

ignite/internal/plugin/consumer.go#L29-L38

Added lines #L29 - L38 were not covered by tests
}
134 changes: 134 additions & 0 deletions ignite/internal/plugin/consumer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package plugininternal

import (
"context"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"

"github.com/ignite/cli/v28/ignite/services/plugin"
"github.com/ignite/cli/v28/ignite/services/plugin/mocks"
)

func TestConsumerPlugin(t *testing.T) {
tests := []struct {
name string
args []string
setup func(*testing.T, string)
expectedOutput string
expectedError string
}{
{
name: "fail: missing arg",
expectedError: "missing argument",
},
{
name: "fail: invalid arg",
args: []string{"xxx"},
expectedError: "invalid argument \"xxx\"",
},
{
name: "fail: writeGenesis w/o priv_validator_key.json",
args: []string{"writeGenesis"},
expectedError: "open .*/config/priv_validator_key.json: no such file or directory",
},
{
name: "fail: writeFenesis w/o genesis.json",
args: []string{"writeGenesis"},
setup: func(t *testing.T, path string) {
// Add priv_validator_key.json to path
bz, err := os.ReadFile("testdata/consumer/config/priv_validator_key.json")
require.NoError(t, err)
err = os.WriteFile(filepath.Join(path, "config", "priv_validator_key.json"), bz, 0o777)
require.NoError(t, err)
},
expectedError: ".*/config/genesis.json does not exist, run `init` first",
},

{
name: "ok: writeGenesis",
args: []string{"writeGenesis"},
setup: func(t *testing.T, path string) {
// Add priv_validator_key.json to path
bz, err := os.ReadFile("testdata/consumer/config/priv_validator_key.json")
require.NoError(t, err)
err = os.WriteFile(filepath.Join(path, "config", "priv_validator_key.json"), bz, 0o777)
require.NoError(t, err)

// Add genesis.json to path
bz, err = os.ReadFile("testdata/consumer/config/genesis.json")
require.NoError(t, err)
err = os.WriteFile(filepath.Join(path, "config", "genesis.json"), bz, 0o777)
require.NoError(t, err)
},
},
{
name: "ok: isInitialized returns false",
args: []string{"isInitialized"},
expectedOutput: "false",
},
{
name: "ok: isInitialized returns true",
args: []string{"isInitialized"},
setup: func(t *testing.T, path string) {
// isInitialized returns true if there's a consumer genesis with an
// InitialValSet length != 0
// Add priv_validator_key.json to path
bz, err := os.ReadFile("testdata/consumer/config/priv_validator_key.json")
require.NoError(t, err)
err = os.WriteFile(filepath.Join(path, "config", "priv_validator_key.json"), bz, 0o777)
require.NoError(t, err)

// Add genesis.json to path
bz, err = os.ReadFile("testdata/consumer/config/genesis.json")
require.NoError(t, err)
err = os.WriteFile(filepath.Join(path, "config", "genesis.json"), bz, 0o777)
require.NoError(t, err)

// Call writeGenesis to create the genesis
chainer := mocks.NewChainerInterface(t)
chainer.EXPECT().ID().Return("id", nil).Maybe()
chainer.EXPECT().AppPath().Return("apppath").Maybe()
chainer.EXPECT().ConfigPath().Return("configpath").Maybe()
chainer.EXPECT().Home().Return(path, nil).Maybe()
chainer.EXPECT().RPCPublicAddress().Return("rpcPublicAddress", nil).Maybe()
_, err = Execute(context.Background(), consumerPlugin, []string{"writeGenesis"}, plugin.WithChain(chainer))
require.NoError(t, err)
},
expectedOutput: "true",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
homePath := t.TempDir()
err := os.MkdirAll(filepath.Join(homePath, "config"), 0o777)
require.NoError(t, err)
chainer := mocks.NewChainerInterface(t)
chainer.EXPECT().ID().Return("id", nil).Maybe()
chainer.EXPECT().AppPath().Return("apppath").Maybe()
chainer.EXPECT().ConfigPath().Return("configpath").Maybe()
chainer.EXPECT().Home().Return(homePath, nil).Maybe()
chainer.EXPECT().RPCPublicAddress().Return("rpcPublicAddress", nil).Maybe()
if tt.setup != nil {
tt.setup(t, homePath)
}

out, err := Execute(
context.Background(),
consumerPlugin,
tt.args,
plugin.WithChain(chainer),
)

if tt.expectedError != "" {
require.Error(t, err)
require.Regexp(t, tt.expectedError, err.Error())
return
}
require.NoError(t, err)
require.Equal(t, tt.expectedOutput, out)
})
}
}
18 changes: 9 additions & 9 deletions ignite/internal/plugin/execute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@ import (

func TestPluginExecute(t *testing.T) {
tests := []struct {
name string
pluginPath string
expectedOut string
expectedError string
name string
pluginPath string
expectedOutput string
expectedError string
}{
{
name: "fail: plugin doesnt exist",
pluginPath: "/not/exists",
expectedError: "local app path \"/not/exists\" not found: stat /not/exists: no such file or directory",
},
{
name: "ok: plugin execute ok ",
pluginPath: "testdata/execute_ok",
expectedOut: "ok args=[arg1 arg2] chainid=id appPath=apppath configPath=configpath home=home rpcAddress=rpcPublicAddress\n",
name: "ok: plugin execute ok",
pluginPath: "testdata/execute_ok",
expectedOutput: "ok args=[arg1 arg2] chainid=id appPath=apppath configPath=configpath home=home rpcAddress=rpcPublicAddress\n",
},
{
name: "ok: plugin execute fail ",
name: "ok: plugin execute fail",
pluginPath: "testdata/execute_fail",
expectedError: "fail",
},
Expand Down Expand Up @@ -64,7 +64,7 @@ func TestPluginExecute(t *testing.T) {
return
}
require.NoError(t, err)
require.Equal(t, tt.expectedOut, out)
require.Equal(t, tt.expectedOutput, out)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"app_name": "test",
"app_version": "",
"genesis_time": "2024-01-19T10:27:44.742750573Z",
"chain_id": "test",
"initial_height": 1,
"app_hash": null,
"app_state": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"address": "2D3C15095E5EAA318CAEDE1C2D02C77581584751",
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "uBOT+dDuUvXjJrkfwMNrS4bRT4/O+fBnpwfYpR6n1Wk="
},
"priv_key": {
"type": "tendermint/PrivKeyEd25519",
"value": "HovIzTJTGMrQx5oBikjfypyMZYF9QP5MxS+S+S/3QYq4E5P50O5S9eMmuR/Aw2tLhtFPj8758GenB9ilHqfVaQ=="
}
}
Loading
Loading