diff --git a/node/cmd/guardiand/adminclient.go b/node/cmd/guardiand/adminclient.go index 2af1292d..cd08966c 100644 --- a/node/cmd/guardiand/adminclient.go +++ b/node/cmd/guardiand/adminclient.go @@ -109,7 +109,9 @@ func runInjectGovernanceVAA(cmd *cobra.Command, args []string) { log.Fatalf("failed to submit governance VAA: %v", err) } - log.Printf("VAA successfully injected with digest %s", hexutils.BytesToHex(resp.Digest)) + for _, digest := range resp.Digests { + log.Printf("VAA successfully injected with digest %s", hexutils.BytesToHex(digest)) + } } func runFindMissingMessages(cmd *cobra.Command, args []string) { diff --git a/node/cmd/guardiand/adminserver.go b/node/cmd/guardiand/adminserver.go index 04e7bf6f..4e0a12a8 100644 --- a/node/cmd/guardiand/adminserver.go +++ b/node/cmd/guardiand/adminserver.go @@ -163,36 +163,43 @@ func (s *nodePrivilegedService) InjectGovernanceVAA(ctx context.Context, req *no v *vaa.VAA err error ) - switch payload := req.Payload.(type) { - case *nodev1.InjectGovernanceVAARequest_GuardianSet: - v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, req.CurrentSetIndex, req.Nonce, req.Sequence) - case *nodev1.InjectGovernanceVAARequest_ContractUpgrade: - v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, req.CurrentSetIndex, req.Nonce, req.Sequence) - case *nodev1.InjectGovernanceVAARequest_BridgeRegisterChain: - v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, req.CurrentSetIndex, req.Nonce, req.Sequence) - case *nodev1.InjectGovernanceVAARequest_BridgeContractUpgrade: - v, err = tokenBridgeUpgradeContract(payload.BridgeContractUpgrade, req.CurrentSetIndex, req.Nonce, req.Sequence) - default: - panic(fmt.Sprintf("unsupported VAA type: %T", payload)) - } - if err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) + + digests := make([][]byte, len(req.Messages)) + + for i, message := range req.Messages { + switch payload := message.Payload.(type) { + case *nodev1.GovernanceMessage_GuardianSet: + v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, req.CurrentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_ContractUpgrade: + v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, req.CurrentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_BridgeRegisterChain: + v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, req.CurrentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_BridgeContractUpgrade: + v, err = tokenBridgeUpgradeContract(payload.BridgeContractUpgrade, req.CurrentSetIndex, message.Nonce, message.Sequence) + default: + panic(fmt.Sprintf("unsupported VAA type: %T", payload)) + } + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + // Generate digest of the unsigned VAA. + digest, err := v.SigningMsg() + if err != nil { + panic(err) + } + + s.logger.Info("governance VAA constructed", + zap.Any("vaa", v), + zap.String("digest", digest.String()), + ) + + s.injectC <- v + + digests[i] = digest.Bytes() } - // Generate digest of the unsigned VAA. - digest, err := v.SigningMsg() - if err != nil { - panic(err) - } - - s.logger.Info("governance VAA constructed", - zap.Any("vaa", v), - zap.String("digest", digest.String()), - ) - - s.injectC <- v - - return &nodev1.InjectGovernanceVAAResponse{Digest: digest.Bytes()}, nil + return &nodev1.InjectGovernanceVAAResponse{Digests: digests}, nil } func (s *nodePrivilegedService) FindMissingMessages(ctx context.Context, req *nodev1.FindMissingMessagesRequest) (*nodev1.FindMissingMessagesResponse, error) { diff --git a/node/cmd/guardiand/admintemplate.go b/node/cmd/guardiand/admintemplate.go index 3344265f..0e7ae20b 100644 --- a/node/cmd/guardiand/admintemplate.go +++ b/node/cmd/guardiand/admintemplate.go @@ -93,10 +93,14 @@ func runGuardianSetTemplate(cmd *cobra.Command, args []string) { m := &nodev1.InjectGovernanceVAARequest{ CurrentSetIndex: uint32(*templateGuardianIndex), - Sequence: rand.Uint64(), - Nonce: rand.Uint32(), - Payload: &nodev1.InjectGovernanceVAARequest_GuardianSet{ - GuardianSet: &nodev1.GuardianSetUpdate{Guardians: guardians}, + Messages: []*nodev1.GovernanceMessage{ + { + Sequence: rand.Uint64(), + Nonce: rand.Uint32(), + Payload: &nodev1.GovernanceMessage_GuardianSet{ + GuardianSet: &nodev1.GuardianSetUpdate{Guardians: guardians}, + }, + }, }, } @@ -119,12 +123,16 @@ func runContractUpgradeTemplate(cmd *cobra.Command, args []string) { m := &nodev1.InjectGovernanceVAARequest{ CurrentSetIndex: uint32(*templateGuardianIndex), - Sequence: rand.Uint64(), - Nonce: rand.Uint32(), - Payload: &nodev1.InjectGovernanceVAARequest_ContractUpgrade{ - ContractUpgrade: &nodev1.ContractUpgrade{ - ChainId: uint32(chainID), - NewContract: address, + Messages: []*nodev1.GovernanceMessage{ + { + Sequence: rand.Uint64(), + Nonce: rand.Uint32(), + Payload: &nodev1.GovernanceMessage_ContractUpgrade{ + ContractUpgrade: &nodev1.ContractUpgrade{ + ChainId: uint32(chainID), + NewContract: address, + }, + }, }, }, } @@ -147,13 +155,17 @@ func runTokenBridgeRegisterChainTemplate(cmd *cobra.Command, args []string) { m := &nodev1.InjectGovernanceVAARequest{ CurrentSetIndex: uint32(*templateGuardianIndex), - Sequence: rand.Uint64(), - Nonce: rand.Uint32(), - Payload: &nodev1.InjectGovernanceVAARequest_BridgeRegisterChain{ - BridgeRegisterChain: &nodev1.BridgeRegisterChain{ - Module: *module, - ChainId: uint32(chainID), - EmitterAddress: address, + Messages: []*nodev1.GovernanceMessage{ + { + Sequence: rand.Uint64(), + Nonce: rand.Uint32(), + Payload: &nodev1.GovernanceMessage_BridgeRegisterChain{ + BridgeRegisterChain: &nodev1.BridgeRegisterChain{ + Module: *module, + ChainId: uint32(chainID), + EmitterAddress: address, + }, + }, }, }, } @@ -177,13 +189,17 @@ func runTokenBridgeUpgradeContractTemplate(cmd *cobra.Command, args []string) { m := &nodev1.InjectGovernanceVAARequest{ CurrentSetIndex: uint32(*templateGuardianIndex), - Sequence: rand.Uint64(), - Nonce: rand.Uint32(), - Payload: &nodev1.InjectGovernanceVAARequest_BridgeContractUpgrade{ - BridgeContractUpgrade: &nodev1.BridgeUpgradeContract{ - Module: *module, - TargetChainId: uint32(chainID), - NewContract: address, + Messages: []*nodev1.GovernanceMessage{ + { + Sequence: rand.Uint64(), + Nonce: rand.Uint32(), + Payload: &nodev1.GovernanceMessage_BridgeContractUpgrade{ + BridgeContractUpgrade: &nodev1.BridgeUpgradeContract{ + Module: *module, + TargetChainId: uint32(chainID), + NewContract: address, + }, + }, }, }, } diff --git a/node/cmd/guardiand/adminverify.go b/node/cmd/guardiand/adminverify.go index 36812f08..ab5e43ff 100644 --- a/node/cmd/guardiand/adminverify.go +++ b/node/cmd/guardiand/adminverify.go @@ -34,27 +34,31 @@ func runGovernanceVAAVerify(cmd *cobra.Command, args []string) { log.Fatalf("failed to deserialize: %v", err) } - var ( - v *vaa.VAA - ) - switch payload := msg.Payload.(type) { - case *nodev1.InjectGovernanceVAARequest_GuardianSet: - v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, msg.CurrentSetIndex, msg.Nonce, msg.Sequence) - case *nodev1.InjectGovernanceVAARequest_ContractUpgrade: - v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, msg.CurrentSetIndex, msg.Nonce, msg.Sequence) - case *nodev1.InjectGovernanceVAARequest_BridgeRegisterChain: - v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, msg.CurrentSetIndex, msg.Nonce, msg.Sequence) - default: - panic(fmt.Sprintf("unsupported VAA type: %T", payload)) - } - if err != nil { - log.Fatalf("invalid update: %v", err) - } + for _, message := range msg.Messages { + var ( + v *vaa.VAA + ) + switch payload := message.Payload.(type) { + case *nodev1.GovernanceMessage_GuardianSet: + v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, msg.CurrentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_ContractUpgrade: + v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, msg.CurrentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_BridgeRegisterChain: + v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, msg.CurrentSetIndex, message.Nonce, message.Sequence) + case *nodev1.GovernanceMessage_BridgeContractUpgrade: + v, err = tokenBridgeUpgradeContract(payload.BridgeContractUpgrade, msg.CurrentSetIndex, message.Nonce, message.Sequence) + default: + panic(fmt.Sprintf("unsupported VAA type: %T", payload)) + } + if err != nil { + log.Fatalf("invalid update: %v", err) + } - digest, err := v.SigningMsg() - if err != nil { - panic(err) - } + digest, err := v.SigningMsg() + if err != nil { + panic(err) + } - log.Printf("VAA with digest %s: %+v", digest.Hex(), spew.Sdump(v)) + log.Printf("VAA with digest %s: %+v", digest.Hex(), spew.Sdump(v)) + } } diff --git a/proto/node/v1/node.proto b/proto/node/v1/node.proto index e071865b..3644386e 100644 --- a/proto/node/v1/node.proto +++ b/proto/node/v1/node.proto @@ -27,6 +27,11 @@ message InjectGovernanceVAARequest { // Index of the current guardian set. uint32 current_set_index = 1; + // List of governance VAA messages to inject. + repeated GovernanceMessage messages = 2; +} + +message GovernanceMessage { // Sequence number. This is critical for replay protection - make sure the sequence number // is unique for every new manually injected governance VAA. Sequences are tracked // by emitter, and manually injected VAAs all use a single hardcoded emitter. @@ -51,8 +56,8 @@ message InjectGovernanceVAARequest { } message InjectGovernanceVAAResponse { - // Canonical digest of the submitted VAA. - bytes digest = 1; + // Canonical digests of the submitted VAAs. + repeated bytes digests = 1; } // GuardianSet represents a new guardian set to be submitted to and signed by the node.