node: Added RecoverChainId governance support

This commit is contained in:
Kevin Peters 2024-01-22 17:44:38 -06:00 committed by Evan Gray
parent cfe1ec40a8
commit c7a7d1a56b
6 changed files with 959 additions and 682 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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()))
}