Skip to content

Commit

Permalink
Switch to Gateway Governance Module
Browse files Browse the repository at this point in the history
  • Loading branch information
joelsmith-2019 committed Feb 5, 2025
1 parent a785322 commit 9e88ce5
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 184 deletions.
106 changes: 55 additions & 51 deletions sdk/vaa/payloads.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,11 @@ type GovernanceAction uint8
var (
// Wormhole core governance actions
// See e.g. GovernanceStructs.sol for semantic meaning of these
ActionContractUpgrade GovernanceAction = 1
ActionGuardianSetUpdate GovernanceAction = 2
ActionCoreSetMessageFee GovernanceAction = 3
ActionCoreTransferFees GovernanceAction = 4
ActionCoreRecoverChainId GovernanceAction = 5
ActionSlashingParamsUpdate GovernanceAction = 6
ActionContractUpgrade GovernanceAction = 1
ActionGuardianSetUpdate GovernanceAction = 2
ActionCoreSetMessageFee GovernanceAction = 3
ActionCoreTransferFees GovernanceAction = 4
ActionCoreRecoverChainId GovernanceAction = 5

// Wormchain cosmwasm/middleware governance actions
ActionStoreCode GovernanceAction = 1
Expand All @@ -87,6 +86,7 @@ var (
ActionScheduleUpgrade GovernanceAction = 1
ActionCancelUpgrade GovernanceAction = 2
ActionSetIbcComposabilityMwContract GovernanceAction = 3
ActionSlashingParamsUpdate GovernanceAction = 4

// Accountant governance actions
ActionModifyBalance GovernanceAction = 1
Expand Down Expand Up @@ -128,32 +128,6 @@ type (
NewIndex uint32
}

// BodySlashingParamsUpdate is a governance message to update the slashing parameters on Wormchain.
//
// It is important to note that the slashing keeper only accepts `int64` values as input, so we need to convert
// the `uint64` values to `int64` before passing them to the keeper. This conversion can introduce overflow
// issues if the `uint64` values are too large. To combat this, the Wormchain CLI and the slashing keeper run
// validation checks on the new parameter values.
//
// Below documents the entire process of updating the slashing parameters:
// 1. The CLI command receives the new slashing parameters from the user as `uint64` values for `SignedBlocksWindow` and `DowntimeJailDuration` and as `string` values
// for `MinSignedPerWindow`, `SlashFractionDoubleSign`, and `SlashFractionDowntime`. The command accepts `string` values for ease of use when providing decimal values.
// 2. The CLI command converts the `string` values into `sdk.Dec` values and then into `uint64` values.
// 3. The CLI command validates that the `uint64` values are within the acceptable range for the slashing parameters.
// 4. The CLI command serializes the new slashing parameters into a governance VAA.
// 5. The governance VAA is signed & broadcasted to the Wormchain.
// 6. Wormchain deserializes the governance VAA and extracts every new slashing parameter as a uint64 value.
// 7. Wormchain converts the uint64 values to int64 values and passes them to the slashing keeper.
// 8. The slashing keeper runs validation checks on the new slashing parameters and throws an error if they are invalid.
// 9. If the new slashing parameters pass the validation checks, the slashing keeper updates its parameters.
BodySlashingParamsUpdate struct {
SignedBlocksWindow uint64
MinSignedPerWindow uint64
DowntimeJailDuration uint64
SlashFractionDoubleSign uint64
SlashFractionDowntime uint64
}

// BodyTokenBridgeRegisterChain is a governance message to register a chain on the token bridge
BodyTokenBridgeRegisterChain struct {
Module string
Expand Down Expand Up @@ -220,6 +194,32 @@ type (
ContractAddr [32]byte
}

// BodyGatewaySlashingParamsUpdate is a governance message to update the slashing parameters on Wormchain.
//
// It is important to note that the slashing keeper only accepts `int64` values as input, so we need to convert
// the `uint64` values to `int64` before passing them to the keeper. This conversion can introduce overflow
// issues if the `uint64` values are too large. To combat this, the Wormchain CLI and the slashing keeper run
// validation checks on the new parameter values.
//
// Below documents the entire process of updating the slashing parameters:
// 1. The CLI command receives the new slashing parameters from the user as `uint64` values for `SignedBlocksWindow` and `DowntimeJailDuration` and as `string` values
// for `MinSignedPerWindow`, `SlashFractionDoubleSign`, and `SlashFractionDowntime`. The command accepts `string` values for ease of use when providing decimal values.
// 2. The CLI command converts the `string` values into `sdk.Dec` values and then into `uint64` values.
// 3. The CLI command validates that the `uint64` values are within the acceptable range for the slashing parameters.
// 4. The CLI command serializes the new slashing parameters into a governance VAA.
// 5. The governance VAA is signed & broadcasted to the Wormchain.
// 6. Wormchain deserializes the governance VAA and extracts every new slashing parameter as a uint64 value.
// 7. Wormchain converts the uint64 values to int64 values and passes them to the slashing keeper.
// 8. The slashing keeper runs validation checks on the new slashing parameters and throws an error if they are invalid.
// 9. If the new slashing parameters pass the validation checks, the slashing keeper updates its parameters.
BodyGatewaySlashingParamsUpdate struct {
SignedBlocksWindow uint64
MinSignedPerWindow uint64
DowntimeJailDuration uint64
SlashFractionDoubleSign uint64
SlashFractionDowntime uint64
}

// BodyCircleIntegrationUpdateWormholeFinality is a governance message to update the wormhole finality for Circle Integration.
BodyCircleIntegrationUpdateWormholeFinality struct {
TargetChainID ChainID
Expand Down Expand Up @@ -310,25 +310,6 @@ func (b BodyGuardianSetUpdate) Serialize() ([]byte, error) {
return buf.Bytes(), nil
}

func (b BodySlashingParamsUpdate) Serialize() ([]byte, error) {
buf := new(bytes.Buffer)

// Module
buf.Write(CoreModule)
// // Action
MustWrite(buf, binary.BigEndian, ActionSlashingParamsUpdate)
// // ChainID - 0 for universal
MustWrite(buf, binary.BigEndian, uint16(0))

MustWrite(buf, binary.BigEndian, b.SignedBlocksWindow)
MustWrite(buf, binary.BigEndian, b.MinSignedPerWindow)
MustWrite(buf, binary.BigEndian, b.DowntimeJailDuration)
MustWrite(buf, binary.BigEndian, b.SlashFractionDoubleSign)
MustWrite(buf, binary.BigEndian, b.SlashFractionDowntime)

return buf.Bytes(), nil
}

func (r BodyTokenBridgeRegisterChain) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
MustWrite(payload, binary.BigEndian, r.ChainID)
Expand Down Expand Up @@ -439,6 +420,29 @@ func (r *BodyGatewayIbcComposabilityMwContract) Deserialize(bz []byte) error {
return nil
}

func (b BodyGatewaySlashingParamsUpdate) Serialize() ([]byte, error) {
payload := new(bytes.Buffer)
MustWrite(payload, binary.BigEndian, b.SignedBlocksWindow)
MustWrite(payload, binary.BigEndian, b.MinSignedPerWindow)
MustWrite(payload, binary.BigEndian, b.DowntimeJailDuration)
MustWrite(payload, binary.BigEndian, b.SlashFractionDoubleSign)
MustWrite(payload, binary.BigEndian, b.SlashFractionDowntime)
return serializeBridgeGovernanceVaa(GatewayModuleStr, ActionSlashingParamsUpdate, ChainIDWormchain, payload.Bytes())
}

func (r *BodyGatewaySlashingParamsUpdate) Deserialize(bz []byte) error {
if len(bz) != 40 {
return fmt.Errorf("incorrect payload length, should be 40, is %d", len(bz))
}

r.SignedBlocksWindow = binary.BigEndian.Uint64(bz[0:8])
r.MinSignedPerWindow = binary.BigEndian.Uint64(bz[8:16])
r.DowntimeJailDuration = binary.BigEndian.Uint64(bz[16:24])
r.SlashFractionDoubleSign = binary.BigEndian.Uint64(bz[24:32])
r.SlashFractionDowntime = binary.BigEndian.Uint64(bz[32:40])
return nil
}

func (r BodyGatewayScheduleUpgrade) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
payload.Write([]byte(r.Name))
Expand Down
78 changes: 57 additions & 21 deletions sdk/vaa/payloads_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,27 +74,6 @@ func TestBodyGuardianSetUpdateSerialize(t *testing.T) {
assert.Equal(t, expected, hex.EncodeToString(serializedBodyGuardianSetUpdate))
}

func TestBodySlashingParamsUpdateSerialize(t *testing.T) {
signedBlocksWindow := uint64(100)
minSignedPerWindow := uint64(500000000000000000)
downtimeJailDuration := uint64(600 * time.Second)
slashFractionDoubleSign := uint64(50000000000000000)
slashFractionDowntime := uint64(10000000000000000)

bodySlashingParamsUpdate := BodySlashingParamsUpdate{
SignedBlocksWindow: signedBlocksWindow,
MinSignedPerWindow: minSignedPerWindow,
DowntimeJailDuration: downtimeJailDuration,
SlashFractionDoubleSign: slashFractionDoubleSign,
SlashFractionDowntime: slashFractionDowntime,
}
serializedBody, err := bodySlashingParamsUpdate.Serialize()
require.NoError(t, err)

expected := "00000000000000000000000000000000000000000000000000000000436f7265060000000000000000006406f05b59d3b200000000008bb2c9700000b1a2bc2ec50000002386f26fc10000"
assert.Equal(t, expected, hex.EncodeToString(serializedBody))
}

func TestBodyTokenBridgeRegisterChainSerialize(t *testing.T) {
module := "test"
tests := []struct {
Expand Down Expand Up @@ -385,6 +364,63 @@ func TestBodyGatewayIbcComposabilityMwContractDeserializeFailureTooLong(t *testi
require.ErrorContains(t, err, "incorrect payload length, should be 32, is 33")
}

func TestBodySlashingParamsUpdateSerialize(t *testing.T) {
signedBlocksWindow := uint64(100)
minSignedPerWindow := uint64(500000000000000000)
downtimeJailDuration := uint64(600 * time.Second)
slashFractionDoubleSign := uint64(50000000000000000)
slashFractionDowntime := uint64(10000000000000000)

bodySlashingParamsUpdate := BodyGatewaySlashingParamsUpdate{
SignedBlocksWindow: signedBlocksWindow,
MinSignedPerWindow: minSignedPerWindow,
DowntimeJailDuration: downtimeJailDuration,
SlashFractionDoubleSign: slashFractionDoubleSign,
SlashFractionDowntime: slashFractionDowntime,
}
serializedBody, err := bodySlashingParamsUpdate.Serialize()
require.NoError(t, err)

expected := "00000000000000000000000000000000000000476174657761794d6f64756c65040c20000000000000006406f05b59d3b200000000008bb2c9700000b1a2bc2ec50000002386f26fc10000"
assert.Equal(t, expected, hex.EncodeToString(serializedBody))
}

const BodySlashingParamsUpdateBuf = "000000000000006406f05b59d3b200000000008bb2c9700000b1a2bc2ec50000002386f26fc10000"

func TestBodySlashingParamsUpdateDeserialize(t *testing.T) {
expected := BodyGatewaySlashingParamsUpdate{
SignedBlocksWindow: 100,
MinSignedPerWindow: 500000000000000000,
DowntimeJailDuration: uint64(600 * time.Second),
SlashFractionDoubleSign: 50000000000000000,
SlashFractionDowntime: 10000000000000000,
}
var payloadBody BodyGatewaySlashingParamsUpdate
bz, err := hex.DecodeString(BodySlashingParamsUpdateBuf)
require.NoError(t, err)
err = payloadBody.Deserialize(bz)
require.NoError(t, err)
assert.Equal(t, expected, payloadBody)
}

func TestBodySlashingParamsUpdateDeserializeFailureTooShort(t *testing.T) {
buf, err := hex.DecodeString(BodySlashingParamsUpdateBuf[0 : len(BodySlashingParamsUpdateBuf)-2])
require.NoError(t, err)

var actual BodyGatewaySlashingParamsUpdate
err = actual.Deserialize(buf)
require.ErrorContains(t, err, "incorrect payload length, should be 40, is 39")
}

func TestBodySlashingParamsUpdateDeserializeFailureTooLong(t *testing.T) {
buf, err := hex.DecodeString(BodySlashingParamsUpdateBuf + "00")
require.NoError(t, err)

var actual BodyGatewaySlashingParamsUpdate
err = actual.Deserialize(buf)
require.ErrorContains(t, err, "incorrect payload length, should be 40, is 41")
}

func TestBodyCoreRecoverChainIdSerialize(t *testing.T) {
expected := "00000000000000000000000000000000000000000000000000000000436f72650500000000000000000000000000000000000000000000000000000000000000010fa0"
BodyRecoverChainId := BodyRecoverChainId{
Expand Down
25 changes: 9 additions & 16 deletions wormchain/interchaintest/slashing_params_update_vaa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package ictest

import (
"context"
"encoding/binary"
"encoding/hex"
"encoding/json"
"strconv"
Expand All @@ -15,7 +14,6 @@ import (
"github.com/stretchr/testify/require"
"github.com/wormhole-foundation/wormchain/interchaintest/guardians"
"github.com/wormhole-foundation/wormchain/interchaintest/helpers"
types "github.com/wormhole-foundation/wormchain/x/wormhole/types"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
)

Expand All @@ -37,9 +35,6 @@ func createSlashingParamsUpdate(
slashFractionDoubleSign string,
slashFractionDowntime string,
) ([]byte, error) {
var coreModule [32]byte
copy(coreModule[:], vaa.CoreModule[:])

minSignedWindow, err := sdk.NewDecFromStr(minSignedPerWindow)
if err != nil {
return nil, err
Expand All @@ -57,17 +52,15 @@ func createSlashingParamsUpdate(
return nil, err
}

payload := make([]byte, 40)
binary.BigEndian.PutUint64(payload[0:8], signedBlocksWindow)
binary.BigEndian.PutUint64(payload[8:16], minSignedWindow.BigInt().Uint64())
binary.BigEndian.PutUint64(payload[16:24], downtimeJailDurationSeconds)
binary.BigEndian.PutUint64(payload[24:32], slashFractionDoubleSignDec.BigInt().Uint64())
binary.BigEndian.PutUint64(payload[32:40], slashFractionDowntimeDec.BigInt().Uint64())

gov_msg := types.NewGovernanceMessage(coreModule, byte(vaa.ActionSlashingParamsUpdate), uint16(vaa.ChainIDWormchain),
payload)
payloadBody := vaa.BodyGatewaySlashingParamsUpdate{
SignedBlocksWindow: signedBlocksWindow,
MinSignedPerWindow: minSignedWindow.BigInt().Uint64(),
DowntimeJailDuration: downtimeJailDurationSeconds,
SlashFractionDoubleSign: slashFractionDoubleSignDec.BigInt().Uint64(),
SlashFractionDowntime: slashFractionDowntimeDec.BigInt().Uint64(),
}

return gov_msg.MarshalBinary(), nil
return payloadBody.Serialize()
}

// querySlashingParams queries the slashing params from the chain
Expand Down Expand Up @@ -121,7 +114,7 @@ func createAndExecuteVaa(ctx context.Context, guardians *guardians.ValSet, wormc
}
vHex := hex.EncodeToString(vBz)

_, err = wormchain.FullNodes[0].ExecTx(ctx, "faucet", "wormhole", "execute-governance-vaa", vHex)
_, err = wormchain.FullNodes[0].ExecTx(ctx, "faucet", "wormhole", "execute-gateway-governance-vaa", vHex)
if err != nil {
return err
}
Expand Down
26 changes: 13 additions & 13 deletions wormchain/x/wormhole/client/cli/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,19 +482,19 @@ func CmdGenerateSlashingParamsUpdateVaa() *cobra.Command {
return fmt.Errorf("slash fraction downtime must be greater than or equal to 0.000000000000000000 and less than or equal to 1.000000000000000000")
}

slashingUpdate := make([]byte, 40)
binary.BigEndian.PutUint64(slashingUpdate[:8], signedBlocksWindow)
binary.BigEndian.PutUint64(slashingUpdate[8:16], minSignedPerWindowDec.BigInt().Uint64())
binary.BigEndian.PutUint64(slashingUpdate[16:24], downtimeJailDuration*uint64(time.Second))
binary.BigEndian.PutUint64(slashingUpdate[24:32], slashFractionDoubleSignDec.BigInt().Uint64())
binary.BigEndian.PutUint64(slashingUpdate[32:40], slashFractionDowntimeDec.BigInt().Uint64())

action := vaa.ActionSlashingParamsUpdate
chain := vaa.ChainIDWormchain
module := [32]byte{}
copy(module[:], vaa.CoreModule)
msg := types.NewGovernanceMessage(module, byte(action), uint16(chain), slashingUpdate)
v.Payload = msg.MarshalBinary()
slashingBody := vaa.BodyGatewaySlashingParamsUpdate{
SignedBlocksWindow: signedBlocksWindow,
MinSignedPerWindow: minSignedPerWindowDec.BigInt().Uint64(),
DowntimeJailDuration: downtimeJailDuration * uint64(time.Second),
SlashFractionDoubleSign: slashFractionDoubleSignDec.BigInt().Uint64(),
SlashFractionDowntime: slashFractionDowntimeDec.BigInt().Uint64(),
}
payload, err := slashingBody.Serialize()
if err != nil {
return
}

v.Payload = payload
v.EmitterChain = 1

for i, key := range privateKeys {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package keeper

import (
"context"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

"github.com/wormhole-foundation/wormchain/x/wormhole/types"
Expand Down Expand Up @@ -48,6 +50,8 @@ func (k msgServer) ExecuteGatewayGovernanceVaa(
return k.cancelUpgrade(ctx)
case vaa.ActionSetIbcComposabilityMwContract:
return k.setIbcComposabilityMwContract(ctx, payload)
case vaa.ActionSlashingParamsUpdate:
return k.setSlashingParams(ctx, payload)
default:
return nil, types.ErrUnknownGovernanceAction
}
Expand Down Expand Up @@ -100,3 +104,29 @@ func (k msgServer) setIbcComposabilityMwContract(

return &types.EmptyResponse{}, nil
}

func (k msgServer) setSlashingParams(
ctx sdk.Context,
payload []byte,
) (*types.EmptyResponse, error) {
var payloadBody vaa.BodyGatewaySlashingParamsUpdate
payloadBody.Deserialize(payload)

// Update slashing params
params := slashingtypes.NewParams(
int64(payloadBody.SignedBlocksWindow),
sdk.NewDecWithPrec(int64(payloadBody.MinSignedPerWindow), 18),
time.Duration(int64(payloadBody.DowntimeJailDuration)),
sdk.NewDecWithPrec(int64(payloadBody.SlashFractionDoubleSign), 18),
sdk.NewDecWithPrec(int64(payloadBody.SlashFractionDowntime), 18),
)

// Set the new params
//
// TODO: Once upgraded to CosmosSDK v0.47, this method will return an error
// if the params do not pass validation checks. Because of that, we need to
// return the error from this function.
k.slashingKeeper.SetParams(ctx, params)

return &types.EmptyResponse{}, nil
}
Loading

0 comments on commit 9e88ce5

Please sign in to comment.