node: Added RecoverChainId governance support
This commit is contained in:
parent
cfe1ec40a8
commit
c7a7d1a56b
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -56,6 +57,9 @@ var ibcUpdateChannelChainTargetChainId *string
|
|||
var ibcUpdateChannelChainChannelId *string
|
||||
var ibcUpdateChannelChainChainId *string
|
||||
|
||||
var recoverChainIdEvmChainId *string
|
||||
var recoverChainIdNewChainId *string
|
||||
|
||||
func init() {
|
||||
governanceFlagSet := pflag.NewFlagSet("governance", pflag.ExitOnError)
|
||||
chainID = governanceFlagSet.String("chain-id", "", "Chain ID")
|
||||
|
@ -159,6 +163,14 @@ func init() {
|
|||
AdminClientIbcTranslatorUpdateChannelChainCmd.Flags().AddFlagSet(ibcUpdateChannelChainFlagSet)
|
||||
TemplateCmd.AddCommand(AdminClientIbcReceiverUpdateChannelChainCmd)
|
||||
TemplateCmd.AddCommand(AdminClientIbcTranslatorUpdateChannelChainCmd)
|
||||
|
||||
// flags for the recover-chain-id command
|
||||
recoverChainIdFlagSet := pflag.NewFlagSet("recover-chain-id", pflag.ExitOnError)
|
||||
recoverChainIdEvmChainId = recoverChainIdFlagSet.String("evm-chain-id", "", "EVM Chain ID to recover")
|
||||
recoverChainIdNewChainId = recoverChainIdFlagSet.String("new-chain-id", "", "New Chain ID to recover to")
|
||||
AdminClientRecoverChainIdCmd.Flags().AddFlagSet(recoverChainIdFlagSet)
|
||||
AdminClientRecoverChainIdCmd.Flags().AddFlagSet(moduleFlagSet)
|
||||
TemplateCmd.AddCommand(AdminClientRecoverChainIdCmd)
|
||||
}
|
||||
|
||||
var TemplateCmd = &cobra.Command{
|
||||
|
@ -190,6 +202,12 @@ var AdminClientTokenBridgeUpgradeContractCmd = &cobra.Command{
|
|||
Run: runTokenBridgeUpgradeContractTemplate,
|
||||
}
|
||||
|
||||
var AdminClientRecoverChainIdCmd = &cobra.Command{
|
||||
Use: "recover-chain-id",
|
||||
Short: "Generate an empty recover chain id template at specified path",
|
||||
Run: runRecoverChainIdTemplate,
|
||||
}
|
||||
|
||||
var AdminClientCircleIntegrationUpdateWormholeFinalityCmd = &cobra.Command{
|
||||
Use: "circle-integration-update-wormhole-finality",
|
||||
Short: "Generate an empty circle integration update wormhole finality template at specified path",
|
||||
|
@ -405,6 +423,48 @@ func runTokenBridgeUpgradeContractTemplate(cmd *cobra.Command, args []string) {
|
|||
fmt.Print(string(b))
|
||||
}
|
||||
|
||||
func runRecoverChainIdTemplate(cmd *cobra.Command, args []string) {
|
||||
if *module == "" {
|
||||
log.Fatal("--module must be specified.")
|
||||
}
|
||||
if *recoverChainIdEvmChainId == "" {
|
||||
log.Fatal("--evm-chain-id must be specified.")
|
||||
}
|
||||
if _, err := isValidUint256(*recoverChainIdEvmChainId); err != nil {
|
||||
log.Fatal("failed to parse evm chain id as uint256:", err)
|
||||
}
|
||||
if *recoverChainIdNewChainId == "" {
|
||||
log.Fatal("--new-chain-id must be specified.")
|
||||
}
|
||||
newChainID, err := parseChainID(*recoverChainIdNewChainId)
|
||||
if err != nil {
|
||||
log.Fatal("failed to parse chain id:", err)
|
||||
}
|
||||
|
||||
m := &nodev1.InjectGovernanceVAARequest{
|
||||
CurrentSetIndex: uint32(*templateGuardianIndex),
|
||||
Messages: []*nodev1.GovernanceMessage{
|
||||
{
|
||||
Sequence: rand.Uint64(),
|
||||
Nonce: rand.Uint32(),
|
||||
Payload: &nodev1.GovernanceMessage_RecoverChainId{
|
||||
RecoverChainId: &nodev1.RecoverChainId{
|
||||
Module: *module,
|
||||
EvmChainId: *recoverChainIdEvmChainId,
|
||||
NewChainId: uint32(newChainID),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
b, err := prototext.MarshalOptions{Multiline: true}.Marshal(m)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Print(string(b))
|
||||
}
|
||||
|
||||
func runCircleIntegrationUpdateWormholeFinalityTemplate(cmd *cobra.Command, args []string) {
|
||||
if *circleIntegrationChainID == "" {
|
||||
log.Fatal("--chain-id must be specified.")
|
||||
|
@ -921,3 +981,20 @@ func parseChainID(name string) (vaa.ChainID, error) {
|
|||
|
||||
return vaa.ChainID(i), nil
|
||||
}
|
||||
|
||||
func isValidUint256(s string) (bool, error) {
|
||||
i := new(big.Int)
|
||||
i.SetString(s, 10) // Parse in base 10
|
||||
|
||||
// Create upper limit as 2^256 - 1
|
||||
upperLimit := new(big.Int)
|
||||
upperLimit.Exp(big.NewInt(2), big.NewInt(256), nil)
|
||||
upperLimit.Sub(upperLimit, big.NewInt(1))
|
||||
|
||||
// Check if i is within the range [0, 2^256 - 1]
|
||||
if i.Cmp(big.NewInt(0)) < 0 || i.Cmp(upperLimit) > 0 {
|
||||
return false, fmt.Errorf("value is not a valid uint256")
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -184,6 +184,35 @@ func tokenBridgeRegisterChain(req *nodev1.BridgeRegisterChain, timestamp time.Ti
|
|||
return v, nil
|
||||
}
|
||||
|
||||
// recoverChainId converts a nodev1.RecoverChainId message to its canonical VAA representation.
|
||||
// Returns an error if the data is invalid.
|
||||
func recoverChainId(req *nodev1.RecoverChainId, timestamp time.Time, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) {
|
||||
evm_chain_id_big := big.NewInt(0)
|
||||
evm_chain_id_big, ok := evm_chain_id_big.SetString(req.EvmChainId, 10)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid evm_chain_id")
|
||||
}
|
||||
|
||||
// uint256 has Bytes32 method for easier serialization
|
||||
evm_chain_id, overflow := uint256.FromBig(evm_chain_id_big)
|
||||
if overflow {
|
||||
return nil, errors.New("evm_chain_id overflow")
|
||||
}
|
||||
|
||||
if req.NewChainId > math.MaxUint16 {
|
||||
return nil, errors.New("invalid new_chain_id")
|
||||
}
|
||||
|
||||
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
|
||||
vaa.BodyRecoverChainId{
|
||||
Module: req.Module,
|
||||
EvmChainID: evm_chain_id,
|
||||
NewChainID: vaa.ChainID(req.NewChainId),
|
||||
}.Serialize())
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// accountantModifyBalance converts a nodev1.AccountantModifyBalance message to its canonical VAA representation.
|
||||
// Returns an error if the data is invalid.
|
||||
func accountantModifyBalance(req *nodev1.AccountantModifyBalance, timestamp time.Time, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) {
|
||||
|
@ -563,6 +592,8 @@ func GovMsgToVaa(message *nodev1.GovernanceMessage, currentSetIndex uint32, time
|
|||
v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, timestamp, currentSetIndex, message.Nonce, message.Sequence)
|
||||
case *nodev1.GovernanceMessage_BridgeContractUpgrade:
|
||||
v, err = tokenBridgeUpgradeContract(payload.BridgeContractUpgrade, timestamp, currentSetIndex, message.Nonce, message.Sequence)
|
||||
case *nodev1.GovernanceMessage_RecoverChainId:
|
||||
v, err = recoverChainId(payload.RecoverChainId, timestamp, currentSetIndex, message.Nonce, message.Sequence)
|
||||
case *nodev1.GovernanceMessage_AccountantModifyBalance:
|
||||
v, err = accountantModifyBalance(payload.AccountantModifyBalance, timestamp, currentSetIndex, message.Nonce, message.Sequence)
|
||||
case *nodev1.GovernanceMessage_WormchainStoreCode:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -90,6 +90,9 @@ message GovernanceMessage {
|
|||
BridgeRegisterChain bridge_register_chain = 12;
|
||||
BridgeUpgradeContract bridge_contract_upgrade = 13;
|
||||
|
||||
// Core, Token bridge, and NFT module
|
||||
RecoverChainId recover_chain_id = 27;
|
||||
|
||||
// Wormchain
|
||||
|
||||
WormchainStoreCode wormchain_store_code = 14;
|
||||
|
@ -206,6 +209,18 @@ message BridgeUpgradeContract {
|
|||
string new_contract = 3;
|
||||
}
|
||||
|
||||
message RecoverChainId {
|
||||
// Module identifier
|
||||
string module = 1;
|
||||
|
||||
// The EVM chain ID of the chain to be recovered
|
||||
// This should be a decimal formatted integer string (Uint256)
|
||||
string evm_chain_id = 2;
|
||||
|
||||
// The new chain ID to be used for the chain
|
||||
uint32 new_chain_id = 3;
|
||||
}
|
||||
|
||||
message WormchainStoreCode {
|
||||
// payload is the hex string of the sha3 256 hash of the wasm binary being uploaded
|
||||
string wasm_hash = 1;
|
||||
|
|
|
@ -128,6 +128,13 @@ type (
|
|||
NewContract Address
|
||||
}
|
||||
|
||||
// BodyRecoverChainId is a governance message to recover a chain id.
|
||||
BodyRecoverChainId struct {
|
||||
Module string
|
||||
EvmChainID *uint256.Int
|
||||
NewChainID ChainID
|
||||
}
|
||||
|
||||
// BodyTokenBridgeModifyBalance is a governance message to modify accountant balances for the tokenbridge.
|
||||
BodyAccountantModifyBalance struct {
|
||||
Module string
|
||||
|
@ -257,6 +264,24 @@ func (r BodyTokenBridgeUpgradeContract) Serialize() []byte {
|
|||
return serializeBridgeGovernanceVaa(r.Module, ActionUpgradeTokenBridge, r.TargetChainID, r.NewContract[:])
|
||||
}
|
||||
|
||||
func (r BodyRecoverChainId) Serialize() []byte {
|
||||
// Module
|
||||
buf := LeftPadBytes(r.Module, 32)
|
||||
// Action
|
||||
var action GovernanceAction
|
||||
if r.Module == "Core" {
|
||||
action = ActionCoreRecoverChainId
|
||||
} else {
|
||||
action = ActionTokenBridgeRecoverChainId
|
||||
}
|
||||
MustWrite(buf, binary.BigEndian, action)
|
||||
// EvmChainID
|
||||
MustWrite(buf, binary.BigEndian, r.EvmChainID.Bytes32())
|
||||
// NewChainID
|
||||
MustWrite(buf, binary.BigEndian, r.NewChainID)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (r BodyAccountantModifyBalance) Serialize() []byte {
|
||||
payload := &bytes.Buffer{}
|
||||
MustWrite(payload, binary.BigEndian, r.Sequence)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -226,3 +227,23 @@ func TestBodyGatewayIbcComposabilityMwContractDeserialize(t *testing.T) {
|
|||
payloadBody.Deserialize(dummyBytes[:])
|
||||
assert.Equal(t, expected, payloadBody)
|
||||
}
|
||||
|
||||
func TestBodyCoreRecoverChainIdSerialize(t *testing.T) {
|
||||
expected := "00000000000000000000000000000000000000000000000000000000436f72650500000000000000000000000000000000000000000000000000000000000000010fa0"
|
||||
BodyRecoverChainId := BodyRecoverChainId{
|
||||
Module: "Core",
|
||||
EvmChainID: uint256.NewInt(1),
|
||||
NewChainID: 4000,
|
||||
}
|
||||
assert.Equal(t, expected, hex.EncodeToString(BodyRecoverChainId.Serialize()))
|
||||
}
|
||||
|
||||
func TestBodyTokenBridgeRecoverChainIdSerialize(t *testing.T) {
|
||||
expected := "000000000000000000000000000000000000000000546f6b656e4272696467650300000000000000000000000000000000000000000000000000000000000000010fa0"
|
||||
BodyRecoverChainId := BodyRecoverChainId{
|
||||
Module: "TokenBridge",
|
||||
EvmChainID: uint256.NewInt(1),
|
||||
NewChainID: 4000,
|
||||
}
|
||||
assert.Equal(t, expected, hex.EncodeToString(BodyRecoverChainId.Serialize()))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue