Compare commits

...

4 Commits

Author SHA1 Message Date
Bruce Riley d38cda598a Add admin command tests 2024-04-24 18:08:09 -05:00
Bruce Riley e2458dcac4 Code review rework 2024-04-24 18:08:09 -05:00
Bruce Riley 39db1176af Node: Adminserver commands should not panic 2024-04-24 18:08:09 -05:00
Dirk Brink a566c3d3bf docs: Update security.md with Cantina NTT audit report 2024-04-24 18:50:49 -04:00
9 changed files with 1196 additions and 176 deletions

View File

@ -44,6 +44,7 @@ As these 3rd party audits are completed and issues are sufficiently addressed, w
- **[Jan 2024 - OtterSec](https://github.com/wormhole-foundation/wormhole-audits/blob/main/2024-01-ottersec-terra.pdf)**: _Terra Classic Contract Upgrades_
- **[Feb 2024 - Cyfrin](https://github.com/wormhole-foundation/wormhole-audits/blob/main/2024-04-09-cyfrin-wormhole-evm-cctp-v2-1.pdf)**: _CCTP EVM Contracts_
- **[Mar 2024 - Cyfrin](https://github.com/wormhole-foundation/wormhole-audits/blob/main/2024-04-11-cyfrin-wormhole-evm-ntt.pdf)**: _NTT EVM Contracts_
- **[Mar 2024 - Cantina](https://github.com/wormhole-foundation/wormhole-audits/blob/main/2024-04-cantina-wormhole-evm-ntt.pdf)**: _NTT EVM Contracts_
- **[Mar 2024 - OtterSec](https://github.com/wormhole-foundation/wormhole-audits/blob/main/2024-03-28-ottersec-solana-ntt.pdf)**: _NTT Solana Contracts_
- **[Mar 2024 - Neodyme](https://github.com/wormhole-foundation/wormhole-audits/blob/main/2024-04-12-neodyme-solana-ntt.pdf)**: _NTT Solana Contracts_

View File

@ -717,7 +717,7 @@ func runWormchainMigrateContractTemplate(cmd *cobra.Command, args []string) {
log.Fatal("--contract-address must be specified.")
}
if *wormchainMigrateContractInstantiationMsg == "" {
log.Fatal("--instantiate-msg must be specified.")
log.Fatal("--instantiation-msg must be specified.")
}
m := &nodev1.InjectGovernanceVAARequest{

View File

@ -118,12 +118,16 @@ func adminGuardianSetUpdateToVAA(req *nodev1.GuardianSetUpdate, timestamp time.T
addrs[i] = ethAddr
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyGuardianSetUpdate{
Keys: addrs,
NewIndex: guardianSetIndex + 1,
}.Serialize())
body, err := vaa.BodyGuardianSetUpdate{
Keys: addrs,
NewIndex: guardianSetIndex + 1,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -146,12 +150,16 @@ func adminContractUpgradeToVAA(req *nodev1.ContractUpgrade, timestamp time.Time,
newContractAddress := vaa.Address{}
copy(newContractAddress[:], b)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyContractUpgrade{
ChainID: vaa.ChainID(req.ChainId),
NewContract: newContractAddress,
}.Serialize())
body, err := vaa.BodyContractUpgrade{
ChainID: vaa.ChainID(req.ChainId),
NewContract: newContractAddress,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -174,13 +182,17 @@ func tokenBridgeRegisterChain(req *nodev1.BridgeRegisterChain, timestamp time.Ti
emitterAddress := vaa.Address{}
copy(emitterAddress[:], b)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyTokenBridgeRegisterChain{
Module: req.Module,
ChainID: vaa.ChainID(req.ChainId),
EmitterAddress: emitterAddress,
}.Serialize())
body, err := vaa.BodyTokenBridgeRegisterChain{
Module: req.Module,
ChainID: vaa.ChainID(req.ChainId),
EmitterAddress: emitterAddress,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -203,13 +215,17 @@ func recoverChainId(req *nodev1.RecoverChainId, timestamp time.Time, guardianSet
return nil, errors.New("invalid new_chain_id")
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyRecoverChainId{
Module: req.Module,
EvmChainID: evm_chain_id,
NewChainID: vaa.ChainID(req.NewChainId),
}.Serialize())
body, err := vaa.BodyRecoverChainId{
Module: req.Module,
EvmChainID: evm_chain_id,
NewChainID: vaa.ChainID(req.NewChainId),
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -254,20 +270,24 @@ func accountantModifyBalance(req *nodev1.AccountantModifyBalance, timestamp time
tokenAdress := vaa.Address{}
copy(tokenAdress[:], b)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyAccountantModifyBalance{
Module: req.Module,
TargetChainID: vaa.ChainID(req.TargetChainId),
body, err := vaa.BodyAccountantModifyBalance{
Module: req.Module,
TargetChainID: vaa.ChainID(req.TargetChainId),
Sequence: req.Sequence,
ChainId: vaa.ChainID(req.ChainId),
TokenChain: vaa.ChainID(req.TokenChain),
TokenAddress: tokenAdress,
Kind: uint8(req.Kind),
Amount: amount,
Reason: req.Reason,
}.Serialize())
Sequence: req.Sequence,
ChainId: vaa.ChainID(req.ChainId),
TokenChain: vaa.ChainID(req.TokenChain),
TokenAddress: tokenAdress,
Kind: uint8(req.Kind),
Amount: amount,
Reason: req.Reason,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -290,13 +310,17 @@ func tokenBridgeUpgradeContract(req *nodev1.BridgeUpgradeContract, timestamp tim
newContract := vaa.Address{}
copy(newContract[:], b)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyTokenBridgeUpgradeContract{
Module: req.Module,
TargetChainID: vaa.ChainID(req.TargetChainId),
NewContract: newContract,
}.Serialize())
body, err := vaa.BodyTokenBridgeUpgradeContract{
Module: req.Module,
TargetChainID: vaa.ChainID(req.TargetChainId),
NewContract: newContract,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -316,11 +340,15 @@ func wormchainStoreCode(req *nodev1.WormchainStoreCode, timestamp time.Time, gua
wasmHash := [32]byte{}
copy(wasmHash[:], b)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyWormchainStoreCode{
WasmHash: wasmHash,
}.Serialize())
body, err := vaa.BodyWormchainStoreCode{
WasmHash: wasmHash,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -329,11 +357,15 @@ func wormchainStoreCode(req *nodev1.WormchainStoreCode, timestamp time.Time, gua
func wormchainInstantiateContract(req *nodev1.WormchainInstantiateContract, timestamp time.Time, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
instantiationParams_hash := vaa.CreateInstatiateCosmwasmContractHash(req.CodeId, req.Label, []byte(req.InstantiationMsg))
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyWormchainInstantiateContract{
InstantiationParamsHash: instantiationParams_hash,
}.Serialize())
body, err := vaa.BodyWormchainInstantiateContract{
InstantiationParamsHash: instantiationParams_hash,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -341,11 +373,15 @@ func wormchainInstantiateContract(req *nodev1.WormchainInstantiateContract, time
func wormchainMigrateContract(req *nodev1.WormchainMigrateContract, timestamp time.Time, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
instantiationParams_hash := vaa.CreateMigrateCosmwasmContractHash(req.CodeId, req.Contract, []byte(req.InstantiationMsg))
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyWormchainMigrateContract{
MigrationParamsHash: instantiationParams_hash,
}.Serialize())
body, err := vaa.BodyWormchainMigrateContract{
MigrationParamsHash: instantiationParams_hash,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -373,11 +409,16 @@ func wormchainWasmInstantiateAllowlist(
var decodedAddr32 [32]byte
copy(decodedAddr32[:], decodedAddr)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, vaa.BodyWormchainWasmAllowlistInstantiate{
body, err := vaa.BodyWormchainWasmAllowlistInstantiate{
ContractAddr: decodedAddr32,
CodeId: req.CodeId,
}.Serialize(action))
}.Serialize(action)
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -388,11 +429,17 @@ func gatewayScheduleUpgrade(
nonce uint32,
sequence uint64,
) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, vaa.BodyGatewayScheduleUpgrade{
body, err := vaa.BodyGatewayScheduleUpgrade{
Name: req.Name,
Height: req.Height,
}.Serialize())
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -402,10 +449,14 @@ func gatewayCancelUpgrade(
nonce uint32,
sequence uint64,
) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.EmptyPayloadVaa(vaa.GatewayModuleStr, vaa.ActionCancelUpgrade, vaa.ChainIDWormchain),
)
body, err := vaa.EmptyPayloadVaa(vaa.GatewayModuleStr, vaa.ActionCancelUpgrade, vaa.ChainIDWormchain)
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -424,10 +475,15 @@ func gatewayIbcComposabilityMwSetContract(
var decodedAddr32 [32]byte
copy(decodedAddr32[:], decodedAddr)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, vaa.BodyGatewayIbcComposabilityMwContract{
body, err := vaa.BodyGatewayIbcComposabilityMwContract{
ContractAddr: decodedAddr32,
}.Serialize())
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -440,12 +496,17 @@ func circleIntegrationUpdateWormholeFinality(req *nodev1.CircleIntegrationUpdate
if req.Finality > math.MaxUint8 {
return nil, fmt.Errorf("invalid finality, must be <= %d", math.MaxUint8)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyCircleIntegrationUpdateWormholeFinality{
TargetChainID: vaa.ChainID(req.TargetChainId),
Finality: uint8(req.Finality),
}.Serialize())
body, err := vaa.BodyCircleIntegrationUpdateWormholeFinality{
TargetChainID: vaa.ChainID(req.TargetChainId),
Finality: uint8(req.Finality),
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -470,14 +531,18 @@ func circleIntegrationRegisterEmitterAndDomain(req *nodev1.CircleIntegrationRegi
foreignEmitterAddress := vaa.Address{}
copy(foreignEmitterAddress[:], b)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyCircleIntegrationRegisterEmitterAndDomain{
TargetChainID: vaa.ChainID(req.TargetChainId),
ForeignEmitterChainId: vaa.ChainID(req.ForeignEmitterChainId),
ForeignEmitterAddress: foreignEmitterAddress,
CircleDomain: req.CircleDomain,
}.Serialize())
body, err := vaa.BodyCircleIntegrationRegisterEmitterAndDomain{
TargetChainID: vaa.ChainID(req.TargetChainId),
ForeignEmitterChainId: vaa.ChainID(req.ForeignEmitterChainId),
ForeignEmitterAddress: foreignEmitterAddress,
CircleDomain: req.CircleDomain,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -499,12 +564,16 @@ func circleIntegrationUpgradeContractImplementation(req *nodev1.CircleIntegratio
newImplementationAddress := vaa.Address{}
copy(newImplementationAddress[:], b)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyCircleIntegrationUpgradeContractImplementation{
TargetChainID: vaa.ChainID(req.TargetChainId),
NewImplementationAddress: newImplementationAddress,
}.Serialize())
body, err := vaa.BodyCircleIntegrationUpgradeContractImplementation{
TargetChainID: vaa.ChainID(req.TargetChainId),
NewImplementationAddress: newImplementationAddress,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -527,7 +596,10 @@ func ibcUpdateChannelChain(
if len(req.ChannelId) > 64 {
return nil, fmt.Errorf("invalid channel ID length, must be <= 64")
}
channelId := vaa.LeftPadIbcChannelId(req.ChannelId)
channelId, err := vaa.LeftPadIbcChannelId(req.ChannelId)
if err != nil {
return nil, fmt.Errorf("failed to left pad channel id: %w", err)
}
var module string
if req.Module == nodev1.IbcUpdateChannelChainModule_IBC_UPDATE_CHANNEL_CHAIN_MODULE_RECEIVER {
@ -538,14 +610,17 @@ func ibcUpdateChannelChain(
return nil, fmt.Errorf("unrecognized ibc update channel chain module")
}
// create governance VAA
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyIbcUpdateChannelChain{
TargetChainId: vaa.ChainID(req.TargetChainId),
ChannelId: channelId,
ChainId: vaa.ChainID(req.ChainId),
}.Serialize(module))
body, err := vaa.BodyIbcUpdateChannelChain{
TargetChainId: vaa.ChainID(req.TargetChainId),
ChannelId: channelId,
ChainId: vaa.ChainID(req.ChainId),
}.Serialize(module)
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -568,12 +643,16 @@ func wormholeRelayerSetDefaultDeliveryProvider(req *nodev1.WormholeRelayerSetDef
NewDefaultDeliveryProviderAddress := vaa.Address{}
copy(NewDefaultDeliveryProviderAddress[:], b)
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyWormholeRelayerSetDefaultDeliveryProvider{
ChainID: vaa.ChainID(req.ChainId),
NewDefaultDeliveryProviderAddress: NewDefaultDeliveryProviderAddress,
}.Serialize())
body, err := vaa.BodyWormholeRelayerSetDefaultDeliveryProvider{
ChainID: vaa.ChainID(req.ChainId),
NewDefaultDeliveryProviderAddress: NewDefaultDeliveryProviderAddress,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -598,7 +677,6 @@ func evmCallToVaa(evmCall *nodev1.EvmCall, timestamp time.Time, guardianSetIndex
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -619,13 +697,17 @@ func solanaCallToVaa(solanaCall *nodev1.SolanaCall, timestamp time.Time, guardia
return nil, fmt.Errorf("failed to decode instruction: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex,
vaa.BodyGeneralPurposeGovernanceSolana{
ChainID: vaa.ChainID(solanaCall.ChainId),
GovernanceContract: governanceContract,
Instruction: instruction,
}.Serialize())
body, err := vaa.BodyGeneralPurposeGovernanceSolana{
ChainID: vaa.ChainID(solanaCall.ChainId),
GovernanceContract: governanceContract,
Instruction: instruction,
}.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize governance body: %w", err)
}
v := vaa.CreateGovernanceVAA(timestamp, nonce, sequence, guardianSetIndex, body)
return v, nil
}
@ -677,7 +759,7 @@ func GovMsgToVaa(message *nodev1.GovernanceMessage, currentSetIndex uint32, time
case *nodev1.GovernanceMessage_SolanaCall:
v, err = solanaCallToVaa(payload.SolanaCall, timestamp, currentSetIndex, message.Nonce, message.Sequence)
default:
panic(fmt.Sprintf("unsupported VAA type: %T", payload))
err = fmt.Errorf("unsupported VAA type: %T", payload)
}
return v, err

View File

@ -2,28 +2,33 @@
package adminrpc
import (
"bytes"
"context"
"crypto/ecdsa"
math_rand "math/rand"
"testing"
"time"
"github.com/certusone/wormhole/node/pkg/common"
nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1"
"github.com/certusone/wormhole/node/pkg/watchers/evm/connectors"
"github.com/certusone/wormhole/node/pkg/watchers/evm/connectors/ethabi"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/event"
ethRpc "github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
"go.uber.org/zap"
"google.golang.org/protobuf/encoding/prototext"
)
type mockEVMConnector struct {
guardianAddrs []common.Address
guardianAddrs []ethCommon.Address
guardianSetIndex uint32
}
@ -42,7 +47,7 @@ func (m mockEVMConnector) NetworkName() string {
panic("unimplemented")
}
func (m mockEVMConnector) ContractAddress() common.Address {
func (m mockEVMConnector) ContractAddress() ethCommon.Address {
panic("unimplemented")
}
@ -50,11 +55,11 @@ func (m mockEVMConnector) WatchLogMessagePublished(ctx context.Context, errC cha
panic("unimplemented")
}
func (m mockEVMConnector) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
func (m mockEVMConnector) TransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) {
panic("unimplemented")
}
func (m mockEVMConnector) TimeOfBlockByHash(ctx context.Context, hash common.Hash) (uint64, error) {
func (m mockEVMConnector) TimeOfBlockByHash(ctx context.Context, hash ethCommon.Hash) (uint64, error) {
panic("unimplemented")
}
@ -82,7 +87,7 @@ func (c mockEVMConnector) SubscribeNewHead(ctx context.Context, ch chan<- *types
panic("unimplemented")
}
func generateGS(num int) (keys []*ecdsa.PrivateKey, addrs []common.Address) {
func generateGS(num int) (keys []*ecdsa.PrivateKey, addrs []ethCommon.Address) {
for i := 0; i < num; i++ {
key, err := ethcrypto.GenerateKey()
if err != nil {
@ -94,7 +99,7 @@ func generateGS(num int) (keys []*ecdsa.PrivateKey, addrs []common.Address) {
return
}
func addrsToHexStrings(addrs []common.Address) (out []string) {
func addrsToHexStrings(addrs []ethCommon.Address) (out []string) {
for _, addr := range addrs {
out = append(out, addr.String())
}
@ -125,7 +130,7 @@ func generateMockVAA(gsIndex uint32, gsKeys []*ecdsa.PrivateKey) []byte {
return vBytes
}
func setupAdminServerForVAASigning(gsIndex uint32, gsAddrs []common.Address) *nodePrivilegedService {
func setupAdminServerForVAASigning(gsIndex uint32, gsAddrs []ethCommon.Address) *nodePrivilegedService {
gk, err := ethcrypto.GenerateKey()
if err != nil {
panic(err)
@ -150,7 +155,7 @@ func setupAdminServerForVAASigning(gsIndex uint32, gsAddrs []common.Address) *no
}
func TestSignExistingVAA_NoVAA(t *testing.T) {
s := setupAdminServerForVAASigning(0, []common.Address{})
s := setupAdminServerForVAASigning(0, []ethCommon.Address{})
_, err := s.SignExistingVAA(context.Background(), &nodev1.SignExistingVAARequest{
Vaa: nil,
@ -247,7 +252,7 @@ func TestSignExistingVAA_CantReachQuorum(t *testing.T) {
gsAddrs = append(gsAddrs, s.guardianAddress)
_, err := s.SignExistingVAA(context.Background(), &nodev1.SignExistingVAARequest{
Vaa: v,
NewGuardianAddrs: addrsToHexStrings(append(gsAddrs, common.Address{0, 1}, common.Address{3, 1}, common.Address{8, 1})),
NewGuardianAddrs: addrsToHexStrings(append(gsAddrs, ethCommon.Address{0, 1}, ethCommon.Address{3, 1}, ethCommon.Address{8, 1})),
NewGuardianSetIndex: 1,
})
require.ErrorContains(t, err, "cannot reach quorum on new guardian set with the local signature")
@ -270,3 +275,131 @@ func TestSignExistingVAA_Valid(t *testing.T) {
v2 := generateMockVAA(1, append(gsKeys, s.gk))
require.Equal(t, v2, res.Vaa)
}
const govGuardianSetIndex = uint32(4)
var govTimestamp = time.Now()
const govEmitterChain = vaa.ChainIDSolana
var govEmitterAddr vaa.Address = [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}
// verifyGovernanceVAA verifies the VAA fields of a generated governance VAA. Note that it doesn't verify the payload because that is
// already verified in `sdk/vaa/payload_test` and we don't want to duplicate all those arrays.
func verifyGovernanceVAA(t *testing.T, v *vaa.VAA, expectedSeqNo uint64, expectedNonce uint32) {
t.Helper()
require.NotNil(t, v)
assert.Equal(t, uint8(vaa.SupportedVAAVersion), v.Version)
assert.Equal(t, govGuardianSetIndex, v.GuardianSetIndex)
assert.Nil(t, v.Signatures)
assert.Equal(t, govTimestamp, v.Timestamp)
assert.Equal(t, expectedNonce, v.Nonce)
assert.Equal(t, expectedSeqNo, v.Sequence)
assert.Equal(t, uint8(32), v.ConsistencyLevel)
assert.Equal(t, govEmitterChain, v.EmitterChain)
assert.True(t, bytes.Equal(govEmitterAddr[:], v.EmitterAddress[:]))
}
func Test_adminGuardianSetUpdateToVAA(t *testing.T) {
// Success case.
govMsg := &nodev1.GovernanceMessage{
Sequence: math_rand.Uint64(), //nolint:gosec
Nonce: math_rand.Uint32(), //nolint:gosec
Payload: &nodev1.GovernanceMessage_GuardianSet{
GuardianSet: &nodev1.GuardianSetUpdate{
Guardians: []*nodev1.GuardianSetUpdate_Guardian{
{
Pubkey: "0x187727CdD17C8142FE9b29A066F577548423aF0e",
Name: "P2P Validator",
},
},
},
},
}
vaa, err := GovMsgToVaa(govMsg, govGuardianSetIndex, govTimestamp)
require.NoError(t, err)
verifyGovernanceVAA(t, vaa, govMsg.Sequence, govMsg.Nonce)
// No guardian keys should return an error.
govMsg.Payload = &nodev1.GovernanceMessage_GuardianSet{
GuardianSet: &nodev1.GuardianSetUpdate{
// Leave Guardians nil.
},
}
vaa, err = GovMsgToVaa(govMsg, govGuardianSetIndex, govTimestamp)
require.ErrorContains(t, err, "empty guardian set specified")
assert.Nil(t, vaa)
// Too many guardian keys should return an error.
guardians := make([]*nodev1.GuardianSetUpdate_Guardian, 0, common.MaxGuardianCount+1)
for count := 0; count < common.MaxGuardianCount+1; count++ {
guardians = append(guardians, &nodev1.GuardianSetUpdate_Guardian{Pubkey: "0x187727CdD17C8142FE9b29A066F577548423aF0e", Name: "P2P Validator"})
}
govMsg.Payload = &nodev1.GovernanceMessage_GuardianSet{
GuardianSet: &nodev1.GuardianSetUpdate{
Guardians: guardians,
},
}
vaa, err = GovMsgToVaa(govMsg, govGuardianSetIndex, govTimestamp)
require.ErrorContains(t, err, "too many guardians")
assert.Nil(t, vaa)
// Invalid guardian key should return an error.
govMsg.Payload = &nodev1.GovernanceMessage_GuardianSet{
GuardianSet: &nodev1.GuardianSetUpdate{
Guardians: []*nodev1.GuardianSetUpdate_Guardian{
{
Pubkey: "HelloWorld",
Name: "P2P Validator",
},
},
},
}
vaa, err = GovMsgToVaa(govMsg, govGuardianSetIndex, govTimestamp)
require.ErrorContains(t, err, "invalid pubkey format")
assert.Nil(t, vaa)
// Duplicate guardian key should return an error.
govMsg.Payload = &nodev1.GovernanceMessage_GuardianSet{
GuardianSet: &nodev1.GuardianSetUpdate{
Guardians: []*nodev1.GuardianSetUpdate_Guardian{
{
Pubkey: "0x187727CdD17C8142FE9b29A066F577548423aF0e",
Name: "P2P Validator",
},
{
Pubkey: "0x187727CdD17C8142FE9b29A066F577548423aF0e",
Name: "P2P Validator",
},
},
},
}
vaa, err = GovMsgToVaa(govMsg, govGuardianSetIndex, govTimestamp)
require.ErrorContains(t, err, "duplicate pubkey at index 1 (duplicate of 0)")
assert.Nil(t, vaa)
}
func Test_adminCommands(t *testing.T) {
for _, tst := range adminCommandTest {
t.Run(tst.label, func(t *testing.T) {
var msg nodev1.InjectGovernanceVAARequest
err := prototext.Unmarshal([]byte(tst.prototext), &msg)
require.NoError(t, err)
require.Equal(t, 1, len(msg.Messages))
govMsg := msg.Messages[0]
vaa, err := GovMsgToVaa(govMsg, govGuardianSetIndex, govTimestamp)
if tst.errText == "" {
require.NoError(t, err)
verifyGovernanceVAA(t, vaa, govMsg.Sequence, govMsg.Nonce)
} else {
require.ErrorContains(t, err, tst.errText)
}
})
}
}

View File

@ -0,0 +1,638 @@
//nolint:unparam
package adminrpc
type adminCommandTestEntry struct {
label string
errText string // empty string means success
prototext string
}
var adminCommandTest = []adminCommandTestEntry{
// build/bin/guardiand template guardian-set-update --num=2 --idx=4
{
label: "GuardianSetUpdate success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 13675600082943268828
nonce: 1875482155
guardian_set: {
guardians: {
pubkey: "0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe"
name: "Example validator 0"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
}
}`,
},
{
label: "GuardianSetUpdate no guardian keys",
errText: "empty guardian set specified",
prototext: `
current_set_index: 4
messages: {
sequence: 13675600082943268828
nonce: 1875482155
guardian_set: {
}
}`,
},
{
label: "GuardianSetUpdate too many guardian keys",
errText: "too many guardians",
prototext: `
current_set_index: 4
messages: {
sequence: 13675600082943268828
nonce: 1875482155
guardian_set: {
guardians: {
pubkey: "0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe"
name: "Example validator 0"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
guardians: {
pubkey: "0x88D7D8B32a9105d228100E72dFFe2Fae0705D31c"
name: "Example validator 1"
}
}
}`,
},
{
label: "GuardianSetUpdate invalid guardian key",
errText: "invalid pubkey format",
prototext: `
current_set_index: 4
messages: {
sequence: 13675600082943268828
nonce: 1875482155
guardian_set: {
guardians: {
pubkey: "Hello, World!"
name: "Example validator 0"
}
}
}`,
},
{
label: "GuardianSetUpdate duplicate guardian key",
errText: "duplicate pubkey at index 1",
prototext: `
current_set_index: 4
messages: {
sequence: 13675600082943268828
nonce: 1875482155
guardian_set: {
guardians: {
pubkey: "0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe"
name: "Example validator 0"
}
guardians: {
pubkey: "0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe"
name: "Example validator 0"
}
}
}`,
},
// build/bin/guardiand template contract-upgrade --chain-id "ethereum" --new-address 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550
{
label: "ContractUpgrade success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 12970493895929703138
nonce: 700990237
contract_upgrade: {
chain_id: 2
new_contract: "000000000000000000000000c89ce4735882c9f0f0fe26686c53074e09b0d550"
}
}`,
},
{
label: "ContractUpgrade invalid contract address",
errText: "invalid new contract address encoding (expected hex)",
prototext: `
current_set_index: 4
messages: {
sequence: 12970493895929703138
nonce: 700990237
contract_upgrade: {
chain_id: 2
new_contract: "Hello, World!"
}
}`,
},
{
label: "ContractUpgrade contract address wrong length",
errText: "invalid new_contract address",
prototext: `
current_set_index: 4
messages: {
sequence: 12970493895929703138
nonce: 700990237
contract_upgrade: {
chain_id: 2
new_contract: "c89ce4735882c9f0f0fe26686c53074e09b0d550"
}
}`,
},
{
label: "ContractUpgrade chain id too large",
errText: "invalid chain_id",
prototext: `
current_set_index: 4
messages: {
sequence: 12970493895929703138
nonce: 700990237
contract_upgrade: {
chain_id: 65536
new_contract: "000000000000000000000000c89ce4735882c9f0f0fe26686c53074e09b0d550"
}
}`,
},
// build/bin/guardiand template token-bridge-register-chain --chain-id ethereum --module TokenBridge --new-address 0x0290FB167208Af455bB137780163b7B7a9a10C16
{
label: "BridgeRegisterChain success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 13048739474937843907
nonce: 277897432
bridge_register_chain: {
module: "TokenBridge"
chain_id: 2
emitter_address: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
}
}`,
},
{
label: "BridgeRegisterChain invalid chain id",
errText: "invalid chain_id",
prototext: `
current_set_index: 4
messages: {
sequence: 13048739474937843907
nonce: 277897432
bridge_register_chain: {
module: "TokenBridge"
chain_id: 65536
emitter_address: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
}
}`,
},
{
label: "BridgeRegisterChain invalid emitter address",
errText: "invalid emitter address encoding (expected hex)",
prototext: `
current_set_index: 4
messages: {
sequence: 13048739474937843907
nonce: 277897432
bridge_register_chain: {
module: "TokenBridge"
chain_id: 2
emitter_address: "Hello, World!"
}
}`,
},
{
label: "BridgeRegisterChain invalid emitter address length",
errText: "invalid emitter address (expected 32 bytes)",
prototext: `
current_set_index: 4
messages: {
sequence: 13048739474937843907
nonce: 277897432
bridge_register_chain: {
module: "TokenBridge"
chain_id: 2
emitter_address: "0290fb167208af455bb137780163b7b7a9a10c16"
}
}`,
},
// build/bin/guardiand template recover-chain-id --module TokenBridge --evm-chain-id 42 --new-chain-id 43
{
label: "RecoverChainId success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 4474356899438211298
nonce: 4040780926
recover_chain_id: {
module: "TokenBridge"
evm_chain_id: "42"
new_chain_id: 43
}
}`,
},
{
label: "RecoverChainId invalid evm chain id",
errText: "invalid evm_chain_id",
prototext: `
current_set_index: 4
messages: {
sequence: 4474356899438211298
nonce: 4040780926
recover_chain_id: {
module: "TokenBridge"
evm_chain_id: "Hello, World!"
new_chain_id: 43
}
}`,
},
{
label: "RecoverChainId evm chain id too large",
errText: "evm_chain_id overflow",
prototext: `
current_set_index: 4
messages: {
sequence: 4474356899438211298
nonce: 4040780926
recover_chain_id: {
module: "TokenBridge"
evm_chain_id: "115792089237316195423570985008687907853269984665640564039457584007913129639936"
new_chain_id: 43
}
}`,
},
{
label: "RecoverChainId invalid new chain id",
errText: "invalid new_chain_id",
prototext: `
current_set_index: 4
messages: {
sequence: 4474356899438211298
nonce: 4040780926
recover_chain_id: {
module: "TokenBridge"
evm_chain_id: "42"
new_chain_id: 65536
}
}`,
},
// TODO: Skipping AccountantModifyBalance because it doesn't have an admin command to generate the prototext.
// build/bin/guardiand template token-bridge-upgrade-contract --chain-id ethereum --module TokenBridge --new-address 0x0290FB167208Af455bB137780163b7B7a9a10C16
{
label: "BridgeUpgradeContract success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 2474806415844516465
nonce: 1137535017
bridge_contract_upgrade: {
module: "TokenBridge"
target_chain_id: 2
new_contract: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
}
}`,
},
{
label: "BridgeUpgradeContract invalid target chain id",
errText: "invalid target_chain_id",
prototext: `
current_set_index: 4
messages: {
sequence: 2474806415844516465
nonce: 1137535017
bridge_contract_upgrade: {
module: "TokenBridge"
target_chain_id: 65536
new_contract: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
}
}`,
},
{
label: "BridgeUpgradeContract invalid new contract address",
errText: "invalid new contract address (expected hex)",
prototext: `
current_set_index: 4
messages: {
sequence: 2474806415844516465
nonce: 1137535017
bridge_contract_upgrade: {
module: "TokenBridge"
target_chain_id: 2
new_contract: "Hello, World!"
}
}`,
},
{
label: "BridgeUpgradeContract contract address too long",
errText: "invalid new contract address (expected 32 bytes)",
prototext: `
current_set_index: 4
messages: {
sequence: 2474806415844516465
nonce: 1137535017
bridge_contract_upgrade: {
module: "TokenBridge"
target_chain_id: 2
new_contract: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c1600"
}
}`,
},
// build/bin/guardiand template wormchain-store-code --wasm-hash 0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16
{
label: "WormchainStoreCode success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 1985924966232230622
nonce: 1162627577
wormchain_store_code: {
wasm_hash: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
}
}`,
},
{
label: "WormchainStoreCode invalid wasm hash",
errText: "invalid cosmwasm bytecode hash (expected hex)",
prototext: `
current_set_index: 4
messages: {
sequence: 1985924966232230622
nonce: 1162627577
wormchain_store_code: {
wasm_hash: "Hello, World!"
}
}`,
},
{
label: "WormchainStoreCode invalid wasm hash length",
errText: "invalid cosmwasm bytecode hash (expected 32 bytes but received 33 bytes)",
prototext: `
current_set_index: 4
messages: {
sequence: 1985924966232230622
nonce: 1162627577
wormchain_store_code: {
wasm_hash: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c1600"
}
}`,
},
// build/bin/guardiand template wormchain-instantiate-contract --code-id 12345678 --label "Hi, Mom!" --instantiation-msg "Some random junk"
{
label: "WormchainInstantiateContract success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 3355941316502237895
nonce: 749992725
wormchain_instantiate_contract: {
code_id: 12345678
label: "Hi, Mom!"
instantiation_msg: "Some random junk"
}
}`,
},
// build/bin/guardiand template wormchain-migrate-contract --code-id 12345678 --contract-address wormhole1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqtm7t3h --instantiation-msg "Some junk"
{
label: "WormchainMigrateContract success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 13069018493465262425
nonce: 222803138
wormchain_migrate_contract: {
code_id: 12345678
contract: "wormhole1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqtm7t3h"
instantiation_msg: "Some junk"
}
}`,
},
// build/bin/guardiand template wormchain-add-wasm-instantiate-allowlist --code-id 12345678 --contract-address wormchain-add-wasm-instantiate-allowlist
{
label: "WormchainWasmInstantiateAllowlist success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 14341603504021037676
nonce: 1682273406
wormchain_wasm_instantiate_allowlist: {
code_id: 12345678
contract: "wormhole1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjq4lyjmh"
action: WORMCHAIN_WASM_INSTANTIATE_ALLOWLIST_ACTION_ADD
}
}`,
},
{
label: "WormchainWasmInstantiateAllowlist invalid bech32 contract address",
errText: "decoding bech32 failed",
prototext: `
current_set_index: 4
messages: {
sequence: 14341603504021037676
nonce: 1682273406
wormchain_wasm_instantiate_allowlist: {
code_id: 12345678
contract: "Hi, Mom!"
action: WORMCHAIN_WASM_INSTANTIATE_ALLOWLIST_ACTION_ADD
}
}`,
},
{
label: "WormchainWasmInstantiateAllowlist unexpected action",
errText: "unrecognized wasm instantiate allowlist action",
prototext: `
current_set_index: 4
messages: {
sequence: 14341603504021037676
nonce: 1682273406
wormchain_wasm_instantiate_allowlist: {
code_id: 12345678
contract: "wormhole1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjq4lyjmh"
action: WORMCHAIN_WASM_INSTANTIATE_ALLOWLIST_ACTION_UNSPECIFIED
}
}`,
},
// build/bin/guardiand template circle-integration-update-wormhole-finality --chain-id ethereum --finality 42
{
label: "CircleIntegrationUpdateWormholeFinality success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 6415677735604800159
nonce: 1410643993
circle_integration_update_wormhole_finality: {
finality: 42
target_chain_id: 2
}
}`,
},
// build/bin/guardiand template circle-integration-register-emitter-and-domain --chain-id ethereum --circle-domain 42 --foreign-emitter-chain-id bsc --foreign-emitter-address 0x0290FB167208Af455bB137780163b7B7a9a10C16
{
label: "CircleIntegrationRegisterEmitterAndDomain success",
errText: "",
prototext: `
current_set_index: 4
messages: {
sequence: 4922548351928530675
nonce: 1868545932
circle_integration_register_emitter_and_domain: {
foreign_emitter_chain_id: 4
foreign_emitter_address: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
circle_domain: 42
target_chain_id: 2
}
}`,
},
{
label: "CircleIntegrationRegisterEmitterAndDomain invalid target chain id",
errText: "invalid target chain id",
prototext: `
current_set_index: 4
messages: {
sequence: 4922548351928530675
nonce: 1868545932
circle_integration_register_emitter_and_domain: {
foreign_emitter_chain_id: 4
foreign_emitter_address: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
circle_domain: 42
target_chain_id: 65536
}
}`,
},
{
label: "CircleIntegrationRegisterEmitterAndDomain invalid foreign chain id",
errText: "invalid foreign emitter chain id",
prototext: `
current_set_index: 4
messages: {
sequence: 4922548351928530675
nonce: 1868545932
circle_integration_register_emitter_and_domain: {
foreign_emitter_chain_id: 65536
foreign_emitter_address: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
circle_domain: 42
target_chain_id: 2
}
}`,
},
{
label: "CircleIntegrationRegisterEmitterAndDomain invalid foreign emitter address",
errText: "invalid foreign emitter address encoding",
prototext: `
current_set_index: 4
messages: {
sequence: 4922548351928530675
nonce: 1868545932
circle_integration_register_emitter_and_domain: {
foreign_emitter_chain_id: 4
foreign_emitter_address: "Hello, World!"
circle_domain: 42
target_chain_id: 2
}
}`,
},
{
label: "CircleIntegrationRegisterEmitterAndDomain foreign emitter address too short",
errText: "invalid foreign emitter address (expected 32 bytes)",
prototext: `
current_set_index: 4
messages: {
sequence: 4922548351928530675
nonce: 1868545932
circle_integration_register_emitter_and_domain: {
foreign_emitter_chain_id: 4
foreign_emitter_address: "00000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
circle_domain: 42
target_chain_id: 2
}
}`,
},
}

View File

@ -3,6 +3,7 @@ package vaa
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"math"
@ -248,7 +249,7 @@ type (
}
)
func (b BodyContractUpgrade) Serialize() []byte {
func (b BodyContractUpgrade) Serialize() ([]byte, error) {
buf := new(bytes.Buffer)
// Module
@ -260,10 +261,10 @@ func (b BodyContractUpgrade) Serialize() []byte {
buf.Write(b.NewContract[:])
return buf.Bytes()
return buf.Bytes(), nil
}
func (b BodyGuardianSetUpdate) Serialize() []byte {
func (b BodyGuardianSetUpdate) Serialize() ([]byte, error) {
buf := new(bytes.Buffer)
// Module
@ -279,10 +280,10 @@ func (b BodyGuardianSetUpdate) Serialize() []byte {
buf.Write(k[:])
}
return buf.Bytes()
return buf.Bytes(), nil
}
func (r BodyTokenBridgeRegisterChain) Serialize() []byte {
func (r BodyTokenBridgeRegisterChain) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
MustWrite(payload, binary.BigEndian, r.ChainID)
payload.Write(r.EmitterAddress[:])
@ -290,13 +291,16 @@ func (r BodyTokenBridgeRegisterChain) Serialize() []byte {
return serializeBridgeGovernanceVaa(r.Module, ActionRegisterChain, 0, payload.Bytes())
}
func (r BodyTokenBridgeUpgradeContract) Serialize() []byte {
func (r BodyTokenBridgeUpgradeContract) Serialize() ([]byte, error) {
return serializeBridgeGovernanceVaa(r.Module, ActionUpgradeTokenBridge, r.TargetChainID, r.NewContract[:])
}
func (r BodyRecoverChainId) Serialize() []byte {
func (r BodyRecoverChainId) Serialize() ([]byte, error) {
// Module
buf := LeftPadBytes(r.Module, 32)
buf, err := LeftPadBytes(r.Module, 32)
if err != nil {
return nil, fmt.Errorf("failed to left pad module: %w", err)
}
// Action
var action GovernanceAction
if r.Module == "Core" {
@ -309,10 +313,10 @@ func (r BodyRecoverChainId) Serialize() []byte {
MustWrite(buf, binary.BigEndian, r.EvmChainID.Bytes32())
// NewChainID
MustWrite(buf, binary.BigEndian, r.NewChainID)
return buf.Bytes()
return buf.Bytes(), nil
}
func (r BodyAccountantModifyBalance) Serialize() []byte {
func (r BodyAccountantModifyBalance) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
MustWrite(payload, binary.BigEndian, r.Sequence)
MustWrite(payload, binary.BigEndian, r.ChainId)
@ -335,28 +339,28 @@ func (r BodyAccountantModifyBalance) Serialize() []byte {
return serializeBridgeGovernanceVaa(r.Module, ActionModifyBalance, r.TargetChainID, payload.Bytes())
}
func (r BodyWormchainStoreCode) Serialize() []byte {
func (r BodyWormchainStoreCode) Serialize() ([]byte, error) {
return serializeBridgeGovernanceVaa(WasmdModuleStr, ActionStoreCode, ChainIDWormchain, r.WasmHash[:])
}
func (r BodyWormchainInstantiateContract) Serialize() []byte {
func (r BodyWormchainInstantiateContract) Serialize() ([]byte, error) {
return serializeBridgeGovernanceVaa(WasmdModuleStr, ActionInstantiateContract, ChainIDWormchain, r.InstantiationParamsHash[:])
}
func (r BodyWormchainMigrateContract) Serialize() []byte {
func (r BodyWormchainMigrateContract) Serialize() ([]byte, error) {
return serializeBridgeGovernanceVaa(WasmdModuleStr, ActionMigrateContract, ChainIDWormchain, r.MigrationParamsHash[:])
}
func (r BodyWormchainWasmAllowlistInstantiate) Serialize(action GovernanceAction) []byte {
func (r BodyWormchainWasmAllowlistInstantiate) Serialize(action GovernanceAction) ([]byte, error) {
payload := &bytes.Buffer{}
payload.Write(r.ContractAddr[:])
MustWrite(payload, binary.BigEndian, r.CodeId)
return serializeBridgeGovernanceVaa(WasmdModuleStr, action, ChainIDWormchain, payload.Bytes())
}
func (r *BodyWormchainWasmAllowlistInstantiate) Deserialize(bz []byte) {
func (r *BodyWormchainWasmAllowlistInstantiate) Deserialize(bz []byte) error {
if len(bz) != 40 {
panic("incorrect payload length")
return fmt.Errorf("incorrect payload length, should be 40, is %d", len(bz))
}
var contractAddr [32]byte
@ -366,42 +370,45 @@ func (r *BodyWormchainWasmAllowlistInstantiate) Deserialize(bz []byte) {
r.ContractAddr = contractAddr
r.CodeId = codeId
return nil
}
func (r BodyGatewayIbcComposabilityMwContract) Serialize() []byte {
func (r BodyGatewayIbcComposabilityMwContract) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
payload.Write(r.ContractAddr[:])
return serializeBridgeGovernanceVaa(GatewayModuleStr, ActionSetIbcComposabilityMwContract, ChainIDWormchain, payload.Bytes())
}
func (r *BodyGatewayIbcComposabilityMwContract) Deserialize(bz []byte) {
func (r *BodyGatewayIbcComposabilityMwContract) Deserialize(bz []byte) error {
if len(bz) != 32 {
panic("incorrect payload length")
return fmt.Errorf("incorrect payload length, should be 32, is %d", len(bz))
}
var contractAddr [32]byte
copy(contractAddr[:], bz[0:32])
r.ContractAddr = contractAddr
return nil
}
func (r BodyGatewayScheduleUpgrade) Serialize() []byte {
func (r BodyGatewayScheduleUpgrade) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
payload.Write([]byte(r.Name))
MustWrite(payload, binary.BigEndian, r.Height)
return serializeBridgeGovernanceVaa(GatewayModuleStr, ActionScheduleUpgrade, ChainIDWormchain, payload.Bytes())
}
func (r *BodyGatewayScheduleUpgrade) Deserialize(bz []byte) {
func (r *BodyGatewayScheduleUpgrade) Deserialize(bz []byte) error {
r.Name = string(bz[0 : len(bz)-8])
r.Height = binary.BigEndian.Uint64(bz[len(bz)-8:])
return nil
}
func (r BodyCircleIntegrationUpdateWormholeFinality) Serialize() []byte {
func (r BodyCircleIntegrationUpdateWormholeFinality) Serialize() ([]byte, error) {
return serializeBridgeGovernanceVaa(CircleIntegrationModuleStr, CircleIntegrationActionUpdateWormholeFinality, r.TargetChainID, []byte{r.Finality})
}
func (r BodyCircleIntegrationRegisterEmitterAndDomain) Serialize() []byte {
func (r BodyCircleIntegrationRegisterEmitterAndDomain) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
MustWrite(payload, binary.BigEndian, r.ForeignEmitterChainId)
payload.Write(r.ForeignEmitterAddress[:])
@ -409,15 +416,15 @@ func (r BodyCircleIntegrationRegisterEmitterAndDomain) Serialize() []byte {
return serializeBridgeGovernanceVaa(CircleIntegrationModuleStr, CircleIntegrationActionRegisterEmitterAndDomain, r.TargetChainID, payload.Bytes())
}
func (r BodyCircleIntegrationUpgradeContractImplementation) Serialize() []byte {
func (r BodyCircleIntegrationUpgradeContractImplementation) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
payload.Write(r.NewImplementationAddress[:])
return serializeBridgeGovernanceVaa(CircleIntegrationModuleStr, CircleIntegrationActionUpgradeContractImplementation, r.TargetChainID, payload.Bytes())
}
func (r BodyIbcUpdateChannelChain) Serialize(module string) []byte {
func (r BodyIbcUpdateChannelChain) Serialize(module string) ([]byte, error) {
if module != IbcReceiverModuleStr && module != IbcTranslatorModuleStr {
panic("module for BodyIbcUpdateChannelChain must be either IbcReceiver or IbcTranslator")
return nil, errors.New("module for BodyIbcUpdateChannelChain must be either IbcReceiver or IbcTranslator")
}
payload := &bytes.Buffer{}
@ -426,7 +433,7 @@ func (r BodyIbcUpdateChannelChain) Serialize(module string) []byte {
return serializeBridgeGovernanceVaa(module, IbcReceiverActionUpdateChannelChain, r.TargetChainId, payload.Bytes())
}
func (r BodyWormholeRelayerSetDefaultDeliveryProvider) Serialize() []byte {
func (r BodyWormholeRelayerSetDefaultDeliveryProvider) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
payload.Write(r.NewDefaultDeliveryProviderAddress[:])
return serializeBridgeGovernanceVaa(WormholeRelayerModuleStr, WormholeRelayerSetDefaultDeliveryProvider, r.ChainID, payload.Bytes())
@ -443,10 +450,10 @@ func (r BodyGeneralPurposeGovernanceEvm) Serialize() ([]byte, error) {
}
MustWrite(payload, binary.BigEndian, uint16(len(r.Payload)))
payload.Write(r.Payload)
return serializeBridgeGovernanceVaa(GeneralPurposeGovernanceModuleStr, GeneralPurposeGovernanceEvmAction, r.ChainID, payload.Bytes()), nil
return serializeBridgeGovernanceVaa(GeneralPurposeGovernanceModuleStr, GeneralPurposeGovernanceEvmAction, r.ChainID, payload.Bytes())
}
func (r BodyGeneralPurposeGovernanceSolana) Serialize() []byte {
func (r BodyGeneralPurposeGovernanceSolana) Serialize() ([]byte, error) {
payload := &bytes.Buffer{}
payload.Write(r.GovernanceContract[:])
// NOTE: unlike in EVM, we don't write the payload length here, because we're using
@ -457,12 +464,15 @@ func (r BodyGeneralPurposeGovernanceSolana) Serialize() []byte {
return serializeBridgeGovernanceVaa(GeneralPurposeGovernanceModuleStr, GeneralPurposeGovernanceSolanaAction, r.ChainID, payload.Bytes())
}
func EmptyPayloadVaa(module string, actionId GovernanceAction, chainId ChainID) []byte {
func EmptyPayloadVaa(module string, actionId GovernanceAction, chainId ChainID) ([]byte, error) {
return serializeBridgeGovernanceVaa(module, actionId, chainId, []byte{})
}
func serializeBridgeGovernanceVaa(module string, actionId GovernanceAction, chainId ChainID, payload []byte) []byte {
buf := LeftPadBytes(module, 32)
func serializeBridgeGovernanceVaa(module string, actionId GovernanceAction, chainId ChainID, payload []byte) ([]byte, error) {
buf, err := LeftPadBytes(module, 32)
if err != nil {
return nil, fmt.Errorf("failed to left pad module: %w", err)
}
// Write action ID
MustWrite(buf, binary.BigEndian, actionId)
// Write target chain
@ -470,24 +480,27 @@ func serializeBridgeGovernanceVaa(module string, actionId GovernanceAction, chai
// Write emitter address of chain to be registered
buf.Write(payload[:])
return buf.Bytes()
return buf.Bytes(), nil
}
func LeftPadIbcChannelId(channelId string) [64]byte {
channelIdBuf := LeftPadBytes(channelId, 64)
func LeftPadIbcChannelId(channelId string) ([64]byte, error) {
channelIdBuf, err := LeftPadBytes(channelId, 64)
if err != nil {
return [64]byte{}, fmt.Errorf("failed to left pad module: %w", err)
}
var channelIdIdLeftPadded [64]byte
copy(channelIdIdLeftPadded[:], channelIdBuf.Bytes())
return channelIdIdLeftPadded
return channelIdIdLeftPadded, nil
}
// Prepends 0x00 bytes to the payload buffer, up to a size of `length`
func LeftPadBytes(payload string, length int) *bytes.Buffer {
func LeftPadBytes(payload string, length int) (*bytes.Buffer, error) {
if length < 0 {
panic("cannot prepend bytes to a negative length buffer")
return nil, errors.New("cannot prepend bytes to a negative length buffer")
}
if len(payload) > length {
panic(fmt.Sprintf("payload longer than %d bytes", length))
return nil, fmt.Errorf(fmt.Sprintf("payload longer than %d bytes", length))
}
buf := &bytes.Buffer{}
@ -500,5 +513,5 @@ func LeftPadBytes(payload string, length int) *bytes.Buffer {
// add the payload slice
buf.Write([]byte(payload))
return buf
return buf, nil
}

View File

@ -3,11 +3,14 @@ package vaa
import (
"bytes"
"encoding/hex"
"errors"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/holiman/uint256"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var addr = Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}
@ -53,7 +56,8 @@ func TestBodyTokenBridgeUpgradeContract(t *testing.T) {
func TestBodyContractUpgradeSerialize(t *testing.T) {
bodyContractUpgrade := BodyContractUpgrade{ChainID: 1, NewContract: addr}
expected := "00000000000000000000000000000000000000000000000000000000436f72650100010000000000000000000000000000000000000000000000000000000000000004"
serializedBodyContractUpgrade := bodyContractUpgrade.Serialize()
serializedBodyContractUpgrade, err := bodyContractUpgrade.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(serializedBodyContractUpgrade))
}
@ -64,7 +68,8 @@ func TestBodyGuardianSetUpdateSerialize(t *testing.T) {
}
bodyGuardianSetUpdate := BodyGuardianSetUpdate{Keys: keys, NewIndex: uint32(1)}
expected := "00000000000000000000000000000000000000000000000000000000436f726502000000000001025aaeb6053f3e94c9b9a09f33669435e7ef1beaed5aaeb6053f3e94c9b9a09f33669435e7ef1beaee"
serializedBodyGuardianSetUpdate := bodyGuardianSetUpdate.Serialize()
serializedBodyGuardianSetUpdate, err := bodyGuardianSetUpdate.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(serializedBodyGuardianSetUpdate))
}
@ -74,27 +79,30 @@ func TestBodyTokenBridgeRegisterChainSerialize(t *testing.T) {
name string
expected string
object BodyTokenBridgeRegisterChain
panic bool
err error
}{
{
name: "working_as_expected",
panic: false,
err: nil,
object: BodyTokenBridgeRegisterChain{Module: module, ChainID: 1, EmitterAddress: addr},
expected: "000000000000000000000000000000000000000000000000000000007465737401000000010000000000000000000000000000000000000000000000000000000000000004",
},
{
name: "panic_at_the_disco!",
panic: true,
err: errors.New("payload longer than 32 bytes"),
object: BodyTokenBridgeRegisterChain{Module: "123456789012345678901234567890123", ChainID: 1, EmitterAddress: addr},
expected: "payload longer than 32 bytes",
},
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
if testCase.panic {
assert.PanicsWithValue(t, testCase.expected, func() { testCase.object.Serialize() })
buf, err := testCase.object.Serialize()
if testCase.err != nil {
require.ErrorContains(t, err, testCase.err.Error())
assert.Nil(t, buf)
} else {
assert.Equal(t, testCase.expected, hex.EncodeToString(testCase.object.Serialize()))
require.NoError(t, err)
assert.Equal(t, testCase.expected, hex.EncodeToString(buf))
}
})
}
@ -104,32 +112,80 @@ func TestBodyTokenBridgeUpgradeContractSerialize(t *testing.T) {
module := "test"
bodyTokenBridgeUpgradeContract := BodyTokenBridgeUpgradeContract{Module: module, TargetChainID: 1, NewContract: addr}
expected := "00000000000000000000000000000000000000000000000000000000746573740200010000000000000000000000000000000000000000000000000000000000000004"
serializedBodyTokenBridgeUpgradeContract := bodyTokenBridgeUpgradeContract.Serialize()
serializedBodyTokenBridgeUpgradeContract, err := bodyTokenBridgeUpgradeContract.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(serializedBodyTokenBridgeUpgradeContract))
}
func TestBodyWormchainStoreCodeSerialize(t *testing.T) {
expected := "0000000000000000000000000000000000000000005761736d644d6f64756c65010c200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
bodyWormchainStoreCode := BodyWormchainStoreCode{WasmHash: dummyBytes}
assert.Equal(t, expected, hex.EncodeToString(bodyWormchainStoreCode.Serialize()))
buf, err := bodyWormchainStoreCode.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyWormchainInstantiateContractSerialize(t *testing.T) {
actual := BodyWormchainInstantiateContract{InstantiationParamsHash: dummyBytes}
expected := "0000000000000000000000000000000000000000005761736d644d6f64756c65020c200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
assert.Equal(t, expected, hex.EncodeToString(actual.Serialize()))
buf, err := actual.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyWormchainMigrateContractSerialize(t *testing.T) {
actual := BodyWormchainMigrateContract{MigrationParamsHash: dummyBytes}
expected := "0000000000000000000000000000000000000000005761736d644d6f64756c65030c200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
assert.Equal(t, expected, hex.EncodeToString(actual.Serialize()))
buf, err := actual.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyWormchainWasmAllowlistInstantiateSerialize(t *testing.T) {
actual := BodyWormchainWasmAllowlistInstantiate{ContractAddr: dummyBytes, CodeId: uint64(42)}
expected := "0000000000000000000000000000000000000000005761736d644d6f64756c65040c200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20000000000000002a"
buf, err := actual.Serialize(ActionAddWasmInstantiateAllowlist)
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
const BodyWormchainWasmAllowlistInstantiateBuf = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20000000000000002a"
func TestBodyWormchainWasmAllowlistInstantiateDeserialize(t *testing.T) {
expected := BodyWormchainWasmAllowlistInstantiate{ContractAddr: dummyBytes, CodeId: uint64(42)}
buf, err := hex.DecodeString(BodyWormchainWasmAllowlistInstantiateBuf)
require.NoError(t, err)
var actual BodyWormchainWasmAllowlistInstantiate
err = actual.Deserialize(buf)
require.NoError(t, err)
assert.True(t, reflect.DeepEqual(expected, actual))
}
func TestBodyWormchainWasmAllowlistInstantiateDeserializeFailureTooShort(t *testing.T) {
buf, err := hex.DecodeString(BodyWormchainWasmAllowlistInstantiateBuf[0 : len(BodyWormchainWasmAllowlistInstantiateBuf)-2])
require.NoError(t, err)
var actual BodyWormchainWasmAllowlistInstantiate
err = actual.Deserialize(buf)
require.ErrorContains(t, err, "incorrect payload length, should be 40, is 39")
}
func TestBodyWormchainWasmAllowlistInstantiateDeserializeFailureTooLong(t *testing.T) {
buf, err := hex.DecodeString(BodyWormchainWasmAllowlistInstantiateBuf + "00")
require.NoError(t, err)
var actual BodyWormchainWasmAllowlistInstantiate
err = actual.Deserialize(buf)
require.ErrorContains(t, err, "incorrect payload length, should be 40, is 41")
}
func TestBodyCircleIntegrationUpdateWormholeFinalitySerialize(t *testing.T) {
expected := "000000000000000000000000000000436972636c65496e746567726174696f6e0100022a"
bodyCircleIntegrationUpdateWormholeFinality := BodyCircleIntegrationUpdateWormholeFinality{TargetChainID: ChainIDEthereum, Finality: 42}
assert.Equal(t, expected, hex.EncodeToString(bodyCircleIntegrationUpdateWormholeFinality.Serialize()))
buf, err := bodyCircleIntegrationUpdateWormholeFinality.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyCircleIntegrationRegisterEmitterAndDomainSerialize(t *testing.T) {
@ -140,7 +196,9 @@ func TestBodyCircleIntegrationRegisterEmitterAndDomainSerialize(t *testing.T) {
ForeignEmitterAddress: addr,
CircleDomain: 42,
}
assert.Equal(t, expected, hex.EncodeToString(bodyCircleIntegrationRegisterEmitterAndDomain.Serialize()))
buf, err := bodyCircleIntegrationRegisterEmitterAndDomain.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyCircleIntegrationUpgradeContractImplementationSerialize(t *testing.T) {
@ -149,25 +207,58 @@ func TestBodyCircleIntegrationUpgradeContractImplementationSerialize(t *testing.
TargetChainID: ChainIDEthereum,
NewImplementationAddress: addr,
}
assert.Equal(t, expected, hex.EncodeToString(bodyCircleIntegrationUpgradeContractImplementation.Serialize()))
buf, err := bodyCircleIntegrationUpgradeContractImplementation.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyIbcReceiverUpdateChannelChain(t *testing.T) {
expected := "0000000000000000000000000000000000000000004962635265636569766572010c20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006368616e6e656c2d300013"
channelId := LeftPadIbcChannelId("channel-0")
channelId, err := LeftPadIbcChannelId("channel-0")
require.NoError(t, err)
bodyIbcReceiverUpdateChannelChain := BodyIbcUpdateChannelChain{
TargetChainId: ChainIDWormchain,
ChannelId: channelId,
ChainId: ChainIDInjective,
}
assert.Equal(t, expected, hex.EncodeToString(bodyIbcReceiverUpdateChannelChain.Serialize(IbcReceiverModuleStr)))
buf, err := bodyIbcReceiverUpdateChannelChain.Serialize(IbcReceiverModuleStr)
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyIbcReceiverUpdateChannelChainBadModuleName(t *testing.T) {
channelId, err := LeftPadIbcChannelId("channel-0")
require.NoError(t, err)
bodyIbcReceiverUpdateChannelChain := BodyIbcUpdateChannelChain{
TargetChainId: ChainIDWormchain,
ChannelId: channelId,
ChainId: ChainIDInjective,
}
buf, err := bodyIbcReceiverUpdateChannelChain.Serialize(IbcReceiverModuleStr + "ExtraJunk")
require.ErrorContains(t, err, "module for BodyIbcUpdateChannelChain must be either IbcReceiver or IbcTranslator")
assert.Nil(t, buf)
}
func TestLeftPadIbcChannelId(t *testing.T) {
channelId, err := LeftPadIbcChannelId("channel-0")
require.NoError(t, err)
assert.Equal(t, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006368616e6e656c2d30", hex.EncodeToString(channelId[:]))
}
func TestLeftPadIbcChannelIdFailureTooLong(t *testing.T) {
channelId, err := LeftPadIbcChannelId("channel-ThatIsTooLong!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
require.ErrorContains(t, err, "failed to left pad module: payload longer than 64 bytes")
expected := [64]byte{}
assert.True(t, bytes.Equal(expected[:], channelId[:]))
}
func TestLeftPadBytes(t *testing.T) {
payload := "AAAA"
paddedPayload := LeftPadBytes(payload, int(8))
paddedPayload, err := LeftPadBytes(payload, int(8))
require.NoError(t, err)
buf := &bytes.Buffer{}
buf.WriteByte(0x00)
@ -179,6 +270,24 @@ func TestLeftPadBytes(t *testing.T) {
assert.Equal(t, paddedPayload, buf)
}
func TestLeftPadBytesFailures(t *testing.T) {
payload := "AAAA"
paddedPayload, err := LeftPadBytes(payload, int(-2))
require.ErrorContains(t, err, "cannot prepend bytes to a negative length buffer")
assert.Nil(t, paddedPayload)
paddedPayload, err = LeftPadBytes(payload, int(2))
require.ErrorContains(t, err, "payload longer than 2 bytes")
assert.Nil(t, paddedPayload)
}
func TestSerializeBridgeGovernanceVaaModuleTooLong(t *testing.T) {
buf, err := serializeBridgeGovernanceVaa("ModuleNameIsMoreThanThirtyTwoCharacters", ActionRegisterChain, 1, []byte{0, 1, 2})
require.ErrorContains(t, err, "failed to left pad module: payload longer than 32 bytes")
assert.Nil(t, buf)
}
func FuzzLeftPadBytes(f *testing.F) {
// Add examples to our fuzz corpus
f.Add("FOO", 8)
@ -195,7 +304,8 @@ func FuzzLeftPadBytes(f *testing.F) {
t.Skip()
}
paddedPayload := LeftPadBytes(payload, length)
paddedPayload, err := LeftPadBytes(payload, length)
require.NoError(t, err)
// paddedPayload must always be equal to length
assert.Equal(t, paddedPayload.Len(), length)
@ -208,7 +318,9 @@ func TestBodyWormholeRelayerSetDefaultDeliveryProviderSerialize(t *testing.T) {
ChainID: 4,
NewDefaultDeliveryProviderAddress: addr,
}
assert.Equal(t, expected, hex.EncodeToString(bodyWormholeRelayerSetDefaultDeliveryProvider.Serialize()))
buf, err := bodyWormholeRelayerSetDefaultDeliveryProvider.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyGatewayIbcComposabilityMwContractSerialize(t *testing.T) {
@ -216,18 +328,41 @@ func TestBodyGatewayIbcComposabilityMwContractSerialize(t *testing.T) {
bodyGatewayIbcComposabilityMwContract := BodyGatewayIbcComposabilityMwContract{
ContractAddr: dummyBytes,
}
assert.Equal(t, expected, hex.EncodeToString(bodyGatewayIbcComposabilityMwContract.Serialize()))
buf, err := bodyGatewayIbcComposabilityMwContract.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
const BodyGatewayIbcComposabilityMwContractBuf = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
func TestBodyGatewayIbcComposabilityMwContractDeserialize(t *testing.T) {
expected := BodyGatewayIbcComposabilityMwContract{
ContractAddr: dummyBytes,
}
var payloadBody BodyGatewayIbcComposabilityMwContract
payloadBody.Deserialize(dummyBytes[:])
err := payloadBody.Deserialize(dummyBytes[:])
require.NoError(t, err)
assert.Equal(t, expected, payloadBody)
}
func TestBodyGatewayIbcComposabilityMwContractDeserializeFailureTooShort(t *testing.T) {
buf, err := hex.DecodeString(BodyGatewayIbcComposabilityMwContractBuf[0 : len(BodyGatewayIbcComposabilityMwContractBuf)-2])
require.NoError(t, err)
var actual BodyGatewayIbcComposabilityMwContract
err = actual.Deserialize(buf)
require.ErrorContains(t, err, "incorrect payload length, should be 32, is 31")
}
func TestBodyGatewayIbcComposabilityMwContractDeserializeFailureTooLong(t *testing.T) {
buf, err := hex.DecodeString(BodyGatewayIbcComposabilityMwContractBuf + "00")
require.NoError(t, err)
var actual BodyGatewayIbcComposabilityMwContract
err = actual.Deserialize(buf)
require.ErrorContains(t, err, "incorrect payload length, should be 32, is 33")
}
func TestBodyCoreRecoverChainIdSerialize(t *testing.T) {
expected := "00000000000000000000000000000000000000000000000000000000436f72650500000000000000000000000000000000000000000000000000000000000000010fa0"
BodyRecoverChainId := BodyRecoverChainId{
@ -235,7 +370,9 @@ func TestBodyCoreRecoverChainIdSerialize(t *testing.T) {
EvmChainID: uint256.NewInt(1),
NewChainID: 4000,
}
assert.Equal(t, expected, hex.EncodeToString(BodyRecoverChainId.Serialize()))
buf, err := BodyRecoverChainId.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyTokenBridgeRecoverChainIdSerialize(t *testing.T) {
@ -245,5 +382,18 @@ func TestBodyTokenBridgeRecoverChainIdSerialize(t *testing.T) {
EvmChainID: uint256.NewInt(1),
NewChainID: 4000,
}
assert.Equal(t, expected, hex.EncodeToString(BodyRecoverChainId.Serialize()))
buf, err := BodyRecoverChainId.Serialize()
require.NoError(t, err)
assert.Equal(t, expected, hex.EncodeToString(buf))
}
func TestBodyRecoverChainIdModuleTooLong(t *testing.T) {
BodyRecoverChainId := BodyRecoverChainId{
Module: "ModuleNameIsMoreThanThirtyTwoCharacters",
EvmChainID: uint256.NewInt(1),
NewChainID: 4000,
}
buf, err := BodyRecoverChainId.Serialize()
require.ErrorContains(t, err, "failed to left pad module: payload longer than 32 bytes")
assert.Nil(t, buf)
}

View File

@ -91,7 +91,8 @@ func TestBodyRegisterChain_Serialize(t *testing.T) {
EmitterAddress: Address{1, 2, 3, 4},
}
data := msg.Serialize()
data, err := msg.Serialize()
require.NoError(t, err)
require.Equal(t, "000000000000000000000000000000000000000000000000000000000000000001000000080102030400000000000000000000000000000000000000000000000000000000", hex.EncodeToString(data))
}

View File

@ -501,7 +501,9 @@ func TestWasmdAccountantContractModify(t *testing.T) {
Reason: "test modify",
}
ts := time.Date(2012, 12, 12, 12, 12, 12, 12, time.UTC)
modify_vaa := vaa.CreateGovernanceVAA(ts, 1, 1, tb.set.Index, modify_msg.Serialize())
modify_buf, err := modify_msg.Serialize()
require.NoError(t, err)
modify_vaa := vaa.CreateGovernanceVAA(ts, 1, 1, tb.set.Index, modify_buf)
*modify_vaa = signVaa(*modify_vaa, tb.privateKeys)
vBz, err := modify_vaa.Marshal()
require.NoError(t, err)