diff --git a/.github/workflows/wormchain-icts.yml b/.github/workflows/wormchain-icts.yml index 867c729875..e02ff73285 100644 --- a/.github/workflows/wormchain-icts.yml +++ b/.github/workflows/wormchain-icts.yml @@ -46,7 +46,7 @@ jobs: outputs: type=docker,dest=${{ env.TAR_PATH }} - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ env.IMAGE_NAME }} path: ${{ env.TAR_PATH }} @@ -59,9 +59,11 @@ jobs: # names of `make` commands to run tests test: - "ictest-cancel-upgrade" + - "ictest-slashing-params-update-vaa" - "ictest-upgrade" - "ictest-wormchain" - - "ictest-ibc-receiver" + # Disabled due to flakiness in CI. + # - "ictest-ibc-receiver" - "ictest-validator-hotswap" - "ictest-cw-wormhole" fail-fast: false @@ -77,7 +79,7 @@ jobs: uses: actions/checkout@v4 - name: Download Tarball Artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: ${{ env.IMAGE_NAME }} path: /tmp diff --git a/sdk/vaa/payloads.go b/sdk/vaa/payloads.go index bf86d32280..b28ff4f551 100644 --- a/sdk/vaa/payloads.go +++ b/sdk/vaa/payloads.go @@ -86,6 +86,7 @@ var ( ActionScheduleUpgrade GovernanceAction = 1 ActionCancelUpgrade GovernanceAction = 2 ActionSetIbcComposabilityMwContract GovernanceAction = 3 + ActionSlashingParamsUpdate GovernanceAction = 4 // Accountant governance actions ActionModifyBalance GovernanceAction = 1 @@ -193,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 @@ -393,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)) diff --git a/sdk/vaa/payloads_test.go b/sdk/vaa/payloads_test.go index 1ce46166c8..9333233017 100644 --- a/sdk/vaa/payloads_test.go +++ b/sdk/vaa/payloads_test.go @@ -6,6 +6,7 @@ import ( "errors" "reflect" "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" @@ -363,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{ diff --git a/wormchain/.gitignore b/wormchain/.gitignore index 252784af5f..632f13a987 100644 --- a/wormchain/.gitignore +++ b/wormchain/.gitignore @@ -6,7 +6,7 @@ release/ testing/js/node_modules !build build/wormhole-chaind -build/wormchaind +build/wormchaind* build/data devnet/wormchain-*/data devnet/wormchain-*/config/*.toml diff --git a/wormchain/Dockerfile.ict b/wormchain/Dockerfile.ict index f186b286cc..65c8b86b5f 100644 --- a/wormchain/Dockerfile.ict +++ b/wormchain/Dockerfile.ict @@ -28,7 +28,7 @@ WORKDIR /home/heighliner COPY --from=builder /app/build/wormchaind /usr/bin # copy over c bindings (libwasmvm.x86_64.so, etc) -COPY --from=builder /go/pkg/mod/github.com/!cosm!wasm/wasmvm@v1.1.1/internal/api/* /usr/lib +COPY --from=builder /go/pkg/mod/github.com/!cosm!wasm/wasmvm@v1.1.1/internal/api/* /usr/lib/ EXPOSE 26657 EXPOSE 26656 diff --git a/wormchain/Makefile b/wormchain/Makefile index 7fbdb3a6be..ae1efd7bf8 100644 --- a/wormchain/Makefile +++ b/wormchain/Makefile @@ -90,29 +90,40 @@ local-image: build/wormchaind # Individual Tests ($$ is interpreted as $) rm-testcache: go clean -testcache +.PHONY: rm-testcache ictest-cancel-upgrade: rm-testcache cd interchaintest && go test -race -v -run ^TestCancelUpgrade$$ ./... +.PHONY: ictest-cancel-upgrade ictest-malformed-payload: rm-testcache cd interchaintest && go test -race -v -run ^TestMalformedPayload$$ ./... +.PHONY: ictest-malformed-payload + +ictest-slashing-params-update-vaa: rm-testcache + cd interchaintest && go test -race -v -run ^TestSlashingParamsUpdateVaa$$ ./... +.PHONY: ictest-slashing-params-update-vaa ictest-upgrade-failure: rm-testcache cd interchaintest && go test -race -v -run ^TestUpgradeFailure$$ ./... +.PHONY: ictest-upgrade-failure ictest-upgrade: rm-testcache cd interchaintest && go test -race -v -run ^TestUpgrade$$ ./... +.PHONY: ictest-upgrade ictest-wormchain: rm-testcache cd interchaintest && go test -race -v -run ^TestWormchain$$ ./... +.PHONY: ictest-wormchain ictest-ibc-receiver: rm-testcache cd interchaintest && go test -race -v -run ^TestIbcReceiver ./... +.PHONY: ictest-ibc-receiver ictest-cw-wormhole: rm-testcache cd interchaintest && go test -race -v -run ^TestCWWormhole ./... +.PHONY: ictest-cw-wormhole ictest-validator-hotswap: rm-testcache cd interchaintest && go test -race -v -run ^TestValidatorHotswap$$ ./... - -.PHONY: ictest-cancel-upgrade ictest-malformed-payload ictest-upgrade-failure ictest-upgrade ictest-wormchain ictest-ibc-receiver ictest-cw-wormhole ictest-validator-hotswap +.PHONY: ictest-validator-hotswap diff --git a/wormchain/app/app.go b/wormchain/app/app.go index 40463085ec..131f89a77d 100644 --- a/wormchain/app/app.go +++ b/wormchain/app/app.go @@ -388,6 +388,8 @@ func New( app.SlashingKeeper = slashingkeeper.NewKeeper( appCodec, keys[slashingtypes.StoreKey], &stakingKeeper, app.GetSubspace(slashingtypes.ModuleName), ) + app.WormholeKeeper.SetSlashingKeeper(app.SlashingKeeper) + app.CrisisKeeper = crisiskeeper.NewKeeper( app.GetSubspace(crisistypes.ModuleName), invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName, ) diff --git a/wormchain/interchaintest/helpers/gateway_governance_vaa.go b/wormchain/interchaintest/helpers/gateway_governance_vaa.go index c2f1feb561..4828b41232 100644 --- a/wormchain/interchaintest/helpers/gateway_governance_vaa.go +++ b/wormchain/interchaintest/helpers/gateway_governance_vaa.go @@ -41,7 +41,7 @@ func SetMiddlewareContract( } payloadBz, err := payload.Serialize() require.NoError(t, err) - v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) + v := GenerateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) vBz, err := v.Marshal() require.NoError(t, err) vHex := hex.EncodeToString(vBz) @@ -67,7 +67,7 @@ func ScheduleUpgrade( } payloadBz, err := payload.Serialize() require.NoError(t, err) - v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payloadBz) + v := GenerateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payloadBz) vBz, err := v.Marshal() require.NoError(t, err) vHex := hex.EncodeToString(vBz) @@ -87,7 +87,7 @@ func CancelUpgrade( payloadBz, err := vaa.EmptyPayloadVaa(vaa.GatewayModuleStr, vaa.ActionCancelUpgrade, vaa.ChainIDWormchain) require.NoError(t, err) - v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) + v := GenerateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) vBz, err := v.Marshal() require.NoError(t, err) vHex := hex.EncodeToString(vBz) diff --git a/wormchain/interchaintest/helpers/ibc_translator.go b/wormchain/interchaintest/helpers/ibc_translator.go index 56edd9cf5c..ff7ba88e6b 100644 --- a/wormchain/interchaintest/helpers/ibc_translator.go +++ b/wormchain/interchaintest/helpers/ibc_translator.go @@ -39,7 +39,7 @@ func SubmitAllowlistInstantiateContract( } payloadBz, err := payload.Serialize(vaa.ActionAddWasmInstantiateAllowlist) require.NoError(t, err) - v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) + v := GenerateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) vBz, err := v.Marshal() require.NoError(t, err) vHex := hex.EncodeToString(vBz) @@ -83,7 +83,7 @@ func SubmitUpdateChainToChannelMapMsg(t *testing.T, allowlistChainID uint16, all payload.Write(channelPadded.Bytes()) vaa.MustWrite(payload, binary.BigEndian, allowlistChainID) - v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payload.Bytes()) + v := GenerateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payload.Bytes()) vBz, err := v.Marshal() require.NoError(t, err) @@ -162,7 +162,7 @@ func IbcTranslatorCompleteTransferAndConvertMsg(t *testing.T, emitterChainID uin emitterBz[eIndex-1] = emitterAddr[i-1] eIndex-- } - v := generateVaa(0, guardians, vaa.ChainID(emitterChainID), vaa.Address(emitterBz), payload) + v := GenerateVaa(0, guardians, vaa.ChainID(emitterChainID), vaa.Address(emitterBz), payload) vBz, err := v.Marshal() require.NoError(t, err) diff --git a/wormchain/interchaintest/helpers/instantiate_contract.go b/wormchain/interchaintest/helpers/instantiate_contract.go index e627f02865..b3c7a31f81 100644 --- a/wormchain/interchaintest/helpers/instantiate_contract.go +++ b/wormchain/interchaintest/helpers/instantiate_contract.go @@ -47,7 +47,7 @@ func InstantiateContract( code_id, err := strconv.ParseUint(codeId, 10, 64) require.NoError(t, err) payload := createWasmInstantiatePayload(code_id, label, message) - v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload) + v := GenerateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload) vBz, err := v.Marshal() require.NoError(t, err) vHex := hex.EncodeToString(vBz) diff --git a/wormchain/interchaintest/helpers/migrate_contract.go b/wormchain/interchaintest/helpers/migrate_contract.go index 1f57c6a964..4ae1379bd2 100644 --- a/wormchain/interchaintest/helpers/migrate_contract.go +++ b/wormchain/interchaintest/helpers/migrate_contract.go @@ -42,7 +42,7 @@ func MigrateContract( code_id, err := strconv.ParseUint(codeId, 10, 64) require.NoError(t, err) payload := createWasmMigrationPayload(code_id, contractAddr, message) - v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload) + v := GenerateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload) vBz, err := v.Marshal() require.NoError(t, err) vHex := hex.EncodeToString(vBz) diff --git a/wormchain/interchaintest/helpers/store_contract.go b/wormchain/interchaintest/helpers/store_contract.go index 5151ebadd1..548b635f13 100644 --- a/wormchain/interchaintest/helpers/store_contract.go +++ b/wormchain/interchaintest/helpers/store_contract.go @@ -79,7 +79,7 @@ func StoreContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, } payload := createWasmStoreCodePayload(content) - v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload) + v := GenerateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload) vBz, err := v.Marshal() require.NoError(t, err) diff --git a/wormchain/interchaintest/helpers/token_bridge.go b/wormchain/interchaintest/helpers/token_bridge.go index bd30134008..337fa11328 100644 --- a/wormchain/interchaintest/helpers/token_bridge.go +++ b/wormchain/interchaintest/helpers/token_bridge.go @@ -69,7 +69,7 @@ func TbRegisterChainMsg(t *testing.T, chainID uint16, emitterAddr string, guardi payload, err := bodyTbRegisterChain.Serialize() require.NoError(t, err) - v := generateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload) + v := GenerateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payload) vBz, err := v.Marshal() require.NoError(t, err) @@ -106,7 +106,7 @@ func TbRegisterForeignAsset(t *testing.T, tokenAddr string, chainID uint16, emit emitterBz[eIndex-1] = emitterAddr[i-1] eIndex-- } - v := generateVaa(0, guardians, vaa.ChainID(chainID), vaa.Address(emitterBz), payload.Bytes()) + v := GenerateVaa(0, guardians, vaa.ChainID(chainID), vaa.Address(emitterBz), payload.Bytes()) vBz, err := v.Marshal() require.NoError(t, err) diff --git a/wormchain/interchaintest/helpers/vaa.go b/wormchain/interchaintest/helpers/vaa.go index d2dfb84ee7..c327651eba 100644 --- a/wormchain/interchaintest/helpers/vaa.go +++ b/wormchain/interchaintest/helpers/vaa.go @@ -20,7 +20,7 @@ func signVaa(vaaToSign vaa.VAA, signers *guardians.ValSet) vaa.VAA { return vaaToSign } -func generateVaa(index uint32, signers *guardians.ValSet, emitterChain vaa.ChainID, emitterAddr vaa.Address, payload []byte) vaa.VAA { +func GenerateVaa(index uint32, signers *guardians.ValSet, emitterChain vaa.ChainID, emitterAddr vaa.Address, payload []byte) vaa.VAA { v := vaa.VAA{ Version: uint8(1), GuardianSetIndex: index, @@ -58,7 +58,7 @@ func GenerateEmptyVAA( payloadBz, err := vaa.EmptyPayloadVaa(moduleStr, action, chainID) require.NoError(t, err) - v := generateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) + v := GenerateVaa(0, guardians, vaa.GovernanceChain, vaa.GovernanceEmitter, payloadBz) v = signVaa(v, guardians) vBz, err := v.Marshal() diff --git a/wormchain/interchaintest/slashing_params_update_vaa_test.go b/wormchain/interchaintest/slashing_params_update_vaa_test.go new file mode 100644 index 0000000000..c18f642f57 --- /dev/null +++ b/wormchain/interchaintest/slashing_params_update_vaa_test.go @@ -0,0 +1,237 @@ +package ictest + +import ( + "context" + "encoding/hex" + "encoding/json" + "strconv" + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/strangelove-ventures/interchaintest/v4/chain/cosmos" + "github.com/stretchr/testify/require" + "github.com/wormhole-foundation/wormchain/interchaintest/guardians" + "github.com/wormhole-foundation/wormchain/interchaintest/helpers" + "github.com/wormhole-foundation/wormhole/sdk/vaa" +) + +// Params is the slashing params response from the chain +type Params struct { + SignedBlocksWindow string `json:"signed_blocks_window"` + MinSignedPerWindow string `json:"min_signed_per_window"` + DowntimeJailDuration string `json:"downtime_jail_duration"` + SlashFractionDoubleSign string `json:"slash_fraction_double_sign"` + SlashFractionDowntime string `json:"slash_fraction_downtime"` +} + +// createSlashingParamsUpdate creates a slashing params update VAA +// that can be executed on chain via the governance module +func createSlashingParamsUpdate( + signedBlocksWindow uint64, + minSignedPerWindow string, + downtimeJailDurationSeconds uint64, + slashFractionDoubleSign string, + slashFractionDowntime string, +) ([]byte, error) { + minSignedWindow, err := sdk.NewDecFromStr(minSignedPerWindow) + if err != nil { + return nil, err + } + + downtimeJailDurationSeconds = downtimeJailDurationSeconds * uint64(time.Second) + + slashFractionDoubleSignDec, err := sdk.NewDecFromStr(slashFractionDoubleSign) + if err != nil { + return nil, err + } + + slashFractionDowntimeDec, err := sdk.NewDecFromStr(slashFractionDowntime) + if err != nil { + return nil, err + } + + payloadBody := vaa.BodyGatewaySlashingParamsUpdate{ + SignedBlocksWindow: signedBlocksWindow, + MinSignedPerWindow: minSignedWindow.BigInt().Uint64(), + DowntimeJailDuration: downtimeJailDurationSeconds, + SlashFractionDoubleSign: slashFractionDoubleSignDec.BigInt().Uint64(), + SlashFractionDowntime: slashFractionDowntimeDec.BigInt().Uint64(), + } + + return payloadBody.Serialize() +} + +// querySlashingParams queries the slashing params from the chain +func querySlashingParams(ctx context.Context, wormchain *cosmos.CosmosChain) (params slashingtypes.Params, err error) { + // query the slashing params + res, _, err := wormchain.GetFullNode().ExecQuery(ctx, "slashing", "params") + if err != nil { + return + } + + var slashingParams Params + err = json.Unmarshal(res, &slashingParams) + if err != nil { + return + } + + params.SignedBlocksWindow, err = strconv.ParseInt(slashingParams.SignedBlocksWindow, 10, 64) + if err != nil { + return + } + + params.MinSignedPerWindow, err = sdk.NewDecFromStr(slashingParams.MinSignedPerWindow) + if err != nil { + return + } + + params.DowntimeJailDuration, err = time.ParseDuration(slashingParams.DowntimeJailDuration) + if err != nil { + return + } + + params.SlashFractionDoubleSign, err = sdk.NewDecFromStr(slashingParams.SlashFractionDoubleSign) + if err != nil { + return + } + + params.SlashFractionDowntime, err = sdk.NewDecFromStr(slashingParams.SlashFractionDowntime) + if err != nil { + return + } + + return +} + +// createAndExecuteVaa creates and executes a governance VAA on the wormchain +func createAndExecuteVaa(ctx context.Context, guardians *guardians.ValSet, wormchain *cosmos.CosmosChain, payloadBytes []byte) error { + v := helpers.GenerateVaa(0, guardians, vaa.ChainID(vaa.GovernanceChain), vaa.Address(vaa.GovernanceEmitter), payloadBytes) + vBz, err := v.Marshal() + if err != nil { + return err + } + vHex := hex.EncodeToString(vBz) + + _, err = wormchain.FullNodes[0].ExecTx(ctx, "faucet", "wormhole", "execute-gateway-governance-vaa", vHex) + if err != nil { + return err + } + + return nil +} + +func verifyParams(t *testing.T, ctx context.Context, wormchain *cosmos.CosmosChain) { + // query the slashing params + slashingParams, err := querySlashingParams(ctx, wormchain) + require.NoError(t, err) + + // validate the slashing params did not change + require.Equal(t, int64(200), slashingParams.SignedBlocksWindow) + require.Equal(t, "0.100000000000000000", slashingParams.MinSignedPerWindow.String()) + require.Equal(t, 300*time.Second, slashingParams.DowntimeJailDuration) + require.Equal(t, "0.200000000000000000", slashingParams.SlashFractionDoubleSign.String()) + require.Equal(t, "0.300000000000000000", slashingParams.SlashFractionDowntime.String()) +} + +// TestSlashingParamsUpdateVaa tests the execution of a slashing params update VAA +// and verifies that the governance module correctly updates the slashing params +func TestSlashingParamsUpdateVaa(t *testing.T) { + if testing.Short() { + t.Skip() + } + + t.Parallel() + + // base setup + guardians := guardians.CreateValSet(t, 2) + chains := CreateChains(t, "local", *guardians) + ctx, _, _, _ := BuildInterchain(t, chains) + require.NotNil(t, ctx) + + wormchain := chains[0].(*cosmos.CosmosChain) + + // ------------------------------ + + // create a governance VAA -- happy path + payloadBytes, err := createSlashingParamsUpdate(200, "0.1", 300, "0.2", "0.3") + require.NoError(t, err) + + // create and send + err = createAndExecuteVaa(ctx, guardians, wormchain, payloadBytes) + require.NoError(t, err) + + // verify the slashing params + verifyParams(t, ctx, wormchain) + + // ------------------------------ + + // create a governance VAA - invalid signed blocks window + payloadBytes, err = createSlashingParamsUpdate(0, "0.1", 300, "0.2", "0.3") + require.NoError(t, err) + + // create and send + err = createAndExecuteVaa(ctx, guardians, wormchain, payloadBytes) + // TODO: ON COSMOS SDK V0.47 - WILL ERROR + require.NoError(t, err) + + // verify the slashing params + verifyParams(t, ctx, wormchain) + + // ------------------------------ + + // create a governance VAA - invalid downtime jail duration + payloadBytes, err = createSlashingParamsUpdate(200, "0.1", 0, "0.2", "0.3") + require.NoError(t, err) + + // create and send + err = createAndExecuteVaa(ctx, guardians, wormchain, payloadBytes) + // TODO: ON COSMOS SDK V0.47 - WILL ERROR + require.NoError(t, err) + + // verify the slashing params + verifyParams(t, ctx, wormchain) + + // ------------------------------ + + // create a governance VAA - invalid slash fraction double sign + payloadBytes, err = createSlashingParamsUpdate(200, "0.1", 300, "2.0", "0.3") + require.NoError(t, err) + + // create and send + err = createAndExecuteVaa(ctx, guardians, wormchain, payloadBytes) + // TODO: ON COSMOS SDK V0.47 - WILL ERROR + require.NoError(t, err) + + // verify the slashing params + verifyParams(t, ctx, wormchain) + + // ------------------------------ + + // create a governance VAA - invalid slash fraction downtime + payloadBytes, err = createSlashingParamsUpdate(200, "0.1", 300, "0.2", "2.0") + require.NoError(t, err) + + // create and send + err = createAndExecuteVaa(ctx, guardians, wormchain, payloadBytes) + // TODO: ON COSMOS SDK V0.47 - WILL ERROR + require.NoError(t, err) + + // verify the slashing params + verifyParams(t, ctx, wormchain) + + // ------------------------------ + + // create a governance VAA - negative string values + payloadBytes, err = createSlashingParamsUpdate(200, "-0.1", 300, "-0.2", "-2.0") + require.NoError(t, err) + + // create and send + err = createAndExecuteVaa(ctx, guardians, wormchain, payloadBytes) + // TODO: ON COSMOS SDK V0.47 - WILL ERROR + require.NoError(t, err) + + // verify the slashing params + verifyParams(t, ctx, wormchain) +} diff --git a/wormchain/testutil/keeper/wormhole.go b/wormchain/testutil/keeper/wormhole.go index dcc9a80164..616b427321 100644 --- a/wormchain/testutil/keeper/wormhole.go +++ b/wormchain/testutil/keeper/wormhole.go @@ -1,140 +1,32 @@ package keeper import ( - "os" "testing" "time" - "github.com/CosmWasm/wasmd/x/wasm" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/version" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/wormhole-foundation/wormchain/app" - "github.com/wormhole-foundation/wormchain/app/wasm_handlers" + "github.com/wormhole-foundation/wormchain/app/apptesting" "github.com/wormhole-foundation/wormchain/x/wormhole/keeper" - "github.com/wormhole-foundation/wormchain/x/wormhole/types" - paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/spm/cosmoscmd" - "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" ) -func WormholeKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { +func WormholeKeeper(t *testing.T) (*keeper.Keeper, sdk.Context) { k, _, _, ctx := WormholeKeeperAndWasmd(t) return k, ctx } -func WormholeKeeperAndWasmd(t testing.TB) (*keeper.Keeper, wasmkeeper.Keeper, *wasmkeeper.PermissionedKeeper, sdk.Context) { - keys := sdk.NewKVStoreKeys( - authtypes.StoreKey, - paramstypes.StoreKey, - capabilitytypes.StoreKey, - types.StoreKey, - wasmtypes.StoreKey, - ) - tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) - memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, types.MemStoreKey) - maccPerms := map[string][]string{} +func WormholeKeeperAndWasmd(t *testing.T) (*keeper.Keeper, wasmkeeper.Keeper, *wasmkeeper.PermissionedKeeper, sdk.Context) { + app := apptesting.Setup(t, false, 0) - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - stateStore.MountStoreWithDB(keys[authtypes.StoreKey], sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(keys[paramstypes.StoreKey], sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(keys[capabilitytypes.StoreKey], sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(keys[types.StoreKey], sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(keys[wasmtypes.StoreKey], sdk.StoreTypeIAVL, db) - stateStore.MountStoreWithDB(memKeys[types.MemStoreKey], sdk.StoreTypeMemory, nil) - stateStore.MountStoreWithDB(tkeys[paramstypes.TStoreKey], sdk.StoreTypeTransient, nil) - require.NoError(t, stateStore.LoadLatestVersion()) - - encodingConfig := cosmoscmd.MakeEncodingConfig(app.ModuleBasics) - appCodec := encodingConfig.Marshaler - amino := encodingConfig.Amino - - paramsKeeper := paramskeeper.NewKeeper(appCodec, amino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) - paramsKeeper.Subspace(types.ModuleName) - paramsKeeper.Subspace(wasm.ModuleName) - - paramsKeeper.Subspace(authtypes.ModuleName) - subspace_auth, _ := paramsKeeper.GetSubspace(authtypes.ModuleName) - accountKeeper := authkeeper.NewAccountKeeper( - appCodec, keys[authtypes.StoreKey], subspace_auth, authtypes.ProtoBaseAccount, maccPerms, - ) - // this line is used by starport scaffolding # stargate/app/paramSubspace - - subspaceWasmd, _ := paramsKeeper.GetSubspace(wasmtypes.ModuleName) - - bApp := baseapp.NewBaseApp("wormchain", log.NewNopLogger(), db, encodingConfig.TxConfig.TxDecoder()) - bApp.SetVersion(version.Version) - bApp.SetInterfaceRegistry(encodingConfig.InterfaceRegistry) - - appapp := &app.App{ - BaseApp: bApp, - } - - k := keeper.NewKeeper( - appCodec, - keys[types.StoreKey], - memKeys[types.MemStoreKey], - accountKeeper, - nil, - ) - - supportedFeatures := "iterator,staking,stargate,wormhole" - appapp.WormholeKeeper = *k - - appapp.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) - scopedWasmKeeper := appapp.CapabilityKeeper.ScopeToModule(wasm.ModuleName) - - wasmDir := os.TempDir() - wasmKeeper := wasm.NewKeeper( - appCodec, - keys[wasmtypes.StoreKey], - subspaceWasmd, - accountKeeper, - &wasm_handlers.BankKeeperHandler{}, - &wasm_handlers.StakingKeeperHandler{}, - &wasm_handlers.DistributionKeeperHandler{}, - &wasm_handlers.ChannelKeeperHandler{}, - &wasm_handlers.PortKeeperHandler{}, - scopedWasmKeeper, - &wasm_handlers.ICS20TransferPortSourceHandler{}, - appapp.WormholeKeeper, - appapp.MsgServiceRouter(), - appapp.GRPCQueryRouter(), - wasmDir, - wasm.DefaultWasmConfig(), - supportedFeatures, - wasmkeeper.WithQueryPlugins(keeper.NewCustomQueryHandler(appapp.WormholeKeeper)), - ) - ctx := sdk.NewContext(stateStore, tmproto.Header{ - Time: time.Now(), + ctx := app.BaseApp.NewContext(false, tmproto.Header{ + ChainID: apptesting.SimAppChainID, // The height should be at least 1, because the allowlist antehandler // passes everything at height 0 for gen tx's. Height: 1, - }, false, log.NewNopLogger()) - appapp.MountKVStores(keys) - appapp.MountTransientStores(tkeys) - appapp.MountMemoryStores(memKeys) - - wasmGenState := wasmtypes.GenesisState{} - wasmGenState.Params.CodeUploadAccess = wasmtypes.DefaultUploadAccess - wasmGenState.Params.InstantiateDefaultPermission = wasmtypes.AccessTypeEverybody - wasmKeeper.SetParams(ctx, wasmGenState.Params) - permissionedWasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(wasmKeeper) - appapp.WormholeKeeper.SetWasmdKeeper(permissionedWasmKeeper) - k.SetWasmdKeeper(permissionedWasmKeeper) + Time: time.Now(), + }) - return k, wasmKeeper, permissionedWasmKeeper, ctx + return &app.WormholeKeeper, *app.GetWasmKeeper(), app.ContractKeeper, ctx } diff --git a/wormchain/x/wormhole/client/cli/genesis.go b/wormchain/x/wormhole/client/cli/genesis.go index 2d43fcc9e8..b74e949a87 100644 --- a/wormchain/x/wormhole/client/cli/genesis.go +++ b/wormchain/x/wormhole/client/cli/genesis.go @@ -38,6 +38,11 @@ const FLAG_ACTION = "action" const FLAG_CHAIN = "chain" const FLAG_PUBLIC_KEY = "public-key" const FLAG_NEXT_INDEX = "next-index" +const FLAG_SIGNED_BLOCKS_WINDOW = "signed-blocks-window" +const FLAG_MIN_SIGNED_PER_WINDOW = "min-signed-per-window" +const FLAG_DOWNTIME_JAIL_DURATION = "downtime-jail-duration" +const FLAG_SLASH_FRACTION_DOUBLE_SIGN = "slash-fraction-double-sign" +const FLAG_SLASH_FRACTION_DOWNTIME = "slash-fraction-downtime" // GetGenesisCmd returns the genesis related commands for this module func GetGenesisCmd() *cobra.Command { @@ -54,6 +59,7 @@ func GetGenesisCmd() *cobra.Command { cmd.AddCommand(CmdGenerateVaa()) cmd.AddCommand(CmdGenerateGovernanceVaa()) cmd.AddCommand(CmdGenerateGuardianSetUpdatea()) + cmd.AddCommand(CmdGenerateSlashingParamsUpdateVaa()) cmd.AddCommand(CmdTestSignAddress()) return cmd @@ -216,6 +222,7 @@ func addVaaFlags(cmd *cobra.Command) { cmd.Flags().Uint64(FLAG_SEQUENCE, 0, "sequence number") cmd.Flags().Uint32(FLAG_NONCE, 0, "nonce") cmd.Flags().String(FLAG_PAYLOAD, "", "payload (hex format)") + } func addGovVaaFlags(cmd *cobra.Command) { cmd.Flags().String(FLAG_MODULE, "", "module (ascii string)") @@ -377,7 +384,7 @@ func CmdGenerateGuardianSetUpdatea() *cobra.Command { } action := vaa.ActionGuardianSetUpdate - chain := 3104 + chain := vaa.ChainIDWormchain module := [32]byte{} copy(module[:], vaa.CoreModule) msg := types.NewGovernanceMessage(module, byte(action), uint16(chain), set_update) @@ -405,6 +412,115 @@ func CmdGenerateGuardianSetUpdatea() *cobra.Command { return cmd } +func CmdGenerateSlashingParamsUpdateVaa() *cobra.Command { + cmd := &cobra.Command{ + Use: "generate-slashing-params-update-vaa", + Short: "generate and sign a governance vaa to update the slashing params", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) (err error) { + + privateKeys := []*ecdsa.PrivateKey{} + privateKeysFiles, err := cmd.Flags().GetStringArray(FLAG_KEY) + if err != nil { + return err + } + for _, privFile := range privateKeysFiles { + priv, err := ImportKeyFromFile(privFile) + if err != nil { + return err + } + privateKeys = append(privateKeys, priv) + } + v, err := parseVaaFromFlags(cmd) + if err != nil { + return err + } + + signedBlocksWindow, err := cmd.Flags().GetUint64(FLAG_SIGNED_BLOCKS_WINDOW) + if err != nil { + return err + } + + minSignedPerWindow, err := cmd.Flags().GetString(FLAG_MIN_SIGNED_PER_WINDOW) + if err != nil { + return err + } + minSignedPerWindowDec, err := sdk.NewDecFromStr(minSignedPerWindow) + if err != nil { + return err + } + if minSignedPerWindowDec.LT(sdk.ZeroDec()) || minSignedPerWindowDec.GT(sdk.OneDec()) { + return fmt.Errorf("min signed per window must be greater than or equal to 0.000000000000000000 and less than or equal to 1.000000000000000000") + } + + downtimeJailDuration, err := cmd.Flags().GetUint64(FLAG_DOWNTIME_JAIL_DURATION) + if err != nil { + return err + } + + slashFractionDoubleSign, err := cmd.Flags().GetString(FLAG_SLASH_FRACTION_DOUBLE_SIGN) + if err != nil { + return err + } + slashFractionDoubleSignDec, err := sdk.NewDecFromStr(slashFractionDoubleSign) + if err != nil { + return err + } + if slashFractionDoubleSignDec.LT(sdk.ZeroDec()) || slashFractionDoubleSignDec.GT(sdk.OneDec()) { + return fmt.Errorf("slash fraction double sign must be greater than or equal to 0.000000000000000000 and less than or equal to 1.000000000000000000") + } + + slashFractionDowntime, err := cmd.Flags().GetString(FLAG_SLASH_FRACTION_DOWNTIME) + if err != nil { + return err + } + slashFractionDowntimeDec, err := sdk.NewDecFromStr(slashFractionDowntime) + if err != nil { + return err + } + if slashFractionDowntimeDec.LT(sdk.ZeroDec()) || slashFractionDowntimeDec.GT(sdk.OneDec()) { + return fmt.Errorf("slash fraction downtime must be greater than or equal to 0.000000000000000000 and less than or equal to 1.000000000000000000") + } + + 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 { + v.AddSignature(key, uint8(i)) + } + + v_bz, err := v.Marshal() + if err != nil { + return err + } + fmt.Println(hex.EncodeToString(v_bz)) + + return nil + }, + } + + addVaaFlags(cmd) + cmd.Flags().Uint64(FLAG_SIGNED_BLOCKS_WINDOW, 100, "signed blocks window") + cmd.Flags().String(FLAG_MIN_SIGNED_PER_WINDOW, "0.500000000000000000", "min signed per window") + cmd.Flags().Uint64(FLAG_DOWNTIME_JAIL_DURATION, uint64(600*time.Second), "downtime jail duration (seconds)") + cmd.Flags().String(FLAG_SLASH_FRACTION_DOUBLE_SIGN, "0.050000000000000000", "slash fraction double sign") + cmd.Flags().String(FLAG_SLASH_FRACTION_DOWNTIME, "0.010000000000000000", "slash fraction downtime") + + return cmd +} + func CmdTestSignAddress() *cobra.Command { cmd := &cobra.Command{ Use: "test-sign-address", diff --git a/wormchain/x/wormhole/keeper/keeper.go b/wormchain/x/wormhole/keeper/keeper.go index a3eb4652c1..8967c3627d 100644 --- a/wormchain/x/wormhole/keeper/keeper.go +++ b/wormchain/x/wormhole/keeper/keeper.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" "github.com/wormhole-foundation/wormchain/x/wormhole/types" ) @@ -17,13 +18,15 @@ type ( storeKey sdk.StoreKey memKey sdk.StoreKey - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper - wasmdKeeper types.WasmdKeeper - upgradeKeeper upgradekeeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + wasmdKeeper types.WasmdKeeper + upgradeKeeper upgradekeeper.Keeper + slashingKeeper slashingkeeper.Keeper - setWasmd bool - setUpgrade bool + setWasmd bool + setUpgrade bool + setSlashing bool } ) @@ -59,6 +62,11 @@ func (k *Keeper) SetUpgradeKeeper(keeper upgradekeeper.Keeper) { k.setUpgrade = true } +func (k *Keeper) SetSlashingKeeper(keeper slashingkeeper.Keeper) { + k.slashingKeeper = keeper + k.setSlashing = true +} + func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } diff --git a/wormchain/x/wormhole/keeper/msg_server_allowlist_test.go b/wormchain/x/wormhole/keeper/msg_server_allowlist_test.go index 9087fd78f3..c5ea497411 100644 --- a/wormchain/x/wormhole/keeper/msg_server_allowlist_test.go +++ b/wormchain/x/wormhole/keeper/msg_server_allowlist_test.go @@ -178,8 +178,7 @@ func TestAllowlistEntry(t *testing.T) { func TestAllowlistEntryAnteHandler(t *testing.T) { k, ctx := keepertest.WormholeKeeper(t) - guardians, privateKeys := createNGuardianValidator(k, ctx, 10) - _ = privateKeys + guardians, _ := createNGuardianValidator(k, ctx, 10) k.SetConfig(ctx, types.Config{ GovernanceEmitter: vaa.GovernanceEmitter[:], GovernanceChain: uint32(vaa.GovernanceChain), diff --git a/wormchain/x/wormhole/keeper/msg_server_execute_gateway_governance_vaa.go b/wormchain/x/wormhole/keeper/msg_server_execute_gateway_governance_vaa.go index 415a8b387e..611d068734 100644 --- a/wormchain/x/wormhole/keeper/msg_server_execute_gateway_governance_vaa.go +++ b/wormchain/x/wormhole/keeper/msg_server_execute_gateway_governance_vaa.go @@ -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" @@ -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 } @@ -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 +} diff --git a/wormchain/x/wormhole/keeper/msg_server_execute_gateway_governance_vaa_test.go b/wormchain/x/wormhole/keeper/msg_server_execute_gateway_governance_vaa_test.go new file mode 100644 index 0000000000..6450e4a52a --- /dev/null +++ b/wormchain/x/wormhole/keeper/msg_server_execute_gateway_governance_vaa_test.go @@ -0,0 +1,52 @@ +package keeper_test + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + keepertest "github.com/wormhole-foundation/wormchain/testutil/keeper" + "github.com/wormhole-foundation/wormchain/x/wormhole/keeper" + "github.com/wormhole-foundation/wormchain/x/wormhole/types" + "github.com/wormhole-foundation/wormhole/sdk/vaa" +) + +func TestExecuteSlashingParamsUpdate(t *testing.T) { + k, ctx := keepertest.WormholeKeeper(t) + guardians, privateKeys := createNGuardianValidator(k, ctx, 10) + k.SetConfig(ctx, types.Config{ + GovernanceEmitter: vaa.GovernanceEmitter[:], + GovernanceChain: uint32(vaa.GovernanceChain), + ChainId: uint32(vaa.ChainIDWormchain), + GuardianSetExpiration: 86400, + }) + signer_bz := [20]byte{} + signer := sdk.AccAddress(signer_bz[:]) + + set := createNewGuardianSet(k, ctx, guardians) + k.SetConsensusGuardianSetIndex(ctx, types.ConsensusGuardianSetIndex{Index: set.Index}) + + context := sdk.WrapSDKContext(ctx) + msgServer := keeper.NewMsgServerImpl(*k) + + // create governance to update slashing params + payloadBody := vaa.BodyGatewaySlashingParamsUpdate{ + SignedBlocksWindow: uint64(100), + MinSignedPerWindow: sdk.NewDecWithPrec(5, 1).BigInt().Uint64(), + DowntimeJailDuration: uint64(600 * time.Second), + SlashFractionDoubleSign: sdk.NewDecWithPrec(5, 2).BigInt().Uint64(), + SlashFractionDowntime: sdk.NewDecWithPrec(1, 2).BigInt().Uint64(), + } + payloadBz, err := payloadBody.Serialize() + assert.NoError(t, err) + + v := generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payloadBz) + vBz, _ := v.Marshal() + res, err := msgServer.ExecuteGatewayGovernanceVaa(context, &types.MsgExecuteGatewayGovernanceVaa{ + Signer: signer.String(), + Vaa: vBz, + }) + assert.NoError(t, err) + assert.Equal(t, &types.EmptyResponse{}, res) +} diff --git a/wormchain/x/wormhole/keeper/msg_server_execute_governance_vaa_test.go b/wormchain/x/wormhole/keeper/msg_server_execute_governance_vaa_test.go index 462a6dd46c..5e35b2a859 100644 --- a/wormchain/x/wormhole/keeper/msg_server_execute_governance_vaa_test.go +++ b/wormchain/x/wormhole/keeper/msg_server_execute_governance_vaa_test.go @@ -34,7 +34,6 @@ func createExecuteGovernanceVaaPayload(k *keeper.Keeper, ctx sdk.Context, num_gu func TestExecuteGovernanceVAA(t *testing.T) { k, ctx := keepertest.WormholeKeeper(t) guardians, privateKeys := createNGuardianValidator(k, ctx, 10) - _ = privateKeys k.SetConfig(ctx, types.Config{ GovernanceEmitter: vaa.GovernanceEmitter[:], GovernanceChain: uint32(vaa.GovernanceChain), diff --git a/wormchain/x/wormhole/keeper/msg_server_test.go b/wormchain/x/wormhole/keeper/msg_server_test.go index 09fe3287d4..723ef7874b 100644 --- a/wormchain/x/wormhole/keeper/msg_server_test.go +++ b/wormchain/x/wormhole/keeper/msg_server_test.go @@ -10,7 +10,7 @@ import ( "github.com/wormhole-foundation/wormchain/x/wormhole/types" ) -func setupMsgServer(t testing.TB) (types.MsgServer, context.Context) { +func setupMsgServer(t *testing.T) (types.MsgServer, context.Context) { k, ctx := keepertest.WormholeKeeper(t) return keeper.NewMsgServerImpl(*k), sdk.WrapSDKContext(ctx) } diff --git a/wormchain/x/wormhole/keeper/msg_server_wasmd_test.go b/wormchain/x/wormhole/keeper/msg_server_wasmd_test.go index d78c0cab52..7cacb2ec0a 100644 --- a/wormchain/x/wormhole/keeper/msg_server_wasmd_test.go +++ b/wormchain/x/wormhole/keeper/msg_server_wasmd_test.go @@ -134,7 +134,6 @@ func setupAccountantAndGuardianSet(t *testing.T, ctx sdk.Context, k *keeper.Keep func TestWasmdStoreCode(t *testing.T) { k, ctx := keepertest.WormholeKeeper(t) guardians, privateKeys := createNGuardianValidator(k, ctx, 10) - _ = privateKeys k.SetConfig(ctx, types.Config{ GovernanceEmitter: vaa.GovernanceEmitter[:], GovernanceChain: uint32(vaa.GovernanceChain), @@ -203,7 +202,6 @@ func TestWasmdStoreCode(t *testing.T) { func TestWasmdInstantiateContract(t *testing.T) { k, ctx := keepertest.WormholeKeeper(t) guardians, privateKeys := createNGuardianValidator(k, ctx, 10) - _ = privateKeys k.SetConfig(ctx, types.Config{ GovernanceEmitter: vaa.GovernanceEmitter[:], GovernanceChain: uint32(vaa.GovernanceChain),