Node/Gateway: Relay attestations (#3350)
This commit is contained in:
parent
edba6449a7
commit
c1ff1e1d1c
4
Tiltfile
4
Tiltfile
|
@ -276,7 +276,7 @@ def build_node_yaml():
|
|||
"--accountantContract",
|
||||
"wormhole14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srrg465",
|
||||
"--accountantKeyPath",
|
||||
"/tmp/mounted-keys/wormchain/wormchainKey",
|
||||
"/tmp/mounted-keys/wormchain/accountantKey",
|
||||
"--accountantKeyPassPhrase",
|
||||
"test0000",
|
||||
"--accountantWS",
|
||||
|
@ -294,7 +294,7 @@ def build_node_yaml():
|
|||
"--gatewayRelayerContract",
|
||||
"wormhole17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgshdnj3k",
|
||||
"--gatewayRelayerKeyPath",
|
||||
"/tmp/mounted-keys/wormchain/wormchainKey",
|
||||
"/tmp/mounted-keys/wormchain/gwrelayerKey",
|
||||
"--gatewayRelayerKeyPassPhrase",
|
||||
"test0000",
|
||||
|
||||
|
|
|
@ -49,10 +49,14 @@ spec:
|
|||
secretName: node-wormchain-key
|
||||
optional: false
|
||||
items:
|
||||
- key: wormchainKey0
|
||||
path: wormchainKey0
|
||||
- key: wormchainKey1
|
||||
path: wormchainKey1
|
||||
- key: accountantKey0
|
||||
path: accountantKey0
|
||||
- key: accountantKey1
|
||||
path: accountantKey1
|
||||
- key: gwrelayerKey0
|
||||
path: gwrelayerKey0
|
||||
- key: gwrelayerKey1
|
||||
path: gwrelayerKey1
|
||||
containers:
|
||||
- name: guardiand
|
||||
image: guardiand-image
|
||||
|
@ -98,9 +102,9 @@ spec:
|
|||
- ws://eth-devnet:8545
|
||||
# - --wormchainURL
|
||||
# - wormchain:9090
|
||||
# - --wormchainKeyPath
|
||||
# - /tmp/mounted-keys/wormchain/wormchainKey
|
||||
# - --wormchainKeyPassPhrase
|
||||
# - --accountantKeyPath
|
||||
# - /tmp/mounted-keys/wormchain/accountantKey
|
||||
# - --accountantKeyPassPhrase
|
||||
# - test0000
|
||||
# - --accountantWS
|
||||
# - http://wormchain:26657
|
||||
|
@ -189,5 +193,7 @@ metadata:
|
|||
name: node-wormchain-key
|
||||
type: Opaque
|
||||
data:
|
||||
wormchainKey0: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0Ka2RmOiBiY3J5cHQKc2FsdDogNDc2ODc2NkE3OEZEN0ZBQjMwMUJGOTM5MUYwQ0Y2M0YKdHlwZTogc2VjcDI1NmsxCgpkbEZuN1ZqRk02RnJjYkdaVDRWeE5yRlE3SUhQS2RyVVBCRTYraW8yK0w0VFZqcis5emNIQTF3dzNubWtqNVFlCnVSekJWMjQyeUdTc3hNTTJZckI2Q1ZXdzlaWXJJY3JFeks1c0FuST0KPXB2aHkKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0t
|
||||
wormchainKey1: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0Ka2RmOiBiY3J5cHQKc2FsdDogNzc1M0NCQTBBMUQ0NTJCMkE2QzlERDM4ODc3MTg0NEEKdHlwZTogc2VjcDI1NmsxCgpSYnhRVWRnK2ZHcjMzZTAyVWFFQW1YTDFlNFkrTGJUMFdqbnl4RVR3OXBoL2JXOGI0MzdhWmErOWlCc3NBa0UyCnRScUwvb0J1NWFnQXJocHNnWUgxNlhOWjJHMXRwY0R3V0dQZ1VWVT0KPUd6YUwKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0t
|
||||
accountantKey0: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0Ka2RmOiBiY3J5cHQKc2FsdDogNDc2ODc2NkE3OEZEN0ZBQjMwMUJGOTM5MUYwQ0Y2M0YKdHlwZTogc2VjcDI1NmsxCgpkbEZuN1ZqRk02RnJjYkdaVDRWeE5yRlE3SUhQS2RyVVBCRTYraW8yK0w0VFZqcis5emNIQTF3dzNubWtqNVFlCnVSekJWMjQyeUdTc3hNTTJZckI2Q1ZXdzlaWXJJY3JFeks1c0FuST0KPXB2aHkKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0t
|
||||
accountantKey1: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0Ka2RmOiBiY3J5cHQKc2FsdDogNzc1M0NCQTBBMUQ0NTJCMkE2QzlERDM4ODc3MTg0NEEKdHlwZTogc2VjcDI1NmsxCgpSYnhRVWRnK2ZHcjMzZTAyVWFFQW1YTDFlNFkrTGJUMFdqbnl4RVR3OXBoL2JXOGI0MzdhWmErOWlCc3NBa0UyCnRScUwvb0J1NWFnQXJocHNnWUgxNlhOWjJHMXRwY0R3V0dQZ1VWVT0KPUd6YUwKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0t
|
||||
gwrelayerKey0: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0KdHlwZTogc2VjcDI1NmsxCmtkZjogYmNyeXB0CnNhbHQ6IDc4OUYzRTBCMkVGNDcyNjAyQzNFMUE0OUI2OENFQzlBCgpGWHAvSllPS3E4WmZtOWxHZ3ZFNEM3NXFyUXFNZFp2RHNWRjhObTdMQU1oR2dHbXBnZnpoZjUrZ3IwZ1hjYjVWCmtSTXA2c0p0NkxCVzRPYWF2ckk3ay84Vml2NWhMVU1la1dPMHg5bz0KPUxrb1MKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0t
|
||||
gwrelayerKey1: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0Ka2RmOiBiY3J5cHQKc2FsdDogNDc5RDk3RDE2OTE0QkQ4QjlFNUUwQzkzMDA0RDA4RUEKdHlwZTogc2VjcDI1NmsxCgpvTEJ0aUkwT2pudXo5bHlzeVlZOFhQeEVkTnpwYUJOVWFkL0UySlJld2pFWFZNVVNTWll2QVZKbERiN3hEQjlSCmEvdm45SFNPM2hKOFc1QTBKOVFqUVZXRzVoZXBNZVpQUEI4M1FCUT0KPVJuTGEKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0t
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/certusone/wormhole/node/pkg/common"
|
||||
"github.com/certusone/wormhole/node/pkg/supervisor"
|
||||
"github.com/wormhole-foundation/wormhole/sdk"
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
|
||||
wasmdtypes "github.com/CosmWasm/wasmd/x/wasm/types"
|
||||
|
@ -36,24 +37,54 @@ type (
|
|||
)
|
||||
|
||||
// GatewayRelayer is the object that manages the interface to the wormchain accountant smart contract.
|
||||
type GatewayRelayer struct {
|
||||
ctx context.Context
|
||||
logger *zap.Logger
|
||||
contractAddress string
|
||||
wormchainConn GatewayRelayerWormchainConn
|
||||
env common.Environment
|
||||
subChan chan *vaa.VAA
|
||||
targetAddress vaa.Address
|
||||
}
|
||||
type (
|
||||
GatewayRelayer struct {
|
||||
ctx context.Context
|
||||
logger *zap.Logger
|
||||
ibcTranslatorAddress string
|
||||
wormchainConn GatewayRelayerWormchainConn
|
||||
env common.Environment
|
||||
subChan chan *VaaToPublish
|
||||
tokenBridges tokenBridgeMap
|
||||
tokenBridgeAddress string
|
||||
ibcTranslatorPayloadAddress vaa.Address
|
||||
}
|
||||
|
||||
tokenBridgeMap map[tokenBridgeKey]struct{}
|
||||
|
||||
tokenBridgeKey struct {
|
||||
emitterChainId vaa.ChainID
|
||||
emitterAddr vaa.Address
|
||||
}
|
||||
|
||||
VaaToPublish struct {
|
||||
V *vaa.VAA
|
||||
ContractAddress string
|
||||
VType VaaType
|
||||
}
|
||||
|
||||
VaaType uint8
|
||||
)
|
||||
|
||||
const (
|
||||
IbcTranslator VaaType = iota
|
||||
TokenBridge
|
||||
)
|
||||
|
||||
// subChanSize is the capacity of the submit channel used to publish VAAs.
|
||||
const subChanSize = 50
|
||||
|
||||
var (
|
||||
vaasSubmitted = promauto.NewCounter(
|
||||
vaasSubmittedToIbcTranslator = promauto.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "gwrelayer_vaas_submitted",
|
||||
Help: "Total number of VAAs submitted to the gateway relayer",
|
||||
Name: "gwrelayer_vaas_submitted_to_ibc_translator",
|
||||
Help: "Total number of VAAs submitted to the ibc translator contract by the gateway relayer",
|
||||
})
|
||||
|
||||
vaasSubmittedToTokenBridge = promauto.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "gwrelayer_vaas_submitted_to_token_bridge",
|
||||
Help: "Total number of VAAs submitted to the token bridge contract by the gateway relayer",
|
||||
})
|
||||
|
||||
channelFullErrors = promauto.NewCounter(
|
||||
|
@ -64,7 +95,7 @@ var (
|
|||
submitErrors = promauto.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "gwrelayer_submit_errors",
|
||||
Help: "Total number of errors encountered while submitting VAAs to the gateway relayer",
|
||||
Help: "Total number of errors encountered while submitting VAAs",
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -72,32 +103,46 @@ var (
|
|||
func NewGatewayRelayer(
|
||||
ctx context.Context,
|
||||
logger *zap.Logger,
|
||||
contractAddress string,
|
||||
ibcTranslatorAddress string,
|
||||
wormchainConn GatewayRelayerWormchainConn,
|
||||
env common.Environment,
|
||||
) *GatewayRelayer {
|
||||
if contractAddress == "" {
|
||||
if ibcTranslatorAddress == "" {
|
||||
return nil // This is not an error, it just means the feature is not enabled.
|
||||
}
|
||||
|
||||
return &GatewayRelayer{
|
||||
ctx: ctx,
|
||||
logger: logger.With(zap.String("component", "gwrelayer")),
|
||||
contractAddress: contractAddress,
|
||||
wormchainConn: wormchainConn,
|
||||
env: env,
|
||||
subChan: make(chan *vaa.VAA, subChanSize),
|
||||
ctx: ctx,
|
||||
logger: logger.With(zap.String("component", "gwrelayer")),
|
||||
ibcTranslatorAddress: ibcTranslatorAddress,
|
||||
wormchainConn: wormchainConn,
|
||||
env: env,
|
||||
subChan: make(chan *VaaToPublish, subChanSize),
|
||||
// tokenBridgeAddress and tokenBridges are initialized in Start().
|
||||
}
|
||||
}
|
||||
|
||||
// Start initializes the gateway relayer and starts the worker runnable that submits VAAs to the contract.
|
||||
func (gwr *GatewayRelayer) Start(ctx context.Context) error {
|
||||
var err error
|
||||
gwr.targetAddress, err = convertBech32AddressToWormhole(gwr.contractAddress)
|
||||
gwr.ibcTranslatorPayloadAddress, err = convertBech32AddressToWormhole(gwr.ibcTranslatorAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gwr.logger.Info("starting gateway relayer", zap.String("contract", gwr.contractAddress), zap.String("targetAddress", hex.EncodeToString(gwr.targetAddress.Bytes())))
|
||||
gwr.tokenBridges, gwr.tokenBridgeAddress, err = buildTokenBridgeMap(gwr.logger, gwr.env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build token bridge map: %w", err)
|
||||
}
|
||||
if gwr.tokenBridgeAddress == "" {
|
||||
return fmt.Errorf("failed to look up token bridge address for gateway")
|
||||
}
|
||||
|
||||
gwr.logger.Info("starting gateway relayer",
|
||||
zap.String("ibcTranslatorAddress", gwr.ibcTranslatorAddress),
|
||||
zap.String("ibcTranslatorPayloadAddress", hex.EncodeToString(gwr.ibcTranslatorPayloadAddress.Bytes())),
|
||||
zap.String("tokenBridgeAddress", gwr.tokenBridgeAddress),
|
||||
)
|
||||
|
||||
// Start the watcher to listen to transfer events from the smart contract.
|
||||
if gwr.env == common.GoTest {
|
||||
|
@ -114,6 +159,47 @@ func (gwr *GatewayRelayer) Start(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// buildTokenBridgeMap builds a set of all token bridge emitter chain / emitter addresses.
|
||||
func buildTokenBridgeMap(logger *zap.Logger, env common.Environment) (tokenBridgeMap, string, error) {
|
||||
emitterMap := sdk.KnownTokenbridgeEmitters
|
||||
if env == common.TestNet {
|
||||
emitterMap = sdk.KnownTestnetTokenbridgeEmitters
|
||||
} else if env == common.UnsafeDevNet || env == common.GoTest || env == common.AccountantMock {
|
||||
emitterMap = sdk.KnownDevnetTokenbridgeEmitters
|
||||
}
|
||||
|
||||
// Build the map of token bridges to be monitored.
|
||||
tokenBridges := make(tokenBridgeMap)
|
||||
tokenBridgeAddress := ""
|
||||
for chainId, emitterAddrBytes := range emitterMap {
|
||||
if chainId == vaa.ChainIDWormchain {
|
||||
var err error
|
||||
tokenBridgeAddress, err = sdktypes.Bech32ifyAddressBytes("wormhole", emitterAddrBytes)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf(`failed to convert gateway emitter address "%s" to bech32: %v`, hex.EncodeToString(emitterAddrBytes), err)
|
||||
}
|
||||
|
||||
// We don't want to forward stuff that originated on Gateway, so don't add it to the map.
|
||||
continue
|
||||
}
|
||||
emitterAddr, err := vaa.BytesToAddress(emitterAddrBytes)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to convert emitter address for chain: %v", chainId)
|
||||
}
|
||||
|
||||
tbk := tokenBridgeKey{emitterChainId: chainId, emitterAddr: emitterAddr}
|
||||
_, exists := tokenBridges[tbk]
|
||||
if exists {
|
||||
return nil, "", fmt.Errorf("detected duplicate token bridge for chain: %v", chainId)
|
||||
}
|
||||
|
||||
tokenBridges[tbk] = struct{}{}
|
||||
logger.Info("will monitor token bridge:", zap.Stringer("emitterChainId", tbk.emitterChainId), zap.Stringer("emitterAddr", tbk.emitterAddr))
|
||||
}
|
||||
|
||||
return tokenBridges, tokenBridgeAddress, nil
|
||||
}
|
||||
|
||||
// Close closes the connection to the smart contract.
|
||||
func (gwr *GatewayRelayer) Close() {
|
||||
if gwr.wormchainConn != nil {
|
||||
|
@ -133,24 +219,34 @@ func convertBech32AddressToWormhole(contractAddress string) (vaa.Address, error)
|
|||
|
||||
// SubmitVAA checks to see if the VAA should be submitted to the smart contract, and if so, writes it to the channel for publishing.
|
||||
func (gwr *GatewayRelayer) SubmitVAA(v *vaa.VAA) {
|
||||
if shouldPub, err := shouldPublish(v.Payload, vaa.ChainIDWormchain, gwr.targetAddress); err != nil {
|
||||
var v2p VaaToPublish
|
||||
if shouldPub, err := shouldPublishToIbcTranslator(v.Payload, vaa.ChainIDWormchain, gwr.ibcTranslatorPayloadAddress); err != nil {
|
||||
gwr.logger.Error("failed to check if vaa should be published", zap.String("msgId", v.MessageID()), zap.Error(err))
|
||||
return
|
||||
} else if !shouldPub {
|
||||
} else if shouldPub {
|
||||
v2p.VType = IbcTranslator
|
||||
v2p.ContractAddress = gwr.ibcTranslatorAddress
|
||||
} else if shouldPub = shouldPublishToTokenBridge(gwr.tokenBridges, v); shouldPub {
|
||||
v2p.VType = TokenBridge
|
||||
v2p.ContractAddress = gwr.tokenBridgeAddress
|
||||
} else {
|
||||
gwr.logger.Debug("not relaying vaa", zap.String("msgId", v.MessageID()))
|
||||
return
|
||||
}
|
||||
|
||||
v2p.V = v
|
||||
|
||||
select {
|
||||
case gwr.subChan <- v:
|
||||
gwr.logger.Debug("submitted vaa to channel", zap.String("msgId", v.MessageID()))
|
||||
case gwr.subChan <- &v2p:
|
||||
gwr.logger.Debug("submitted vaa to channel", zap.String("msgId", v.MessageID()), zap.String("contract", v2p.ContractAddress), zap.Uint8("vaaType", uint8(v2p.VType)))
|
||||
default:
|
||||
channelFullErrors.Inc()
|
||||
gwr.logger.Error("unable to submit vaa because the channel is full, dropping it", zap.String("msgId", v.MessageID()))
|
||||
gwr.logger.Error("unable to submit vaa because the channel is full, dropping it", zap.String("msgId", v.MessageID()), zap.String("contract", v2p.ContractAddress), zap.Uint8("vaaType", uint8(v2p.VType)))
|
||||
}
|
||||
}
|
||||
|
||||
// shouldPublish returns true if a message should be forwarded to the contract on wormchain, false if not.
|
||||
func shouldPublish(payload []byte, targetChain vaa.ChainID, targetAddress vaa.Address) (bool, error) {
|
||||
// shouldPublishToIbcTranslator returns true if a message should be forwarded to the contract on wormchain, false if not.
|
||||
func shouldPublishToIbcTranslator(payload []byte, targetChain vaa.ChainID, targetAddress vaa.Address) (bool, error) {
|
||||
if len(payload) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
@ -171,15 +267,33 @@ func shouldPublish(payload []byte, targetChain vaa.ChainID, targetAddress vaa.Ad
|
|||
return true, nil
|
||||
}
|
||||
|
||||
// shouldPublishToTokenBridge returns true if a message should be forwarded to the token bridge, false if not.
|
||||
func shouldPublishToTokenBridge(tokenBridges tokenBridgeMap, v *vaa.VAA) bool {
|
||||
if _, exists := tokenBridges[tokenBridgeKey{emitterChainId: v.EmitterChain, emitterAddr: v.EmitterAddress}]; !exists {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(v.Payload) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// We only forward attestations (type two).
|
||||
if v.Payload[0] != 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// worker listens for VAAs and submits them to the smart contract.
|
||||
func (gwr *GatewayRelayer) worker(ctx context.Context) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case v := <-gwr.subChan:
|
||||
if err := gwr.submitVAAToContract(v); err != nil {
|
||||
gwr.logger.Error("failed to submit vaa to contract", zap.String("msgId", v.MessageID()), zap.Error(err))
|
||||
case v2p := <-gwr.subChan:
|
||||
if err := gwr.submitVAAToContract(v2p); err != nil {
|
||||
gwr.logger.Error("failed to submit vaa to contract", zap.String("msgId", v2p.V.MessageID()), zap.String("contract", v2p.ContractAddress), zap.Uint8("vaaType", uint8(v2p.VType)), zap.Error(err))
|
||||
// TODO: For now we don't want to restart because this will happen if the VAA has already been submitted by another guardian.
|
||||
//return fmt.Errorf("failed to submit vaa to contract: %w", err)
|
||||
}
|
||||
|
@ -188,18 +302,23 @@ func (gwr *GatewayRelayer) worker(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// submitVAAToContract submits a VAA to the smart contract on wormchain.
|
||||
func (gwr *GatewayRelayer) submitVAAToContract(v *vaa.VAA) error {
|
||||
_, err := SubmitVAAToContract(gwr.ctx, gwr.logger, gwr.wormchainConn, gwr.contractAddress, v)
|
||||
func (gwr *GatewayRelayer) submitVAAToContract(v2p *VaaToPublish) error {
|
||||
_, err := SubmitVAAToContract(gwr.ctx, gwr.logger, gwr.wormchainConn, v2p)
|
||||
if err != nil {
|
||||
submitErrors.Inc()
|
||||
return err
|
||||
}
|
||||
// TODO: Need to check txResp for "VAA already submitted", which should not be an error.
|
||||
vaasSubmitted.Inc()
|
||||
|
||||
if v2p.VType == IbcTranslator {
|
||||
vaasSubmittedToIbcTranslator.Inc()
|
||||
} else {
|
||||
vaasSubmittedToTokenBridge.Inc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type (
|
||||
// completeTransferAndConvertMsg is used to submit a VAA to the IBC translator contract.
|
||||
completeTransferAndConvertMsg struct {
|
||||
Params completeTransferAndConvertParams `json:"complete_transfer_and_convert"`
|
||||
}
|
||||
|
@ -207,6 +326,15 @@ type (
|
|||
completeTransferAndConvertParams struct {
|
||||
VAA []byte `json:"vaa"`
|
||||
}
|
||||
|
||||
// submitVAA is used to submit a VAA to the token bridge contract.
|
||||
submitVAA struct {
|
||||
Params submitVAAParams `json:"submit_vaa"`
|
||||
}
|
||||
|
||||
submitVAAParams struct {
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
)
|
||||
|
||||
// SubmitVAAToContract submits a VAA to the smart contract on wormchain.
|
||||
|
@ -214,30 +342,41 @@ func SubmitVAAToContract(
|
|||
ctx context.Context,
|
||||
logger *zap.Logger,
|
||||
wormchainConn GatewayRelayerWormchainConn,
|
||||
contract string,
|
||||
v *vaa.VAA,
|
||||
v2p *VaaToPublish,
|
||||
) (*sdktx.BroadcastTxResponse, error) {
|
||||
logger.Info("submitting VAA to contract", zap.String("message_id", v.MessageID()))
|
||||
logger.Info("submitting VAA to contract", zap.String("message_id", v2p.V.MessageID()), zap.String("contract", v2p.ContractAddress), zap.Uint8("vaaType", uint8(v2p.VType)))
|
||||
|
||||
vaaBytes, err := v.Marshal()
|
||||
vaaBytes, err := v2p.V.Marshal()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal vaa: %w", err)
|
||||
}
|
||||
|
||||
msgData := completeTransferAndConvertMsg{
|
||||
Params: completeTransferAndConvertParams{
|
||||
VAA: vaaBytes,
|
||||
},
|
||||
}
|
||||
var msgBytes []byte
|
||||
|
||||
msgBytes, err := json.Marshal(msgData)
|
||||
if v2p.VType == IbcTranslator {
|
||||
msgData := completeTransferAndConvertMsg{
|
||||
Params: completeTransferAndConvertParams{
|
||||
VAA: vaaBytes,
|
||||
},
|
||||
}
|
||||
msgBytes, err = json.Marshal(msgData)
|
||||
} else if v2p.VType == TokenBridge {
|
||||
msgData := submitVAA{
|
||||
Params: submitVAAParams{
|
||||
Data: vaaBytes,
|
||||
},
|
||||
}
|
||||
msgBytes, err = json.Marshal(msgData)
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid vtype: %d", uint8(v2p.VType))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
|
||||
subMsg := wasmdtypes.MsgExecuteContract{
|
||||
Sender: wormchainConn.SenderAddress(),
|
||||
Contract: contract,
|
||||
Contract: v2p.ContractAddress,
|
||||
Msg: msgBytes,
|
||||
Funds: sdktypes.Coins{},
|
||||
}
|
||||
|
@ -268,7 +407,7 @@ func SubmitVAAToContract(
|
|||
return txResp, fmt.Errorf("submit failed: %s", txResp.TxResponse.RawLog)
|
||||
}
|
||||
|
||||
logger.Info("done sending broadcast", zap.String("msgId", v.MessageID()), zap.Int64("gasUsed", txResp.TxResponse.GasUsed), zap.Stringer("elapsedTime", time.Since(start)))
|
||||
logger.Info("done sending broadcast", zap.String("msgId", v2p.V.MessageID()), zap.String("contract", v2p.ContractAddress), zap.Uint8("vaaType", uint8(v2p.VType)), zap.Int64("gasUsed", txResp.TxResponse.GasUsed), zap.Stringer("elapsedTime", time.Since(start)))
|
||||
logger.Debug("in SubmitVAAToContract, done sending broadcast", zap.String("resp", wormchainConn.BroadcastTxResponseToString(txResp)))
|
||||
|
||||
return txResp, nil
|
||||
|
|
|
@ -3,12 +3,18 @@ package gwrelayer
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/certusone/wormhole/node/pkg/common"
|
||||
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||
|
||||
sdktypes "github.com/cosmos/cosmos-sdk/types"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Test_convertBech32AddressToWormhole(t *testing.T) {
|
||||
|
@ -29,7 +35,7 @@ func Test_convertBech32AddressToWormhole(t *testing.T) {
|
|||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func Test_shouldPublish(t *testing.T) {
|
||||
func Test_shouldPublishToIbcTranslator(t *testing.T) {
|
||||
type Test struct {
|
||||
label string
|
||||
payload []byte
|
||||
|
@ -52,13 +58,63 @@ func Test_shouldPublish(t *testing.T) {
|
|||
|
||||
for _, tc := range tests {
|
||||
t.Run(string(tc.label), func(t *testing.T) {
|
||||
result, err := shouldPublish(tc.payload, vaa.ChainIDWormchain, targetAddress)
|
||||
result, err := shouldPublishToIbcTranslator(tc.payload, vaa.ChainIDWormchain, targetAddress)
|
||||
assert.Equal(t, tc.err, err != nil)
|
||||
assert.Equal(t, tc.result, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_shouldPublishToTokenBridge(t *testing.T) {
|
||||
type Test struct {
|
||||
label string
|
||||
chain vaa.ChainID
|
||||
address vaa.Address
|
||||
payload []byte
|
||||
result bool
|
||||
}
|
||||
|
||||
logger := zap.NewNop()
|
||||
|
||||
tokenBridges, tokenBridgeAddress, err := buildTokenBridgeMap(logger, common.MainNet)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, tokenBridges)
|
||||
require.Equal(t, tokenBridgeAddress, "wormhole1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjq4lyjmh")
|
||||
|
||||
tests := []Test{
|
||||
{label: "unknown chain", chain: vaa.ChainIDUnset, address: addr("0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585"), payload: []byte{}, result: false},
|
||||
{label: "unknown emitter", chain: vaa.ChainIDEthereum, address: addr("0000000000000000000000000000000000000000000000000000000000000000"), payload: []byte{}, result: false},
|
||||
{label: "wormchain", chain: vaa.ChainIDWormchain, address: addr("aeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924"), payload: []byte{}, result: false},
|
||||
{label: "empty payload", chain: vaa.ChainIDEthereum, address: addr("0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585"), payload: []byte{}, result: false},
|
||||
{label: "not an attest", chain: vaa.ChainIDEthereum, address: addr("0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585"), payload: []byte{0x1}, result: false},
|
||||
{label: "should publish", chain: vaa.ChainIDEthereum, address: addr("0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585"), payload: []byte{0x2}, result: true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(string(tc.label), func(t *testing.T) {
|
||||
v := &vaa.VAA{
|
||||
Version: uint8(1),
|
||||
GuardianSetIndex: uint32(1),
|
||||
Signatures: []*vaa.Signature{},
|
||||
Timestamp: time.Unix(0, 0),
|
||||
Nonce: uint32(1),
|
||||
Sequence: uint64(1),
|
||||
ConsistencyLevel: uint8(32),
|
||||
EmitterChain: tc.chain,
|
||||
EmitterAddress: tc.address,
|
||||
Payload: tc.payload,
|
||||
}
|
||||
|
||||
result := shouldPublishToTokenBridge(tokenBridges, v)
|
||||
assert.Equal(t, tc.result, result)
|
||||
})
|
||||
}
|
||||
|
||||
addr, err := sdktypes.Bech32ifyAddressBytes("wormhole", decodeBytes("aeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924"))
|
||||
require.NoError(t, err)
|
||||
fmt.Println(addr)
|
||||
}
|
||||
|
||||
func decodeBytes(s string) []byte {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
|
@ -66,3 +122,11 @@ func decodeBytes(s string) []byte {
|
|||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func addr(str string) vaa.Address {
|
||||
a, err := vaa.StringToAddress(str)
|
||||
if err != nil {
|
||||
panic("failed to convert address")
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ var knownDevnetTokenbridgeEmitters = map[vaa.ChainID]string{
|
|||
vaa.ChainIDTerra: "000000000000000000000000784999135aaa8a3ca5914468852fdddbddd8789d",
|
||||
vaa.ChainIDBSC: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16",
|
||||
vaa.ChainIDAlgorand: "8ec299cb7f3efec28f542397e07f07118d74c875f85409ed8e6b93c17b60e992",
|
||||
vaa.ChainIDWormchain: "f04a313a7349b120c55c99788f12f712176bb3e5926d012d0ea72fa2bbb85051",
|
||||
vaa.ChainIDWormchain: "45dbea4617971d93188eda21530bc6503d153313b6f575048c2c35dbc6e4fb06",
|
||||
vaa.ChainIDSui: "be8d2e6809d4873bcf1d8be6af2b92500091ad6aa5dc76bc717af86a58d300ca",
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,7 @@
|
|||
"max_bytes": "1048576"
|
||||
},
|
||||
"validator": {
|
||||
"pub_key_types": [
|
||||
"ed25519"
|
||||
]
|
||||
"pub_key_types": ["ed25519"]
|
||||
},
|
||||
"version": {}
|
||||
},
|
||||
|
@ -51,6 +49,20 @@
|
|||
"pub_key": null,
|
||||
"account_number": "0",
|
||||
"sequence": "0"
|
||||
},
|
||||
{
|
||||
"@type": "/cosmos.auth.v1beta1.BaseAccount",
|
||||
"address": "wormhole1s5a6dg9p902z5rhjgkk0ts8lulvtmhmpftasxe",
|
||||
"pub_key": null,
|
||||
"account_number": "0",
|
||||
"sequence": "0"
|
||||
},
|
||||
{
|
||||
"@type": "/cosmos.auth.v1beta1.BaseAccount",
|
||||
"address": "wormhole1dtwappgz4zfmlhay44x5r787u6ap0zhrk2m09m",
|
||||
"pub_key": null,
|
||||
"account_number": "0",
|
||||
"sequence": "0"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -98,6 +110,32 @@
|
|||
"amount": "200000000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "wormhole1s5a6dg9p902z5rhjgkk0ts8lulvtmhmpftasxe",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "utest",
|
||||
"amount": "100000000000"
|
||||
},
|
||||
{
|
||||
"denom": "uworm",
|
||||
"amount": "200000000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "wormhole1dtwappgz4zfmlhay44x5r787u6ap0zhrk2m09m",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "utest",
|
||||
"amount": "100000000000"
|
||||
},
|
||||
{
|
||||
"denom": "uworm",
|
||||
"amount": "200000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"supply": [],
|
||||
|
@ -344,10 +382,7 @@
|
|||
"create_localhost": false,
|
||||
"next_client_sequence": "0",
|
||||
"params": {
|
||||
"allowed_clients": [
|
||||
"06-solomachine",
|
||||
"07-tendermint"
|
||||
]
|
||||
"allowed_clients": ["06-solomachine", "07-tendermint"]
|
||||
}
|
||||
},
|
||||
"connection_genesis": {
|
||||
|
@ -438,9 +473,7 @@
|
|||
{
|
||||
"expirationTime": 0,
|
||||
"index": 0,
|
||||
"keys": [
|
||||
"vvpCnVfNGLf4pNkaLamrSvBdD74="
|
||||
]
|
||||
"keys": ["vvpCnVfNGLf4pNkaLamrSvBdD74="]
|
||||
}
|
||||
],
|
||||
"guardianValidatorList": [
|
||||
|
|
Loading…
Reference in New Issue