소스 검색

node: add BridgeUpgradeContract governance VAA

Example VAA produced by the template:

	(*vaa.VAA)(0xc0004f4510)({
	 Version: (uint8) 1,
	 GuardianSetIndex: (uint32) 0,
	 Signatures: ([]*vaa.Signature) (len=1 cap=1) {
	  (*vaa.Signature)(0xc0003b0370)({
	   Index: (uint8) 0,
	   Signature: (vaa.SignatureData) (len=65 cap=65) 0f97ec9093c21ccc4ce544898ed5c21b66ab4c90be894642fbb43474ed9fb48a26d6e12f3397b9fdab160fee64e797d26599a2a9d81a4bf4bc98970b5fa5122501
	  })
	 },
	 Timestamp: (time.Time) 1970-01-01 00:00:00 +0000 UTC,
	 Nonce: (uint32) 1375049878,
	 Sequence: (uint64) 3557202656914991802,
	 ConsistencyLevel: (uint8) 32,
	 EmitterChain: (vaa.ChainID) solana,
	 EmitterAddress: (vaa.Address) (len=32 cap=32) 0000000000000000000000000000000000000000000000000000000000000004,
	 Payload: ([]uint8) (len=67 cap=1000) {
	  00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
	  00000010  00 00 00 00 00 54 6f 6b  65 6e 42 72 69 64 67 65  |.....TokenBridge|
	  00000020  02 00 05 00 00 00 00 00  00 00 00 00 00 00 00 02  |................|
	  00000030  90 fb 16 72 08 af 45 5b  b1 37 78 01 63 b7 b7 a9  |...r..E[.7x.c...|
	  00000040  a1 0c 16                                          |...|
	 }
	})

Change-Id: Ibe95db01e1bc0a9c36e1be06920a389db886fdd1
Leo 4 년 전
부모
커밋
6fd6cb9f02
4개의 변경된 파일107개의 추가작업 그리고 0개의 파일을 삭제
  1. 31 0
      node/cmd/guardiand/adminserver.go
  2. 35 0
      node/cmd/guardiand/admintemplate.go
  3. 29 0
      node/pkg/vaa/payloads.go
  4. 12 0
      proto/node/v1/node.proto

+ 31 - 0
node/cmd/guardiand/adminserver.go

@@ -122,6 +122,35 @@ func tokenBridgeRegisterChain(req *nodev1.BridgeRegisterChain, guardianSetIndex
 	return v, nil
 }
 
+// tokenBridgeUpgradeContract converts a nodev1.TokenBridgeRegisterChain message to its canonical VAA representation.
+// Returns an error if the data is invalid.
+func tokenBridgeUpgradeContract(req *nodev1.BridgeUpgradeContract, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) {
+	if req.TargetChainId > math.MaxUint16 {
+		return nil, errors.New("invalid target_chain_id")
+	}
+
+	b, err := hex.DecodeString(req.NewContract)
+	if err != nil {
+		return nil, errors.New("invalid new contract address (expected hex)")
+	}
+
+	if len(b) != 32 {
+		return nil, errors.New("invalid new contract address (expected 32 bytes)")
+	}
+
+	newContract := vaa.Address{}
+	copy(newContract[:], b)
+
+	v := vaa.CreateGovernanceVAA(nonce, sequence, guardianSetIndex,
+		vaa.BodyTokenBridgeUpgradeContract{
+			Module:        req.Module,
+			TargetChainID: vaa.ChainID(req.TargetChainId),
+			NewContract:   newContract,
+		}.Serialize())
+
+	return v, nil
+}
+
 func (s *nodePrivilegedService) InjectGovernanceVAA(ctx context.Context, req *nodev1.InjectGovernanceVAARequest) (*nodev1.InjectGovernanceVAAResponse, error) {
 	s.logger.Info("governance VAA injected via admin socket", zap.String("request", req.String()))
 
@@ -136,6 +165,8 @@ func (s *nodePrivilegedService) InjectGovernanceVAA(ctx context.Context, req *no
 		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))
 	}

+ 35 - 0
node/cmd/guardiand/admintemplate.go

