Skip to content

Commit

Permalink
feat: add cli and setup script update (#47)
Browse files Browse the repository at this point in the history
* add cli and setup script update

* fix to use l2 at tx broadcasting

* add Readme

* disallow bridge id/addr change

---------

Co-authored-by: JSHan94 <saw151515@gmail.com>
  • Loading branch information
beer-1 and JSHan94 authored Apr 9, 2024
1 parent be4ff5b commit b1905ec
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 15 deletions.
1 change: 1 addition & 0 deletions bots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { MsgCreateBridge, BridgeConfig, Duration } from '@initia/initia.js';
const bridgeConfig = new BridgeConfig(
challenger.key.accAddress,
outputSubmitter.key.accAddress,
new BatchInfo(batchSubmitter.accAddress, config.PUBLISH_BATCH_TARGET),
Duration.fromString(submissionInterval.toString()),
Duration.fromString(finalizedTime.toString()),
new Date(),
Expand Down
24 changes: 12 additions & 12 deletions bots/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bots/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
},
"homepage": "https://github.com/initia-labs/batch-submitter#readme",
"devDependencies": {
"@initia/initia.js": "^0.1.41",
"@initia/initia.js": "^0.1.43",
"@koa/cors": "^5.0.0",
"@sentry/node": "^7.109.0",
"@testcontainers/postgresql": "^10.8.1",
Expand Down
51 changes: 49 additions & 2 deletions bots/src/scripts/setupL2.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { MsgCreateBridge, BridgeConfig, Duration, Wallet, MnemonicKey } from '@initia/initia.js';
import {
MsgCreateBridge,
BridgeConfig,
BatchInfo,
Duration,
Wallet,
MnemonicKey,
BridgeInfo,
MsgSetBridgeInfo
} from '@initia/initia.js';
import { sendTx } from 'lib/tx';
import { config } from 'config';

export const executor = new Wallet(
config.l1lcd,
new MnemonicKey({ mnemonic: config.EXECUTOR_MNEMONIC })
);
export const executorL2 = new Wallet(
config.l2lcd,
new MnemonicKey({ mnemonic: config.EXECUTOR_MNEMONIC })
);
export const challenger = new Wallet(
config.l1lcd,
new MnemonicKey({ mnemonic: config.CHALLENGER_MNEMONIC })
Expand All @@ -14,6 +27,9 @@ export const outputSubmitter = new Wallet(
config.l1lcd,
new MnemonicKey({ mnemonic: config.OUTPUT_SUBMITTER_MNEMONIC })
);
export const batchSubmitter = new MnemonicKey({
mnemonic: config.BATCH_SUBMITTER_MNEMONIC
});

class L2Initializer {
bridgeId = config.BRIDGE_ID;
Expand All @@ -28,6 +44,7 @@ class L2Initializer {
const bridgeConfig = new BridgeConfig(
challenger.key.accAddress,
outputSubmitter.key.accAddress,
new BatchInfo(batchSubmitter.accAddress, config.PUBLISH_BATCH_TARGET),
Duration.fromString(submissionInterval.toString()),
Duration.fromString(finalizedTime.toString()),
new Date(),
Expand All @@ -36,12 +53,42 @@ class L2Initializer {
return new MsgCreateBridge(executor.key.accAddress, bridgeConfig);
}

MsgSetBridgeInfo(bridgeInfo: BridgeInfo) {
return new MsgSetBridgeInfo(executorL2.key.accAddress, bridgeInfo);
}

async initialize() {
const msgs = [
this.MsgCreateBridge(this.submissionInterval, this.finalizedTime)
];

await sendTx(executor, msgs);
const txRes = await sendTx(executor, msgs);

// load bridge info from l1 chain and send to l2 chain
let bridgeID = 0;
const txInfo = await config.l1lcd.tx.txInfo(txRes.txhash);
for (const e of txInfo.events) {
if (e.type !== "create_bridge") {
continue
}

for (const attr of e.attributes) {
if (attr.key !== "bridge_id") {
continue
}

bridgeID = parseInt(attr.value, 10)
}

break
}

const bridgeInfo = await config.l1lcd.ophost.bridgeInfo(bridgeID);
const l2Msgs = [
this.MsgSetBridgeInfo(bridgeInfo)
];

await sendTx(executorL2, l2Msgs);
}
}

Expand Down
106 changes: 106 additions & 0 deletions x/opchild/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package cli

import (
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"time"

"cosmossdk.io/core/address"
"github.com/spf13/cobra"
Expand All @@ -13,7 +16,10 @@ import (
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"

"github.com/initia-labs/OPinit/x/opchild/types"
ophostcli "github.com/initia-labs/OPinit/x/ophost/client/cli"
ophosttypes "github.com/initia-labs/OPinit/x/ophost/types"
)

// GetTxCmd returns a root CLI command handler for all x/opchild transaction commands.
Expand All @@ -30,6 +36,7 @@ func GetTxCmd(ac address.Codec) *cobra.Command {
NewExecuteMessagesCmd(ac),
NewDepositCmd(ac),
NewWithdrawCmd(ac),
NewSetBridgeInfoCmd(ac),
)

return opchildTxCmd
Expand Down Expand Up @@ -202,6 +209,105 @@ Where proposal.json contains:
return cmd
}

// NewSetBridgeInfoCmd returns a CLI command handler for transaction to setting a bridge info.
func NewSetBridgeInfoCmd(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "set-bridge-info [bridge-id] [bridge-addr] [path/to/bridge-config.json]",
Short: "send a bridge creating tx",
Long: strings.TrimSpace(
fmt.Sprintf(
`send a tx to set a bridge info with a config file as a json.
Example:
$ %s tx ophost set-bridge-info 1 init10d07y265gmmuvt4z0w9aw880jnsr700j55nka3 path/to/bridge-config.json
Where bridge-config.json contains:
{
"challenger": "bech32-address",
"proposer": "bech32-addresss",
"submission_interval": "duration",
"finalization_period": "duration",
"submission_start_time" : "rfc3339-datetime",
"batch_info": {"submitter": "bech32-address","chain": "l1|celestia"},
"metadata": "{\"perm_channels\":[{\"port_id\":\"transfer\", \"channel_id\":\"channel-0\"}, {\"port_id\":\"icqhost\", \"channel_id\":\"channel-1\"}]}"
}`, version.AppName,
),
),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

bridgeId, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}

bridgeAddr := args[1]

configBytes, err := os.ReadFile(args[2])
if err != nil {
return err
}

origConfig := ophostcli.BridgeConfig{}
err = json.Unmarshal(configBytes, &origConfig)
if err != nil {
return err
}

submissionInterval, err := time.ParseDuration(origConfig.SubmissionInterval)
if err != nil {
return err
}

finalizationPeriod, err := time.ParseDuration(origConfig.FinalizationPeriod)
if err != nil {
return err
}

submissionStartTime, err := time.Parse(time.RFC3339, origConfig.SubmissionStartTime)
if err != nil {
return err
}

bridgeConfig := ophosttypes.BridgeConfig{
Challenger: origConfig.Challenger,
Proposer: origConfig.Proposer,
SubmissionInterval: submissionInterval,
FinalizationPeriod: finalizationPeriod,
SubmissionStartTime: submissionStartTime,
BatchInfo: origConfig.BatchInfo,
Metadata: []byte(origConfig.Metadata),
}
if err = bridgeConfig.ValidateWithNoAddrValidation(); err != nil {
return err
}

fromAddr, err := ac.BytesToString(clientCtx.GetFromAddress())
if err != nil {
return err
}

msg := types.NewMsgSetBridgeInfo(fromAddr, types.BridgeInfo{
BridgeId: bridgeId,
BridgeAddr: bridgeAddr,
BridgeConfig: bridgeConfig,
})
if err = msg.Validate(ac); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

func newBuildWithdrawMsg(clientCtx client.Context, ac address.Codec, txf tx.Factory, to sdk.AccAddress, amount sdk.Coin) (tx.Factory, *types.MsgInitiateTokenWithdrawal, error) {
sender := clientCtx.GetFromAddress()
senderAddr, err := ac.BytesToString(sender)
Expand Down
83 changes: 83 additions & 0 deletions x/opchild/client/cli/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
"os"
"testing"

"cosmossdk.io/core/address"
Expand Down Expand Up @@ -404,6 +405,88 @@ func (s *CLITestSuite) TestNewExecuteMessagesCmd() {
}
}

func (s *CLITestSuite) TestNewSetBridgeInfo() {
require := s.Require()
cmd := cli.NewSetBridgeInfoCmd(s.ac)

addr0, err := s.ac.BytesToString(s.addrs[0])
s.NoError(err)

invalidConfig, err := os.CreateTemp("/tmp", "bridge_config")
require.NoError(err)
defer os.Remove(invalidConfig.Name())
validConfig, err := os.CreateTemp("/tmp", "bridge_config")
require.NoError(err)
defer os.Remove(validConfig.Name())

invalidConfig.WriteString(`{}`)
validConfig.WriteString(`{
"challenger": "init1q6jhwnarkw2j5qqgx3qlu20k8nrdglft5ksr0g",
"proposer": "init1k2svyvm60r8rhnzr9vemk5f6fksvm6tyeujp3c",
"submission_interval": "100s",
"finalization_period": "1000s",
"submission_start_time" : "2023-12-01T00:00:00Z",
"metadata": "channel-0",
"batch_info": {
"submitter": "init1q6jhwnarkw2j5qqgx3qlu20k8nrdglft5ksr0g",
"chain": "l1"
}
}`)

testCases := []struct {
name string
args []string
expectErr bool
expectedCode uint32
respType proto.Message
}{
{
"invalid transaction (invalid bridge config)",
[]string{
"1",
"init1q6jhwnarkw2j5qqgx3qlu20k8nrdglft5ksr0g",
invalidConfig.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, addr0),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))).String()),
},
true, 0, &sdk.TxResponse{},
},
{
"valid transaction",
[]string{
"1",
"init1q6jhwnarkw2j5qqgx3qlu20k8nrdglft5ksr0g",
validConfig.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, addr0),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))).String()),
},
false, 0, &sdk.TxResponse{},
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
require.Error(err)
} else {
require.NoError(err, "test: %s\noutput: %s", tc.name, out.String())
err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType)
require.NoError(err, out.String(), "test: %s, output\n:", tc.name, out.String())

txResp := tc.respType.(*sdk.TxResponse)
require.Equal(tc.expectedCode, txResp.Code,
"test: %s, output\n:", tc.name, out.String())
}
})
}
}

func TestCLITestSuite(t *testing.T) {
suite.Run(t, new(CLITestSuite))
}
Loading

0 comments on commit b1905ec

Please sign in to comment.