Skip to content

Commit

Permalink
node/admin: add generalised Solana call governance handler
Browse files Browse the repository at this point in the history
handles governance requests of the form

```
current_set_index: 4
messages: {
  sequence: 4513077582118919631
  nonce: 2809988562
  solana_call: {
    chain_id: 3
    governance_contract: "3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5"
    encoded_instruction: "BEEFFACE"
  }
}
```
  • Loading branch information
kcsongor committed Apr 22, 2024
1 parent 62fd2b9 commit 3c3de23
Show file tree
Hide file tree
Showing 5 changed files with 642 additions and 421 deletions.
52 changes: 52 additions & 0 deletions node/cmd/guardiand/admintemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ func init() {
// evm call command
AdminClientGeneralPurposeGovernanceEvmCallCmd.Flags().AddFlagSet(generalPurposeGovernanceFlagSet)
TemplateCmd.AddCommand(AdminClientGeneralPurposeGovernanceEvmCallCmd)
// solana call command
AdminClientGeneralPurposeGovernanceSolanaCallCmd.Flags().AddFlagSet(generalPurposeGovernanceFlagSet)
TemplateCmd.AddCommand(AdminClientGeneralPurposeGovernanceSolanaCallCmd)
}

var TemplateCmd = &cobra.Command{
Expand Down Expand Up @@ -313,6 +316,12 @@ var AdminClientGeneralPurposeGovernanceEvmCallCmd = &cobra.Command{
Run: runGeneralPurposeGovernanceEvmCallTemplate,
}

var AdminClientGeneralPurposeGovernanceSolanaCallCmd = &cobra.Command{
Use: "governance-solana-call",
Short: "Generate a 'general purpose solana governance call' template for specified chain and address",
Run: runGeneralPurposeGovernanceSolanaCallTemplate,
}

func runGuardianSetTemplate(cmd *cobra.Command, args []string) {
// Use deterministic devnet addresses as examples in the template, such that this doubles as a test fixture.
guardians := make([]*nodev1.GuardianSetUpdate_Guardian, *setUpdateNumGuardians)
Expand Down Expand Up @@ -1004,6 +1013,49 @@ func runGeneralPurposeGovernanceEvmCallTemplate(cmd *cobra.Command, args []strin
fmt.Print(string(b))
}

func runGeneralPurposeGovernanceSolanaCallTemplate(cmd *cobra.Command, args []string) {
if *governanceCallData == "" {
log.Fatal("--call-data must be specified")
}
if *governanceContractAddress == "" {
log.Fatal("--governance-contract must be specified")
}
_, err := base58.Decode(*governanceContractAddress)
if err != nil {
log.Fatal("invalid base58 governance contract address")
}
if *governanceTargetChain == "" {
log.Fatal("--chain-id must be specified")
}
chainID, err := parseChainID(*governanceTargetChain)
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_SolanaCall{
SolanaCall: &nodev1.SolanaCall{
ChainId: uint32(chainID),
GovernanceContract: *governanceContractAddress,
EncodedInstruction: *governanceCallData,
},
},
},
},
}

b, err := prototext.MarshalOptions{Multiline: true}.Marshal(m)
if err != nil {
panic(err)
}
fmt.Print(string(b))
}

// parseAddress parses either a hex-encoded address and returns
// a left-padded 32 byte hex string.
func parseAddress(s string) (string, error) {
Expand Down
26 changes: 26 additions & 0 deletions node/pkg/adminrpc/adminserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,30 @@ func evmCallToVaa(evmCall *nodev1.EvmCall, timestamp time.Time, guardianSetIndex
return v, nil
}

func solanaCallToVaa(solanaCall *nodev1.SolanaCall, timestamp time.Time, guardianSetIndex, nonce uint32, sequence uint64) (*vaa.VAA, error) {
address, err := base58.Decode(solanaCall.GovernanceContract)
if err != nil {
return nil, fmt.Errorf("failed to decode base58 governance contract address: %w", err)
}

var governanceContract [32]byte
copy(governanceContract[:], address)

instruction, err := hex.DecodeString(solanaCall.EncodedInstruction)
if err != nil {
return nil, fmt.Errorf("failed to decode instruction: %w", err)
}

v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyGeneralPurposeGovernanceSolana{
ChainID: vaa.ChainID(solanaCall.ChainId),
GovernanceContract: governanceContract,
Instruction: instruction,
}.Serialize())

return v, nil
}

func GovMsgToVaa(message *nodev1.GovernanceMessage, currentSetIndex uint32, timestamp time.Time) (*vaa.VAA, error) {
var (
v *vaa.VAA
Expand Down Expand Up @@ -644,6 +668,8 @@ func GovMsgToVaa(message *nodev1.GovernanceMessage, currentSetIndex uint32, time
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)
case *nodev1.GovernanceMessage_SolanaCall:
v, err = solanaCallToVaa(payload.SolanaCall, timestamp, currentSetIndex, message.Nonce, message.Sequence)
default:
panic(fmt.Sprintf("unsupported VAA type: %T", payload))
}
Expand Down
Loading

0 comments on commit 3c3de23

Please sign in to comment.