@@ -24,6 +24,7 @@ func init() {
 	TemplateCmd.AddCommand(AdminClientGuardianSetTemplateCmd)
 	TemplateCmd.AddCommand(AdminClientContractUpgradeTemplateCmd)
 	TemplateCmd.AddCommand(AdminClientTokenBridgeRegisterChainCmd)
+	TemplateCmd.AddCommand(AdminClientTokenBridgeUpgradeContractCmd)
 }
 
 var TemplateCmd = &cobra.Command{
@@ -52,6 +53,13 @@ var AdminClientTokenBridgeRegisterChainCmd = &cobra.Command{
 	Args:  cobra.ExactArgs(1),
 }
 
+var AdminClientTokenBridgeUpgradeContractCmd = &cobra.Command{
+	Use:   "token-bridge-upgrade-contract [FILENAME]",
+	Short: "Generate an empty token bridge contract upgrade template at specified path (offline)",
+	Run:   runTokenBridgeUpgradeContractTemplate,
+	Args:  cobra.ExactArgs(1),
+}
+
 func runGuardianSetTemplate(cmd *cobra.Command, args []string) {
 	path := args[0]
 
@@ -136,3 +144,30 @@ func runTokenBridgeRegisterChainTemplate(cmd *cobra.Command, args []string) {
 		log.Fatal(err)
 	}
 }
+
+func runTokenBridgeUpgradeContractTemplate(cmd *cobra.Command, args []string) {
+	path := args[0]
+
+	m := &nodev1.InjectGovernanceVAARequest{
+		CurrentSetIndex: uint32(*templateGuardianIndex),
+		Sequence:        rand.Uint64(),
+		Nonce:           rand.Uint32(),
+		Payload: &nodev1.InjectGovernanceVAARequest_BridgeContractUpgrade{
+			BridgeContractUpgrade: &nodev1.BridgeUpgradeContract{
+				Module:        "TokenBridge",
+				TargetChainId: 5,
+				NewContract:   "0000000000000000000000000290FB167208Af455bB137780163b7B7a9a10C16",
+			},
+		},
+	}
+
+	b, err := prototext.MarshalOptions{Multiline: true}.Marshal(m)
+	if err != nil {
+		panic(err)
+	}
+
+	err = ioutil.WriteFile(path, b, 0640)
+	if err != nil {
+		log.Fatal(err)
+	}
+}

+ 29 - 0
node/pkg/vaa/payloads.go

@@ -28,6 +28,13 @@ type (
 		ChainID        ChainID
 		EmitterAddress Address
 	}
+
+	// BodyTokenBridgeUpgradeContract is a governance message to upgrade the token bridge.
+	BodyTokenBridgeUpgradeContract struct {
+		Module        string
+		TargetChainID ChainID
+		NewContract   Address
+	}
 )
 
 func (b BodyContractUpgrade) Serialize() []byte {
@@ -87,3 +94,25 @@ func (r BodyTokenBridgeRegisterChain) Serialize() []byte {
 
 	return buf.Bytes()
 }
+
+func (r BodyTokenBridgeUpgradeContract) Serialize() []byte {
+	if len(r.Module) > 32 {
+		panic("module longer than 32 byte")
+	}
+
+	buf := &bytes.Buffer{}
+
+	// Write token bridge header
+	for i := 0; i < (32 - len(r.Module)); i++ {
+		buf.WriteByte(0x00)
+	}
+	buf.Write([]byte(r.Module))
+	// Write action ID
+	MustWrite(buf, binary.BigEndian, uint8(2))
+	// Write target chain
+	MustWrite(buf, binary.BigEndian, r.TargetChainID)
+	// Write emitter address of chain to be registered
+	buf.Write(r.NewContract[:])
+
+	return buf.Bytes()
+}

+ 12 - 0
proto/node/v1/node.proto

@@ -46,6 +46,7 @@ message InjectGovernanceVAARequest {
     // Token bridge and NFT module
 
     BridgeRegisterChain bridge_register_chain = 12;
+    BridgeUpgradeContract bridge_contract_upgrade = 13;
   }
 }
 
@@ -97,6 +98,17 @@ message ContractUpgrade {
   bytes new_contract = 2;
 }
 
+message BridgeUpgradeContract {
+  // Module identifier of the token or NFT bridge (typically "TokenBridge" or "NFTBridge").
+  string module = 1;
+
+  // ID of the chain where the bridge contract should be updated (uint16).
+  uint32 target_chain_id = 2;
+
+  // Address of the new program/contract.
+  string new_contract = 3;
+}
+
 message FindMissingMessagesRequest {
   // Emitter chain ID to iterate.
   uint32 emitter_chain = 1;