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/tx update batch info #74

Merged
merged 6 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 28 additions & 0 deletions BatchUpdateGuide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# UpdateBatchInfo
Follow the steps below.
### Step 1. Register the key for the new batch submitter address.
`opinitd keys add mocha-4 batch --bech32=celestia`

*Make sure that this new account has a sufficient balance.*

### Step 2. Run the Update batch info command.
`opinitd tx update-batch-info CELESTIA celestia...`

The proposer sends a transaction that includes an update batch info message with the new `ChainType` and `SubmitterAddress`. The bot will `shut down` when it encounters the `MsgUpdateBatchInfo`.

### Step 3. Update the DA node config in the executor config.
```json
{
...
"da_node": {
"chain_id": "mocha-4",
"bech32_prefix": "celestia",
"rpc_address": "",
"gas_price": "",
"gas_adjustment": 1.5,
"tx_timeout": 60
}
}
```

### Step 4. Start the OPInit bot.
150 changes: 148 additions & 2 deletions cmd/opinitd/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"strings"

"cosmossdk.io/errors"
"github.com/spf13/cobra"
Expand All @@ -23,6 +24,9 @@ import (
"github.com/initia-labs/opinit-bots/provider/child"
"github.com/initia-labs/opinit-bots/types"

opchildtypes "github.com/initia-labs/OPinit/x/opchild/types"
ophosttypes "github.com/initia-labs/OPinit/x/ophost/types"

sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand All @@ -35,6 +39,7 @@ func txCmd(ctx *cmdContext) *cobra.Command {

cmd.AddCommand(
txGrantOracleCmd(ctx),
txUpdateBatchInfoCmd(ctx),
)
return cmd
}
Expand All @@ -54,7 +59,12 @@ func txGrantOracleCmd(baseCtx *cmdContext) *cobra.Command {
baseCtx := types.NewContext(ctx, baseCtx.logger.Named(string(bottypes.BotTypeExecutor)), baseCtx.homePath).
WithErrGrp(errGrp)

account, err := l2BroadcasterAccount(baseCtx, cmd)
cfg, err := getExecutorConfig(baseCtx, cmd)
if err != nil {
return err
}

account, err := l2BroadcasterAccount(baseCtx, cfg)
if err != nil {
return err
}
Expand Down Expand Up @@ -107,7 +117,94 @@ func txGrantOracleCmd(baseCtx *cmdContext) *cobra.Command {
return cmd
}

func l2BroadcasterAccount(ctx types.Context, cmd *cobra.Command) (*broadcaster.BroadcasterAccount, error) {
func txUpdateBatchInfoCmd(baseCtx *cmdContext) *cobra.Command {
cmd := &cobra.Command{
Use: "update-batch-info [chain-type] [new-submitter-address]",
Args: cobra.ExactArgs(2),
Short: "Update batch info with new chain type and new submitter address",
Long: `Update batch info with new chain type and new submitter address.
Before running this command, you need to
(1) register a new key for the new submitter address
(2) update the DA configuration in the executor config.
`,
RunE: func(cmd *cobra.Command, args []string) error {
cmdCtx, botDone := context.WithCancel(cmd.Context())
gracefulShutdown(botDone)

errGrp, ctx := errgroup.WithContext(cmdCtx)

baseCtx := types.NewContext(ctx, baseCtx.logger.Named(string(bottypes.BotTypeExecutor)), baseCtx.homePath).
WithErrGrp(errGrp)

cfg, err := getExecutorConfig(baseCtx, cmd)
if err != nil {
return err
}

chainType := args[0]
newSubmitterAddress := args[1]

err = validateBatchInfoArgs(chainType)
if err != nil {
return err
}

bridgeId, err := QueryBridgeId(baseCtx, cfg)
if err != nil {
return err
}

proposerAccount, err := l1ProposerAccount(baseCtx, cfg, bridgeId)
if err != nil {
return err
}

err = proposerAccount.Load(baseCtx)
if err != nil {
return err
}

updateBatchInfoMsg := &ophosttypes.MsgUpdateBatchInfo{
Authority: proposerAccount.GetAddressString(),
BridgeId: bridgeId,
NewBatchInfo: ophosttypes.BatchInfo{
Submitter: newSubmitterAddress,
ChainType: ophosttypes.BatchInfo_ChainType(ophosttypes.BatchInfo_ChainType_value[chainType]),
},
}

txBytes, _, err := proposerAccount.BuildTxWithMsgs(ctx, []sdk.Msg{updateBatchInfoMsg})
if err != nil {
return errors.Wrapf(err, "simulation failed")
}

res, err := proposerAccount.BroadcastTxSync(baseCtx, txBytes)
if err != nil {
// TODO: handle error, may repeat sending tx
return fmt.Errorf("broadcast txs: %w", err)
}
bz, err := json.Marshal(res)
if err != nil {
return err
}
fmt.Println(string(bz))
return nil
},
}

cmd = configFlag(baseCtx.v, cmd)
return cmd
}

func validateBatchInfoArgs(chainType string) error {
chainType = strings.ToUpper(chainType)
if chainType != ophosttypes.BatchInfo_INITIA.String() && chainType != ophosttypes.BatchInfo_CELESTIA.String() {
return fmt.Errorf("supported chain type: %s, %s", ophosttypes.BatchInfo_INITIA.String(), ophosttypes.BatchInfo_CELESTIA.String())
}
return nil
}

func getExecutorConfig(ctx types.Context, cmd *cobra.Command) (*executortypes.Config, error) {
configPath, err := getConfigPath(cmd, ctx.HomePath(), string(bottypes.BotTypeExecutor))
if err != nil {
return nil, err
Expand All @@ -119,6 +216,55 @@ func l2BroadcasterAccount(ctx types.Context, cmd *cobra.Command) (*broadcaster.B
return nil, err
}

return cfg, nil
}

func QueryBridgeId(ctx types.Context, cfg *executortypes.Config) (uint64, error) {
l2Config := cfg.L2NodeConfig()
cdc, _, err := child.GetCodec(l2Config.BroadcasterConfig.Bech32Prefix)
if err != nil {
return 0, err
}

l2RpcClient, err := rpcclient.NewRPCClient(cdc, l2Config.RPC)
if err != nil {
return 0, err
}
queryCtx, cancel := rpcclient.GetQueryContext(ctx, 0)
defer cancel()
bridgeInfoResponse, err := opchildtypes.NewQueryClient(l2RpcClient).BridgeInfo(queryCtx, &opchildtypes.QueryBridgeInfoRequest{})
if err != nil {
return 0, errors.Wrap(err, "failed to query opchild bridge info")
}
return bridgeInfoResponse.BridgeInfo.BridgeId, nil
}

func l1ProposerAccount(ctx types.Context, cfg *executortypes.Config, bridgeId uint64) (*broadcaster.BroadcasterAccount, error) {
l1Config := cfg.L1NodeConfig()
broadcasterConfig := l1Config.BroadcasterConfig
cdc, txConfig, err := child.GetCodec(broadcasterConfig.Bech32Prefix)
if err != nil {
return nil, err
}

rpcClient, err := rpcclient.NewRPCClient(cdc, l1Config.RPC)
if err != nil {
return nil, err
}
queryCtx, cancel := rpcclient.GetQueryContext(ctx, 0)
defer cancel()
bridgeResponse, err := ophosttypes.NewQueryClient(rpcClient).Bridge(queryCtx, &ophosttypes.QueryBridgeRequest{BridgeId: bridgeId})
if err != nil {
return nil, errors.Wrap(err, "failed to query ophost bridge info")
}

keyringConfig := broadcastertypes.KeyringConfig{
Address: bridgeResponse.BridgeConfig.Proposer,
}
return broadcaster.NewBroadcasterAccount(ctx, *broadcasterConfig, cdc, txConfig, rpcClient, keyringConfig)
}

func l2BroadcasterAccount(ctx types.Context, cfg *executortypes.Config) (*broadcaster.BroadcasterAccount, error) {
l2Config := cfg.L2NodeConfig()
broadcasterConfig := l2Config.BroadcasterConfig
cdc, txConfig, err := child.GetCodec(broadcasterConfig.Bech32Prefix)
Expand Down
6 changes: 3 additions & 3 deletions e2e/batch_reconstruction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ func TestBatchReconstructionTest(t *testing.T) {
name: "initia with go relayer",
daChainConfig: DAChainConfig{
ChainConfig: *l1ChainConfig,
ChainType: ophosttypes.BatchInfo_CHAIN_TYPE_INITIA,
ChainType: ophosttypes.BatchInfo_INITIA,
},
relayerImpl: ibc.CosmosRly,
},
{
name: "initia with hermes relayer",
daChainConfig: DAChainConfig{
ChainConfig: *l1ChainConfig,
ChainType: ophosttypes.BatchInfo_CHAIN_TYPE_INITIA,
ChainType: ophosttypes.BatchInfo_INITIA,
},
relayerImpl: ibc.Hermes,
},
Expand All @@ -101,7 +101,7 @@ func TestBatchReconstructionTest(t *testing.T) {
NumValidators: 1,
NumFullNodes: 0,
},
ChainType: ophosttypes.BatchInfo_CHAIN_TYPE_CELESTIA,
ChainType: ophosttypes.BatchInfo_CELESTIA,
},
relayerImpl: ibc.CosmosRly,
},
Expand Down
8 changes: 4 additions & 4 deletions e2e/da_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ func (da *DAChain) GetFullNode() *DAChainNode {

func (da *DAChain) QueryBatchData(ctx context.Context) ([][]byte, error) {
switch da.ChainType {
case ophosttypes.BatchInfo_CHAIN_TYPE_INITIA:
case ophosttypes.BatchInfo_INITIA:
return da.QueryInitiaBatchData(ctx)
case ophosttypes.BatchInfo_CHAIN_TYPE_CELESTIA:
case ophosttypes.BatchInfo_CELESTIA:
return da.QueryCelestiaBatchData(ctx)
}
return nil, fmt.Errorf("unsupported chain type")
}

func (da *DAChain) QueryInitiaBatchData(ctx context.Context) ([][]byte, error) {
if da.ChainType != ophosttypes.BatchInfo_CHAIN_TYPE_INITIA {
if da.ChainType != ophosttypes.BatchInfo_INITIA {
return nil, fmt.Errorf("unmatched chain type")
}

Expand Down Expand Up @@ -112,7 +112,7 @@ func (da *DAChain) QueryInitiaBatchData(ctx context.Context) ([][]byte, error) {
}

func (da *DAChain) QueryCelestiaBatchData(ctx context.Context) ([][]byte, error) {
if da.ChainType != ophosttypes.BatchInfo_CHAIN_TYPE_CELESTIA {
if da.ChainType != ophosttypes.BatchInfo_CELESTIA {
return nil, fmt.Errorf("unmatched chain type")
}

Expand Down
33 changes: 28 additions & 5 deletions e2e/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,26 +334,48 @@ type CosmosTx struct {
}

// GrantOraclePermissions grants oracle permissions to the oracle bridge executor.
func (op *DockerOPBot) GrantOraclePermissions(ctx context.Context, oracleBridgeExecutorAddress string) error {
func (op *DockerOPBot) GrantOraclePermissions(ctx context.Context, oracleBridgeExecutorAddress string) (string, error) {
cmd := op.c.GrantOraclePermissions(oracleBridgeExecutorAddress, op.HomeDir())

ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()

res := op.Exec(ctx, cmd, nil)
if res.Err != nil {
return res.Err
return "", res.Err
}

output := CosmosTx{}
err := json.Unmarshal(res.Stdout, &output)
if err != nil {
return err
return "", err
}
if output.Code != 0 {
return fmt.Errorf("transaction failed with code %d: %s", output.Code, output.Log)
return "", fmt.Errorf("transaction failed with code %d: %s", output.Code, output.Log)
}
return nil
return output.Hash, nil
}

func (op *DockerOPBot) UpdateBatchInfo(ctx context.Context, chainType string, newBatchSubmitterAddress string) (string, error) {
cmd := op.c.UpdateBatchInfo(chainType, newBatchSubmitterAddress, op.HomeDir())

ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()

res := op.Exec(ctx, cmd, nil)
if res.Err != nil {
return "", res.Err
}

output := CosmosTx{}
err := json.Unmarshal(res.Stdout, &output)
if err != nil {
return "", err
}
if output.Code != 0 {
return "", fmt.Errorf("transaction failed with code %d: %s", output.Code, output.Log)
}
return output.Hash, nil
}

// Exec executes the command in the bot's container.
Expand Down Expand Up @@ -532,4 +554,5 @@ type OPBotCommander interface {
RestoreKey(chainID, keyName, bech32Prefix, mnemonic, homeDir string) []string
Start(botName string, homeDir string) []string
GrantOraclePermissions(address string, homeDir string) []string
UpdateBatchInfo(chainType string, newBatchSubmitterAddress string, homeDir string) []string
}
Loading
Loading