node/admin: add generalised EVM call governance handler

Handles governance requests of the form:

```
current_set_index: 4
messages: {
  sequence: 4513077582118919631
  nonce: 2809988562
  evm_call: {
    chain_id: 3
    governance_contract: "0xD8E4C2DbDd2e2bd8F1336EA691dBFF6952B1a6eB"
    target_contract: "0xF890982f9310df57d00f659cf4fd87e65adEd8d7"
    abi_encoded_call: "6497f75a000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000f890982f9310df57d00f659cf4fd87e65aded8d70000000000000000000000000000000000000000000000000000000000000140bebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebe000000000000000000000000000000000000000000000000000000000000000268690000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004beefface00000000000000000000000000000000000000000000000000000000"
  }
}
```
This commit is contained in:
Csongor Kiss 2024-04-22 20:25:08 +01:00
parent 9af1fac9e1
commit 1fc0df91b6
4 changed files with 603 additions and 419 deletions

View File

@ -577,6 +577,28 @@ func wormholeRelayerSetDefaultDeliveryProvider(req *nodev1.WormholeRelayerSetDef
return v, nil
}
func evmCallToVaa(evmCall *nodev1.EvmCall, timestamp time.Time, guardianSetIndex, nonce uint32, sequence uint64) (*vaa.VAA, error) {
var governanceContract [32]byte
copy(governanceContract[:], ethcommon.HexToAddress(evmCall.GovernanceContract).Bytes())
var targetContract [32]byte
copy(targetContract[:], ethcommon.HexToAddress(evmCall.TargetContract).Bytes())
payload, err := hex.DecodeString(evmCall.AbiEncodedCall)
if err != nil {
return nil, fmt.Errorf("failed to decode ABI encoded call: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyGeneralPurposeGovernanceEvm{
ChainID: vaa.ChainID(evmCall.ChainId),
GovernanceContract: governanceContract,
TargetContract: targetContract,
Payload: payload,
}.Serialize())
return v, nil
}
func GovMsgToVaa(message *nodev1.GovernanceMessage, currentSetIndex uint32, timestamp time.Time) (*vaa.VAA, error) {
var (
v *vaa.VAA
@ -620,6 +642,8 @@ func GovMsgToVaa(message *nodev1.GovernanceMessage, currentSetIndex uint32, time
v, err = ibcUpdateChannelChain(payload.IbcUpdateChannelChain, timestamp, currentSetIndex, message.Nonce, message.Sequence)
case *nodev1.GovernanceMessage_WormholeRelayerSetDefaultDeliveryProvider:
v, err = wormholeRelayerSetDefaultDeliveryProvider(payload.WormholeRelayerSetDefaultDeliveryProvider, timestamp, currentSetIndex, message.Nonce, message.Sequence)
case *nodev1.GovernanceMessage_EvmCall:
v, err = evmCallToVaa(payload.EvmCall, timestamp, currentSetIndex, message.Nonce, message.Sequence)
default:
panic(fmt.Sprintf("unsupported VAA type: %T", payload))
}

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ service NodePrivilegedService {
// ChainGovernorReleasePendingVAA release a VAA from the chain governor pending list, publishing it immediately.
rpc ChainGovernorReleasePendingVAA (ChainGovernorReleasePendingVAARequest) returns (ChainGovernorReleasePendingVAAResponse);
// ChainGovernorResetReleaseTimer resets the release timer for a chain governor pending VAA to the configured maximum.
rpc ChainGovernorResetReleaseTimer (ChainGovernorResetReleaseTimerRequest) returns (ChainGovernorResetReleaseTimerResponse);
@ -51,10 +51,10 @@ service NodePrivilegedService {
rpc SignExistingVAA (SignExistingVAARequest) returns (SignExistingVAAResponse);
// DumpRPCs returns the RPCs being used by the guardian
rpc DumpRPCs (DumpRPCsRequest) returns (DumpRPCsResponse);
rpc DumpRPCs (DumpRPCsRequest) returns (DumpRPCsResponse);
// GetMissingVAAs returns the VAAs from a cloud function that need to be reobserved.
rpc GetAndObserveMissingVAAs (GetAndObserveMissingVAAsRequest) returns (GetAndObserveMissingVAAsResponse);
rpc GetAndObserveMissingVAAs (GetAndObserveMissingVAAsRequest) returns (GetAndObserveMissingVAAsResponse);
}
message InjectGovernanceVAARequest {
@ -85,7 +85,7 @@ message GovernanceMessage {
GuardianSetUpdate guardian_set = 10;
ContractUpgrade contract_upgrade = 11;
// Token bridge, NFT module, and Wormhole Relayer module (for the first two)
// Token bridge, NFT module, and Wormhole Relayer module (for the first two)
BridgeRegisterChain bridge_register_chain = 12;
BridgeUpgradeContract bridge_contract_upgrade = 13;
@ -117,6 +117,9 @@ message GovernanceMessage {
IbcUpdateChannelChain ibc_update_channel_chain = 21;
// Wormhole Relayer module
WormholeRelayerSetDefaultDeliveryProvider wormhole_relayer_set_default_delivery_provider = 22;
// Generic governance
EvmCall evm_call = 28;
}
}
@ -191,7 +194,7 @@ message AccountantModifyBalance {
// ContractUpgrade represents a Wormhole contract update to be submitted to and signed by the node.
message ContractUpgrade {
// ID of the chain where the Wormhole contract should be updated (uint8).
// ID of the chain where the Wormhole contract should be updated (uint16).
uint32 chain_id = 1;
// Hex-encoded address (without leading 0x) address of the new program/contract.
@ -417,3 +420,17 @@ message GetAndObserveMissingVAAsRequest {
message GetAndObserveMissingVAAsResponse {
string response =1;
}
// EvmCall represents a generic EVM call that can be executed by the generalized governance contract.
message EvmCall {
// ID of the chain where the action should be executed (uint16).
uint32 chain_id = 1;
// Address of the governance contract (eth address starting with 0x)
string governance_contract = 2;
// Address of the governed contract (eth address starting with 0x)
string target_contract = 3;
string abi_encoded_call = 4;
}

View File

@ -55,6 +55,13 @@ var WormholeRelayerModule = [32]byte{
}
var WormholeRelayerModuleStr = string(WormholeRelayerModule[:])
var GeneralPurposeGovernanceModule = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C,
0x50, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x47, 0x6F, 0x76, 0x65, 0x72, 0x6E, 0x61, 0x6E,
0x63, 0x65,
}
var GeneralPurposeGovernanceModuleStr = string(GeneralPurposeGovernanceModule[:])
type GovernanceAction uint8
var (
@ -216,6 +223,14 @@ type (
ChainID ChainID
NewDefaultDeliveryProviderAddress Address
}
// BodyGeneralPurposeGovernanceEvm is a general purpose governance message for EVM chains
BodyGeneralPurposeGovernanceEvm struct {
ChainID ChainID
GovernanceContract Address
TargetContract Address
Payload []byte
}
)
func (b BodyContractUpgrade) Serialize() []byte {
@ -402,6 +417,16 @@ func (r BodyWormholeRelayerSetDefaultDeliveryProvider) Serialize() []byte {
return serializeBridgeGovernanceVaa(WormholeRelayerModuleStr, WormholeRelayerSetDefaultDeliveryProvider, r.ChainID, payload.Bytes())
}
func (r BodyGeneralPurposeGovernanceEvm) Serialize() []byte {
payload := &bytes.Buffer{}
payload.Write(r.GovernanceContract[:])
payload.Write(r.TargetContract[:])
// write payload len as uint16
MustWrite(payload, binary.BigEndian, uint16(len(r.Payload)))
payload.Write(r.Payload)
return serializeBridgeGovernanceVaa(GeneralPurposeGovernanceModuleStr, GovernanceAction(1), r.ChainID, payload.Bytes())
}
func EmptyPayloadVaa(module string, actionId GovernanceAction, chainId ChainID) []byte {
return serializeBridgeGovernanceVaa(module, actionId, chainId, []byte{})
}