wormhole/wormchain/x/wormhole/governance.go

110 lines
3.4 KiB
Go

package wormhole
import (
"bytes"
"encoding/binary"
"fmt"
"io"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/wormhole-foundation/wormchain/x/wormhole/keeper"
"github.com/wormhole-foundation/wormchain/x/wormhole/types"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
)
// NewWormholeGovernanceProposalHandler creates a governance handler to manage new proposal types.
// It enables GuardianSetProposal to update the guardian set and GenericWormholeMessageProposal to emit a generic wormhole
// message from the governance emitter.
func NewWormholeGovernanceProposalHandler(k keeper.Keeper) govtypes.Handler {
return func(ctx sdk.Context, content govtypes.Content) error {
switch c := content.(type) {
case *types.GuardianSetUpdateProposal:
return handleGuardianSetUpdateProposal(ctx, k, c)
case *types.GovernanceWormholeMessageProposal:
return handleGovernanceWormholeMessageProposal(ctx, k, c)
default:
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized wormhole proposal content type: %T", c)
}
}
}
func handleGuardianSetUpdateProposal(ctx sdk.Context, k keeper.Keeper, proposal *types.GuardianSetUpdateProposal) error {
err := k.UpdateGuardianSet(ctx, types.GuardianSet{
Index: proposal.NewGuardianSet.Index,
Keys: proposal.NewGuardianSet.Keys,
ExpirationTime: 0,
})
if err != nil {
return fmt.Errorf("failed to update guardian set: %w", err)
}
config, ok := k.GetConfig(ctx)
if !ok {
return types.ErrNoConfig
}
// Post a wormhole guardian set update governance message
message := &bytes.Buffer{}
// Header
message.Write(vaa.CoreModule)
MustWrite(message, binary.BigEndian, uint8(2))
MustWrite(message, binary.BigEndian, uint16(0))
// Body
MustWrite(message, binary.BigEndian, proposal.NewGuardianSet.Index)
MustWrite(message, binary.BigEndian, uint8(len(proposal.NewGuardianSet.Keys)))
for _, key := range proposal.NewGuardianSet.Keys {
message.Write(key)
}
emitterAddress, err := types.EmitterAddressFromBytes32(config.GovernanceEmitter)
if err != nil {
return fmt.Errorf("failed to post message: %w", err)
}
err = k.PostMessage(ctx, emitterAddress, 0, message.Bytes())
if err != nil {
return fmt.Errorf("failed to post message: %w", err)
}
return nil
}
func handleGovernanceWormholeMessageProposal(ctx sdk.Context, k keeper.Keeper, proposal *types.GovernanceWormholeMessageProposal) error {
config, ok := k.GetConfig(ctx)
if !ok {
return types.ErrNoConfig
}
// Post a wormhole governance message
message := &bytes.Buffer{}
message.Write(proposal.Module)
MustWrite(message, binary.BigEndian, uint8(proposal.Action))
MustWrite(message, binary.BigEndian, uint16(proposal.TargetChain))
message.Write(proposal.Payload)
emitterAddress, err := types.EmitterAddressFromBytes32(config.GovernanceEmitter)
if err != nil {
return fmt.Errorf("failed to post message: %w", err)
}
err = k.PostMessage(ctx, emitterAddress, 0, message.Bytes())
if err != nil {
return fmt.Errorf("failed to post message: %w", err)
}
return nil
}
// MustWrite calls binary.Write and panics on errors
func MustWrite(w io.Writer, order binary.ByteOrder, data interface{}) {
if err := binary.Write(w, order, data); err != nil {
panic(fmt.Errorf("failed to write binary data: %v", data).Error())
}
}