225 lines
7.4 KiB
Go
225 lines
7.4 KiB
Go
package keeper_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"testing"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/tendermint/crypto/sha3"
|
|
keepertest "github.com/wormhole-foundation/wormchain/testutil/keeper"
|
|
"github.com/wormhole-foundation/wormchain/x/wormhole/keeper"
|
|
"github.com/wormhole-foundation/wormchain/x/wormhole/types"
|
|
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
|
)
|
|
|
|
func createWasmStoreCodePayload(wasmBytes []byte) []byte {
|
|
// governance message with sha3 of wasmBytes as the payload
|
|
var hashWasm [32]byte
|
|
keccak := sha3.NewLegacyKeccak256()
|
|
keccak.Write(wasmBytes)
|
|
keccak.Sum(hashWasm[:0])
|
|
|
|
gov_msg := types.NewGovernanceMessage(keeper.WasmdModule, byte(keeper.ActionStoreCode), uint16(vaa.ChainIDWormchain), hashWasm[:])
|
|
return gov_msg.MarshalBinary()
|
|
}
|
|
|
|
func createWasmInstantiatePayload(code_id uint64, label string, json_msg string) []byte {
|
|
// governance message with sha3 of arguments to instantiate
|
|
// - code_id (big endian)
|
|
// - label
|
|
// - json_msg
|
|
expected_hash := vaa.CreateInstatiateCosmwasmContractHash(code_id, label, []byte(json_msg))
|
|
|
|
var payload bytes.Buffer
|
|
payload.Write(keeper.WasmdModule[:])
|
|
payload.Write([]byte{byte(keeper.ActionInstantiateContract)})
|
|
binary.Write(&payload, binary.BigEndian, uint16(vaa.ChainIDWormchain))
|
|
// custom payload
|
|
payload.Write(expected_hash[:])
|
|
return payload.Bytes()
|
|
}
|
|
|
|
func TestWasmdStoreCode(t *testing.T) {
|
|
k, ctx := keepertest.WormholeKeeper(t)
|
|
guardians, privateKeys := createNGuardianValidator(k, ctx, 10)
|
|
_ = privateKeys
|
|
k.SetConfig(ctx, types.Config{
|
|
GovernanceEmitter: vaa.GovernanceEmitter[:],
|
|
GovernanceChain: uint32(vaa.GovernanceChain),
|
|
ChainId: uint32(vaa.ChainIDWormchain),
|
|
GuardianSetExpiration: 86400,
|
|
})
|
|
signer_bz := [20]byte{}
|
|
signer := sdk.AccAddress(signer_bz[:])
|
|
|
|
set := createNewGuardianSet(k, ctx, guardians)
|
|
|
|
context := sdk.WrapSDKContext(ctx)
|
|
msgServer := keeper.NewMsgServerImpl(*k)
|
|
|
|
// create governance to store code
|
|
payload := createWasmStoreCodePayload(keepertest.EXAMPLE_WASM_CONTRACT_GZIP)
|
|
v := generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload)
|
|
vBz, err := v.Marshal()
|
|
assert.NoError(t, err)
|
|
|
|
// store code should work
|
|
res, err := msgServer.StoreCode(context, &types.MsgStoreCode{
|
|
Signer: signer.String(),
|
|
WASMByteCode: keepertest.EXAMPLE_WASM_CONTRACT_GZIP,
|
|
Vaa: vBz,
|
|
})
|
|
_ = res
|
|
assert.NoError(t, err)
|
|
|
|
// replay attack does not work.
|
|
_, err = msgServer.StoreCode(context, &types.MsgStoreCode{
|
|
Signer: signer.String(),
|
|
WASMByteCode: keepertest.EXAMPLE_WASM_CONTRACT_GZIP,
|
|
Vaa: vBz,
|
|
})
|
|
assert.ErrorIs(t, err, types.ErrVAAAlreadyExecuted)
|
|
|
|
// modified wasm byte code does not verify
|
|
bad_wasm := make([]byte, len(keepertest.EXAMPLE_WASM_CONTRACT_GZIP))
|
|
copy(bad_wasm, keepertest.EXAMPLE_WASM_CONTRACT_GZIP)
|
|
bad_wasm[100] = bad_wasm[100] ^ 0x40
|
|
// create vaa with the hash of the "valid" wasm
|
|
v = generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload)
|
|
vBz, _ = v.Marshal()
|
|
_, err = msgServer.StoreCode(context, &types.MsgStoreCode{
|
|
Signer: signer.String(),
|
|
WASMByteCode: bad_wasm,
|
|
Vaa: vBz,
|
|
})
|
|
assert.ErrorIs(t, err, types.ErrInvalidHash)
|
|
|
|
// Sending to wrong module is error
|
|
payload_wrong_module := createWasmStoreCodePayload(keepertest.EXAMPLE_WASM_CONTRACT_GZIP)
|
|
// tamper with the module id
|
|
payload_wrong_module[16] = 0xff
|
|
v = generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload_wrong_module)
|
|
vBz, _ = v.Marshal()
|
|
_, err = msgServer.StoreCode(context, &types.MsgStoreCode{
|
|
Signer: signer.String(),
|
|
WASMByteCode: bad_wasm,
|
|
Vaa: vBz,
|
|
})
|
|
assert.ErrorIs(t, err, types.ErrUnknownGovernanceModule)
|
|
}
|
|
|
|
func TestWasmdInstantiateContract(t *testing.T) {
|
|
k, ctx := keepertest.WormholeKeeper(t)
|
|
guardians, privateKeys := createNGuardianValidator(k, ctx, 10)
|
|
_ = privateKeys
|
|
k.SetConfig(ctx, types.Config{
|
|
GovernanceEmitter: vaa.GovernanceEmitter[:],
|
|
GovernanceChain: uint32(vaa.GovernanceChain),
|
|
ChainId: uint32(vaa.ChainIDWormchain),
|
|
GuardianSetExpiration: 86400,
|
|
})
|
|
signer_bz := [20]byte{}
|
|
signer := sdk.AccAddress(signer_bz[:])
|
|
|
|
set := createNewGuardianSet(k, ctx, guardians)
|
|
|
|
context := sdk.WrapSDKContext(ctx)
|
|
msgServer := keeper.NewMsgServerImpl(*k)
|
|
|
|
// First we need to upload code that we can instantiate.
|
|
payload := createWasmStoreCodePayload(keepertest.EXAMPLE_WASM_CONTRACT_GZIP)
|
|
v := generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload)
|
|
vBz, err := v.Marshal()
|
|
assert.NoError(t, err)
|
|
res, err := msgServer.StoreCode(context, &types.MsgStoreCode{
|
|
Signer: signer.String(),
|
|
WASMByteCode: keepertest.EXAMPLE_WASM_CONTRACT_GZIP,
|
|
Vaa: vBz,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
code_id := res.CodeID
|
|
|
|
// Now that we have a code_id, we can test instantiating it.
|
|
payload = createWasmInstantiatePayload(code_id, "btc", "{}")
|
|
v = generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload)
|
|
vBz, _ = v.Marshal()
|
|
_, err = msgServer.InstantiateContract(context, &types.MsgInstantiateContract{
|
|
Signer: signer.String(),
|
|
CodeID: code_id,
|
|
Label: "btc",
|
|
Msg: []byte("{}"),
|
|
Vaa: vBz,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Test instantiating with invalid json fails
|
|
payload = createWasmInstantiatePayload(code_id, "btc", "{")
|
|
v = generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload)
|
|
vBz, _ = v.Marshal()
|
|
_, err = msgServer.InstantiateContract(context, &types.MsgInstantiateContract{
|
|
Signer: signer.String(),
|
|
CodeID: code_id,
|
|
Label: "btc",
|
|
Msg: []byte("{"),
|
|
Vaa: vBz,
|
|
})
|
|
require.Error(t, err)
|
|
|
|
// Test that tampering with either code_id, label, or msg fails vaa check
|
|
payload = createWasmInstantiatePayload(code_id, "btc", "{}")
|
|
v = generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload)
|
|
vBz, _ = v.Marshal()
|
|
_, err = msgServer.InstantiateContract(context, &types.MsgInstantiateContract{
|
|
Signer: signer.String(),
|
|
CodeID: code_id + 1,
|
|
Label: "btc",
|
|
Msg: []byte("{}"),
|
|
Vaa: vBz,
|
|
})
|
|
// Bad code_id
|
|
assert.ErrorIs(t, err, types.ErrInvalidHash)
|
|
|
|
v = generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload)
|
|
vBz, _ = v.Marshal()
|
|
_, err = msgServer.InstantiateContract(context, &types.MsgInstantiateContract{
|
|
Signer: signer.String(),
|
|
CodeID: code_id,
|
|
Label: "btc_bad",
|
|
Msg: []byte("{}"),
|
|
Vaa: vBz,
|
|
})
|
|
// Bad label
|
|
assert.ErrorIs(t, err, types.ErrInvalidHash)
|
|
|
|
v = generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload)
|
|
vBz, _ = v.Marshal()
|
|
_, err = msgServer.InstantiateContract(context, &types.MsgInstantiateContract{
|
|
Signer: signer.String(),
|
|
CodeID: code_id,
|
|
Label: "btc",
|
|
Msg: []byte("{\"arg\":\"bad\"}"),
|
|
Vaa: vBz,
|
|
})
|
|
// Bad msg
|
|
assert.ErrorIs(t, err, types.ErrInvalidHash)
|
|
|
|
// Sending to wrong module is error
|
|
payload_wrong_module := createWasmInstantiatePayload(code_id, "btc", "{}")
|
|
// tamper with the module id
|
|
payload_wrong_module[16] = 0xff
|
|
v = generateVaa(set.Index, privateKeys, vaa.ChainID(vaa.GovernanceChain), payload_wrong_module)
|
|
vBz, _ = v.Marshal()
|
|
_, err = msgServer.InstantiateContract(context, &types.MsgInstantiateContract{
|
|
Signer: signer.String(),
|
|
CodeID: code_id,
|
|
Label: "btc",
|
|
Msg: []byte("{\"arg\":\"bad\"}"),
|
|
Vaa: vBz,
|
|
})
|
|
assert.ErrorIs(t, err, types.ErrUnknownGovernanceModule)
|
|
}
|