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
This commit is contained in:
Leo 2021-10-08 19:41:43 +02:00 committed by Leopold Schabel
parent e6aded4fdc
commit 6fd6cb9f02
4 changed files with 107 additions and 0 deletions

View File

@ -122,6 +122,35 @@ func tokenBridgeRegisterChain(req *nodev1.BridgeRegisterChain, guardianSetIndex
return v, nil 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) { 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())) 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) v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, req.CurrentSetIndex, req.Nonce, req.Sequence)
case *nodev1.InjectGovernanceVAARequest_BridgeRegisterChain: case *nodev1.InjectGovernanceVAARequest_BridgeRegisterChain:
v, err = tokenBridgeRegisterChain(payload.BridgeRegisterChain, req.CurrentSetIndex, req.Nonce, req.Sequence) 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: default:
panic(fmt.Sprintf("unsupported VAA type: %T", payload)) panic(fmt.Sprintf("unsupported VAA type: %T", payload))
} }

View File

@ -24,6 +24,7 @@ func init() {
TemplateCmd.AddCommand(AdminClientGuardianSetTemplateCmd) TemplateCmd.AddCommand(AdminClientGuardianSetTemplateCmd)
TemplateCmd.AddCommand(AdminClientContractUpgradeTemplateCmd) TemplateCmd.AddCommand(AdminClientContractUpgradeTemplateCmd)
TemplateCmd.AddCommand(AdminClientTokenBridgeRegisterChainCmd) TemplateCmd.AddCommand(AdminClientTokenBridgeRegisterChainCmd)
TemplateCmd.AddCommand(AdminClientTokenBridgeUpgradeContractCmd)
} }
var TemplateCmd = &cobra.Command{ var TemplateCmd = &cobra.Command{
@ -52,6 +53,13 @@ var AdminClientTokenBridgeRegisterChainCmd = &cobra.Command{
Args: cobra.ExactArgs(1), 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) { func runGuardianSetTemplate(cmd *cobra.Command, args []string) {
path := args[0] path := args[0]
@ -136,3 +144,30 @@ func runTokenBridgeRegisterChainTemplate(cmd *cobra.Command, args []string) {
log.Fatal(err) 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)
}
}

View File

@ -28,6 +28,13 @@ type (
ChainID ChainID ChainID ChainID
EmitterAddress Address 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 { func (b BodyContractUpgrade) Serialize() []byte {
@ -87,3 +94,25 @@ func (r BodyTokenBridgeRegisterChain) Serialize() []byte {
return buf.Bytes() 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()
}

View File

@ -46,6 +46,7 @@ message InjectGovernanceVAARequest {
// Token bridge and NFT module // Token bridge and NFT module
BridgeRegisterChain bridge_register_chain = 12; BridgeRegisterChain bridge_register_chain = 12;
BridgeUpgradeContract bridge_contract_upgrade = 13;
} }
} }
@ -97,6 +98,17 @@ message ContractUpgrade {
bytes new_contract = 2; 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 { message FindMissingMessagesRequest {
// Emitter chain ID to iterate. // Emitter chain ID to iterate.
uint32 emitter_chain = 1; uint32 emitter_chain = 1;