node: add token bridge governance VAA support
Change-Id: I731161f03590ce73145a1686eb2e62cfe19c8223
This commit is contained in:
parent
7998d04554
commit
2022b55fd4
|
@ -2,25 +2,24 @@ package guardiand
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/certusone/wormhole/node/pkg/db"
|
"github.com/certusone/wormhole/node/pkg/db"
|
||||||
publicrpcv1 "github.com/certusone/wormhole/node/pkg/proto/publicrpc/v1"
|
publicrpcv1 "github.com/certusone/wormhole/node/pkg/proto/publicrpc/v1"
|
||||||
"github.com/certusone/wormhole/node/pkg/publicrpc"
|
"github.com/certusone/wormhole/node/pkg/publicrpc"
|
||||||
|
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||||
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
||||||
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
|
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
|
||||||
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||||
"math"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
ethcommon "github.com/ethereum/go-ethereum/common"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
"math"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/certusone/wormhole/node/pkg/common"
|
"github.com/certusone/wormhole/node/pkg/common"
|
||||||
nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1"
|
nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1"
|
||||||
|
@ -36,7 +35,7 @@ type nodePrivilegedService struct {
|
||||||
|
|
||||||
// adminGuardianSetUpdateToVAA converts a nodev1.GuardianSetUpdate message to its canonical VAA representation.
|
// adminGuardianSetUpdateToVAA converts a nodev1.GuardianSetUpdate message to its canonical VAA representation.
|
||||||
// Returns an error if the data is invalid.
|
// Returns an error if the data is invalid.
|
||||||
func adminGuardianSetUpdateToVAA(req *nodev1.GuardianSetUpdate, guardianSetIndex uint32, timestamp uint32) (*vaa.VAA, error) {
|
func adminGuardianSetUpdateToVAA(req *nodev1.GuardianSetUpdate, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) {
|
||||||
if len(req.Guardians) == 0 {
|
if len(req.Guardians) == 0 {
|
||||||
return nil, errors.New("empty guardian set specified")
|
return nil, errors.New("empty guardian set specified")
|
||||||
}
|
}
|
||||||
|
@ -61,22 +60,18 @@ func adminGuardianSetUpdateToVAA(req *nodev1.GuardianSetUpdate, guardianSetIndex
|
||||||
addrs[i] = ethAddr
|
addrs[i] = ethAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
v := &vaa.VAA{
|
v := vaa.CreateGovernanceVAA(nonce, sequence, guardianSetIndex,
|
||||||
Version: vaa.SupportedVAAVersion,
|
vaa.BodyGuardianSetUpdate{
|
||||||
GuardianSetIndex: guardianSetIndex,
|
|
||||||
Timestamp: time.Unix(int64(timestamp), 0),
|
|
||||||
Payload: vaa.BodyGuardianSetUpdate{
|
|
||||||
Keys: addrs,
|
Keys: addrs,
|
||||||
NewIndex: guardianSetIndex + 1,
|
NewIndex: guardianSetIndex + 1,
|
||||||
}.Serialize(),
|
}.Serialize())
|
||||||
}
|
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// adminContractUpgradeToVAA converts a nodev1.ContractUpgrade message to its canonical VAA representation.
|
// adminContractUpgradeToVAA converts a nodev1.ContractUpgrade message to its canonical VAA representation.
|
||||||
// Returns an error if the data is invalid.
|
// Returns an error if the data is invalid.
|
||||||
func adminContractUpgradeToVAA(req *nodev1.ContractUpgrade, guardianSetIndex uint32, timestamp uint32) (*vaa.VAA, error) {
|
func adminContractUpgradeToVAA(req *nodev1.ContractUpgrade, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) {
|
||||||
if len(req.NewContract) != 32 {
|
if len(req.NewContract) != 32 {
|
||||||
return nil, errors.New("invalid new_contract address")
|
return nil, errors.New("invalid new_contract address")
|
||||||
}
|
}
|
||||||
|
@ -88,16 +83,40 @@ func adminContractUpgradeToVAA(req *nodev1.ContractUpgrade, guardianSetIndex uin
|
||||||
newContractAddress := vaa.Address{}
|
newContractAddress := vaa.Address{}
|
||||||
copy(newContractAddress[:], req.NewContract)
|
copy(newContractAddress[:], req.NewContract)
|
||||||
|
|
||||||
v := &vaa.VAA{
|
v := vaa.CreateGovernanceVAA(nonce, sequence, guardianSetIndex,
|
||||||
Version: vaa.SupportedVAAVersion,
|
vaa.BodyContractUpgrade{
|
||||||
GuardianSetIndex: guardianSetIndex,
|
|
||||||
Timestamp: time.Unix(int64(timestamp), 0),
|
|
||||||
Payload: vaa.BodyContractUpgrade{
|
|
||||||
ChainID: vaa.ChainID(req.ChainId),
|
ChainID: vaa.ChainID(req.ChainId),
|
||||||
NewContract: newContractAddress,
|
NewContract: newContractAddress,
|
||||||
}.Serialize(),
|
}.Serialize())
|
||||||
|
|
||||||
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tokenBridgeRegisterChain converts a nodev1.TokenBridgeRegisterChain message to its canonical VAA representation.
|
||||||
|
// Returns an error if the data is invalid.
|
||||||
|
func tokenBridgeRegisterChain(req *nodev1.TokenBridgeRegisterChain, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) {
|
||||||
|
if req.ChainId > math.MaxUint8 {
|
||||||
|
return nil, errors.New("invalid chain_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := hex.DecodeString(req.EmitterAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid emitter address encoding (expected hex)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(b) != 32 {
|
||||||
|
return nil, errors.New("invalid emitter address (expected 32 bytes)")
|
||||||
|
}
|
||||||
|
|
||||||
|
emitterAddress := vaa.Address{}
|
||||||
|
copy(emitterAddress[:], req.EmitterAddress)
|
||||||
|
|
||||||
|
v := vaa.CreateGovernanceVAA(nonce, sequence, guardianSetIndex,
|
||||||
|
vaa.BodyTokenBridgeRegisterChain{
|
||||||
|
ChainID: vaa.ChainID(req.ChainId),
|
||||||
|
EmitterAddress: emitterAddress,
|
||||||
|
}.Serialize())
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,9 +129,11 @@ func (s *nodePrivilegedService) InjectGovernanceVAA(ctx context.Context, req *no
|
||||||
)
|
)
|
||||||
switch payload := req.Payload.(type) {
|
switch payload := req.Payload.(type) {
|
||||||
case *nodev1.InjectGovernanceVAARequest_GuardianSet:
|
case *nodev1.InjectGovernanceVAARequest_GuardianSet:
|
||||||
v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, req.CurrentSetIndex, req.Timestamp)
|
v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, req.CurrentSetIndex, req.Nonce, req.Sequence)
|
||||||
case *nodev1.InjectGovernanceVAARequest_ContractUpgrade:
|
case *nodev1.InjectGovernanceVAARequest_ContractUpgrade:
|
||||||
v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, req.CurrentSetIndex, req.Timestamp)
|
v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, req.CurrentSetIndex, req.Nonce, req.Sequence)
|
||||||
|
case *nodev1.InjectGovernanceVAARequest_TokenBridgeRegisterChain:
|
||||||
|
v, err = tokenBridgeRegisterChain(payload.TokenBridgeRegisterChain, req.CurrentSetIndex, req.Nonce, req.Sequence)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unsupported VAA type: %T", payload))
|
panic(fmt.Sprintf("unsupported VAA type: %T", payload))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package guardiand
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/tendermint/tendermint/libs/rand"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ func init() {
|
||||||
|
|
||||||
TemplateCmd.AddCommand(AdminClientGuardianSetTemplateCmd)
|
TemplateCmd.AddCommand(AdminClientGuardianSetTemplateCmd)
|
||||||
TemplateCmd.AddCommand(AdminClientContractUpgradeTemplateCmd)
|
TemplateCmd.AddCommand(AdminClientContractUpgradeTemplateCmd)
|
||||||
|
TemplateCmd.AddCommand(AdminClientTokenBridgeRegisterChainCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
var TemplateCmd = &cobra.Command{
|
var TemplateCmd = &cobra.Command{
|
||||||
|
@ -43,6 +45,13 @@ var AdminClientContractUpgradeTemplateCmd = &cobra.Command{
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var AdminClientTokenBridgeRegisterChainCmd = &cobra.Command{
|
||||||
|
Use: "token-bridge-register-chain [FILENAME]",
|
||||||
|
Short: "Generate an empty token bridge chain registration template at specified path (offline)",
|
||||||
|
Run: runTokenBridgeRegisterChainTemplate,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
}
|
||||||
|
|
||||||
func runGuardianSetTemplate(cmd *cobra.Command, args []string) {
|
func runGuardianSetTemplate(cmd *cobra.Command, args []string) {
|
||||||
path := args[0]
|
path := args[0]
|
||||||
|
|
||||||
|
@ -58,9 +67,8 @@ func runGuardianSetTemplate(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
m := &nodev1.InjectGovernanceVAARequest{
|
m := &nodev1.InjectGovernanceVAARequest{
|
||||||
CurrentSetIndex: uint32(*templateGuardianIndex),
|
CurrentSetIndex: uint32(*templateGuardianIndex),
|
||||||
// Timestamp is hardcoded to make it reproducible on different devnet nodes.
|
Sequence: 1234,
|
||||||
// In production, a real UNIX timestamp should be used (see node.proto).
|
Nonce: rand.Uint32(),
|
||||||
Timestamp: 1605744545,
|
|
||||||
Payload: &nodev1.InjectGovernanceVAARequest_GuardianSet{
|
Payload: &nodev1.InjectGovernanceVAARequest_GuardianSet{
|
||||||
GuardianSet: &nodev1.GuardianSetUpdate{Guardians: guardians},
|
GuardianSet: &nodev1.GuardianSetUpdate{Guardians: guardians},
|
||||||
},
|
},
|
||||||
|
@ -82,9 +90,8 @@ func runContractUpgradeTemplate(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
m := &nodev1.InjectGovernanceVAARequest{
|
m := &nodev1.InjectGovernanceVAARequest{
|
||||||
CurrentSetIndex: uint32(*templateGuardianIndex),
|
CurrentSetIndex: uint32(*templateGuardianIndex),
|
||||||
// Timestamp is hardcoded to make it reproducible on different devnet nodes.
|
Sequence: 1234,
|
||||||
// In production, a real UNIX timestamp should be used (see node.proto).
|
Nonce: rand.Uint32(),
|
||||||
Timestamp: 1605744545,
|
|
||||||
Payload: &nodev1.InjectGovernanceVAARequest_ContractUpgrade{
|
Payload: &nodev1.InjectGovernanceVAARequest_ContractUpgrade{
|
||||||
ContractUpgrade: &nodev1.ContractUpgrade{
|
ContractUpgrade: &nodev1.ContractUpgrade{
|
||||||
ChainId: 1,
|
ChainId: 1,
|
||||||
|
@ -103,3 +110,28 @@ func runContractUpgradeTemplate(cmd *cobra.Command, args []string) {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func runTokenBridgeRegisterChainTemplate(cmd *cobra.Command, args []string) {
|
||||||
|
path := args[0]
|
||||||
|
|
||||||
|
m := &nodev1.InjectGovernanceVAARequest{
|
||||||
|
CurrentSetIndex: uint32(*templateGuardianIndex),
|
||||||
|
Sequence: rand.Uint64(),
|
||||||
|
Nonce: rand.Uint32(),
|
||||||
|
Payload: &nodev1.InjectGovernanceVAARequest_TokenBridgeRegisterChain{
|
||||||
|
TokenBridgeRegisterChain: &nodev1.TokenBridgeRegisterChain{
|
||||||
|
ChainId: 5,
|
||||||
|
EmitterAddress: "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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package guardiand
|
package guardiand
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/certusone/wormhole/node/pkg/vaa"
|
"github.com/certusone/wormhole/node/pkg/vaa"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
@ -38,9 +39,13 @@ func runGovernanceVAAVerify(cmd *cobra.Command, args []string) {
|
||||||
)
|
)
|
||||||
switch payload := msg.Payload.(type) {
|
switch payload := msg.Payload.(type) {
|
||||||
case *nodev1.InjectGovernanceVAARequest_GuardianSet:
|
case *nodev1.InjectGovernanceVAARequest_GuardianSet:
|
||||||
v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, msg.CurrentSetIndex, msg.Timestamp)
|
v, err = adminGuardianSetUpdateToVAA(payload.GuardianSet, msg.CurrentSetIndex, msg.Nonce, msg.Sequence)
|
||||||
case *nodev1.InjectGovernanceVAARequest_ContractUpgrade:
|
case *nodev1.InjectGovernanceVAARequest_ContractUpgrade:
|
||||||
v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, msg.CurrentSetIndex, msg.Timestamp)
|
v, err = adminContractUpgradeToVAA(payload.ContractUpgrade, msg.CurrentSetIndex, msg.Nonce, msg.Sequence)
|
||||||
|
case *nodev1.InjectGovernanceVAARequest_TokenBridgeRegisterChain:
|
||||||
|
v, err = tokenBridgeRegisterChain(payload.TokenBridgeRegisterChain, msg.CurrentSetIndex, msg.Nonce, msg.Sequence)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unsupported VAA type: %T", payload))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("invalid update: %v", err)
|
log.Fatalf("invalid update: %v", err)
|
||||||
|
|
|
@ -9,7 +9,7 @@ var governanceChain = ChainIDSolana
|
||||||
|
|
||||||
func CreateGovernanceVAA(nonce uint32, sequence uint64, guardianSetIndex uint32, payload []byte) *VAA {
|
func CreateGovernanceVAA(nonce uint32, sequence uint64, guardianSetIndex uint32, payload []byte) *VAA {
|
||||||
vaa := &VAA{
|
vaa := &VAA{
|
||||||
Version: 1,
|
Version: SupportedVAAVersion,
|
||||||
GuardianSetIndex: guardianSetIndex,
|
GuardianSetIndex: guardianSetIndex,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
Timestamp: time.Unix(0, 0),
|
Timestamp: time.Unix(0, 0),
|
||||||
|
|
|
@ -9,6 +9,9 @@ import (
|
||||||
// CoreModule is the identifier of the Core module (which is used for governance messages)
|
// CoreModule is the identifier of the Core module (which is used for governance messages)
|
||||||
var CoreModule = []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x43, 0x6f, 0x72, 0x65}
|
var CoreModule = []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x43, 0x6f, 0x72, 0x65}
|
||||||
|
|
||||||
|
// TokenBridgeModule is the identifier of the token bridge module ("TokenBridge")
|
||||||
|
var TokenBridgeModule = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// BodyContractUpgrade is a governance message to perform a contract upgrade of the core module
|
// BodyContractUpgrade is a governance message to perform a contract upgrade of the core module
|
||||||
BodyContractUpgrade struct {
|
BodyContractUpgrade struct {
|
||||||
|
@ -22,9 +25,8 @@ type (
|
||||||
NewIndex uint32
|
NewIndex uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// BodyRegisterChain is a governance message to register a chain on the token bridge
|
// BodyTokenBridgeRegisterChain is a governance message to register a chain on the token bridge
|
||||||
BodyRegisterChain struct {
|
BodyTokenBridgeRegisterChain struct {
|
||||||
Header [32]byte
|
|
||||||
ChainID ChainID
|
ChainID ChainID
|
||||||
EmitterAddress Address
|
EmitterAddress Address
|
||||||
}
|
}
|
||||||
|
@ -64,11 +66,11 @@ func (b BodyGuardianSetUpdate) Serialize() []byte {
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r BodyRegisterChain) Serialize() []byte {
|
func (r BodyTokenBridgeRegisterChain) Serialize() []byte {
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
// Write token bridge header
|
// Write token bridge header
|
||||||
buf.Write(r.Header[:])
|
buf.Write(TokenBridgeModule)
|
||||||
// Write action ID
|
// Write action ID
|
||||||
MustWrite(buf, binary.BigEndian, uint8(1))
|
MustWrite(buf, binary.BigEndian, uint8(1))
|
||||||
// Write target chain (0 = universal)
|
// Write target chain (0 = universal)
|
||||||
|
|
|
@ -92,8 +92,7 @@ func TestBodyRegisterChain_Serialize(t *testing.T) {
|
||||||
|
|
||||||
var headerB [32]byte
|
var headerB [32]byte
|
||||||
copy(headerB[:], header)
|
copy(headerB[:], header)
|
||||||
msg := &BodyRegisterChain{
|
msg := &BodyTokenBridgeRegisterChain{
|
||||||
Header: headerB,
|
|
||||||
ChainID: 8,
|
ChainID: 8,
|
||||||
EmitterAddress: Address{1, 2, 3, 4},
|
EmitterAddress: Address{1, 2, 3, 4},
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,23 +20,20 @@ message InjectGovernanceVAARequest {
|
||||||
// Index of the current guardian set.
|
// Index of the current guardian set.
|
||||||
uint32 current_set_index = 1;
|
uint32 current_set_index = 1;
|
||||||
|
|
||||||
// UNIX timestamp (s) of the VAA to be created. The timestamp is informational and will be part
|
// Sequence number. This is critical for replay protection - make sure the sequence number
|
||||||
// of the VAA submitted to the chain. It's part of the VAA digest and has to be identical across nodes and
|
// is unique for every new manually injected governance VAA. Sequences are tracked
|
||||||
// is critical for replay protection - a given event may only ever be observed with the same timestamp,
|
// by emitter, and manually injected VAAs all use a single hardcoded emitter.
|
||||||
// otherwise, it may be possible to execute it multiple times.
|
|
||||||
//
|
//
|
||||||
// For messages, the timestamp identifies the block that the message belongs to.
|
// We use random sequence numbers for the manual emitter.
|
||||||
|
uint64 sequence = 2;
|
||||||
|
|
||||||
// For governance VAAs, guardians inject the VAA manually. Best practice is to pick a timestamp which roughly matches
|
// Random nonce for disambiguation. Must be identical across all nodes.
|
||||||
// the timing of the off-chain ceremony used to achieve consensus. For guardian set updates, the actual on-chain
|
uint32 nonce = 3;
|
||||||
// guardian set creation timestamp will be set when the VAA is accepted on each chain.
|
|
||||||
//
|
|
||||||
// This is a uint32 to match the on-chain timestamp representation. This becomes a problem in 2106 (sorry).
|
|
||||||
uint32 timestamp = 2;
|
|
||||||
|
|
||||||
oneof payload{
|
oneof payload{
|
||||||
GuardianSetUpdate guardian_set = 3;
|
GuardianSetUpdate guardian_set = 10;
|
||||||
ContractUpgrade contract_upgrade = 4;
|
ContractUpgrade contract_upgrade = 11;
|
||||||
|
TokenBridgeRegisterChain token_bridge_register_chain = 12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +65,14 @@ message GuardianKey {
|
||||||
bool unsafe_deterministic_key = 2;
|
bool unsafe_deterministic_key = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message TokenBridgeRegisterChain {
|
||||||
|
// ID of the chain to be registered.
|
||||||
|
uint32 chain_id = 1;
|
||||||
|
|
||||||
|
// Hex-encoded emitter address to be registered (without leading 0x).
|
||||||
|
string emitter_address = 2;
|
||||||
|
}
|
||||||
|
|
||||||
// ContractUpgrade represents a Wormhole contract update to be submitted to and signed by the node.
|
// ContractUpgrade represents a Wormhole contract update to be submitted to and signed by the node.
|
||||||
message ContractUpgrade {
|
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 (uint8).
|
||||||
|
|
Loading…
Reference in New Issue