mirror of https://github.com/certusone/wasmd.git
342 lines
12 KiB
Go
342 lines
12 KiB
Go
package e2e_test
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
wasmvm "github.com/CosmWasm/wasmvm/v3"
|
|
ibctesting "github.com/cosmos/ibc-go/v10/testing"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
errorsmod "cosmossdk.io/errors"
|
|
sdkmath "cosmossdk.io/math"
|
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
|
|
|
"github.com/CosmWasm/wasmd/tests/e2e"
|
|
wasmibctesting "github.com/CosmWasm/wasmd/tests/wasmibctesting"
|
|
"github.com/CosmWasm/wasmd/x/wasm/types"
|
|
)
|
|
|
|
func TestGrants(t *testing.T) {
|
|
// Given a contract by address A
|
|
// And a grant for address B by A created
|
|
// When B sends an execute with tokens from A
|
|
// Then the grant is executed as defined
|
|
// And
|
|
// - balance A reduced (on success)
|
|
// - balance B not touched
|
|
|
|
coord := wasmibctesting.NewCoordinator(t, 1)
|
|
chain := wasmibctesting.NewWasmTestChain(coord.GetChain(ibctesting.GetChainID(1)))
|
|
contractAddr := e2e.InstantiateReflectContract(t, chain)
|
|
require.NotEmpty(t, contractAddr)
|
|
|
|
granterAddr := chain.SenderAccount.GetAddress()
|
|
granteePrivKey := secp256k1.GenPrivKey()
|
|
granteeAddr := sdk.AccAddress(granteePrivKey.PubKey().Address().Bytes())
|
|
otherPrivKey := secp256k1.GenPrivKey()
|
|
otherAddr := sdk.AccAddress(otherPrivKey.PubKey().Address().Bytes())
|
|
|
|
chain.Fund(granteeAddr, sdkmath.NewInt(1_000_000))
|
|
chain.Fund(otherAddr, sdkmath.NewInt(1_000_000))
|
|
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
|
|
|
|
myAmount := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(2_000_000))
|
|
|
|
specs := map[string]struct {
|
|
limit types.ContractAuthzLimitX
|
|
filter types.ContractAuthzFilterX
|
|
transferAmount sdk.Coin
|
|
senderKey cryptotypes.PrivKey
|
|
expErr *errorsmod.Error
|
|
}{
|
|
"in limits and filter": {
|
|
limit: types.NewMaxFundsLimit(myAmount),
|
|
filter: types.NewAllowAllMessagesFilter(),
|
|
transferAmount: myAmount,
|
|
senderKey: granteePrivKey,
|
|
},
|
|
"exceed limits": {
|
|
limit: types.NewMaxFundsLimit(myAmount),
|
|
filter: types.NewAllowAllMessagesFilter(),
|
|
transferAmount: myAmount.Add(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.OneInt())),
|
|
senderKey: granteePrivKey,
|
|
expErr: sdkerrors.ErrUnauthorized,
|
|
},
|
|
"not match filter": {
|
|
limit: types.NewMaxFundsLimit(myAmount),
|
|
filter: types.NewAcceptedMessageKeysFilter("foo"),
|
|
transferAmount: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.OneInt()),
|
|
senderKey: granteePrivKey,
|
|
expErr: sdkerrors.ErrUnauthorized,
|
|
},
|
|
"non authorized sender address": { // sanity check - testing sdk
|
|
limit: types.NewMaxFundsLimit(myAmount),
|
|
filter: types.NewAllowAllMessagesFilter(),
|
|
senderKey: otherPrivKey,
|
|
transferAmount: myAmount,
|
|
expErr: authz.ErrNoAuthorizationFound,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
// setup grant
|
|
grant, err := types.NewContractGrant(contractAddr, spec.limit, spec.filter)
|
|
require.NoError(t, err)
|
|
authorization := types.NewContractExecutionAuthorization(*grant)
|
|
expiry := time.Now().Add(time.Hour)
|
|
grantMsg, err := authz.NewMsgGrant(granterAddr, granteeAddr, authorization, &expiry)
|
|
require.NoError(t, err)
|
|
_, err = chain.SendMsgs(grantMsg)
|
|
require.NoError(t, err)
|
|
|
|
granterStartBalance := chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount
|
|
|
|
// when
|
|
anyValidReflectMsg := []byte(fmt.Sprintf(`{"reflect_msg": {"msgs": [{"bank":{"burn":{"amount":[{"denom":%q, "amount": %q}]}}}]}}`, sdk.DefaultBondDenom, myAmount.Amount.String()))
|
|
execMsg := authz.NewMsgExec(spec.senderKey.PubKey().Address().Bytes(), []sdk.Msg{&types.MsgExecuteContract{
|
|
Sender: granterAddr.String(),
|
|
Contract: contractAddr.String(),
|
|
Msg: anyValidReflectMsg,
|
|
Funds: sdk.NewCoins(spec.transferAmount),
|
|
}})
|
|
_, gotErr := chain.SendNonDefaultSenderMsgs(spec.senderKey, &execMsg)
|
|
|
|
// then
|
|
if spec.expErr != nil {
|
|
require.ErrorContains(t, gotErr, fmt.Sprintf("%s/%d:", spec.expErr.Codespace(), spec.expErr.ABCICode()))
|
|
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
|
|
assert.Equal(t, granterStartBalance, chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount)
|
|
return
|
|
}
|
|
require.NoError(t, gotErr)
|
|
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
|
|
assert.Equal(t, granterStartBalance.Sub(spec.transferAmount.Amount), chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStoreCodeGrant(t *testing.T) {
|
|
reflectWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/reflect_1_1.wasm")
|
|
require.NoError(t, err)
|
|
|
|
reflectCodeChecksum, err := wasmvm.CreateChecksum(reflectWasmCode)
|
|
require.NoError(t, err)
|
|
|
|
coord := wasmibctesting.NewCoordinator(t, 1)
|
|
chain := wasmibctesting.NewWasmTestChain(coord.GetChain(ibctesting.GetChainID(1)))
|
|
|
|
granterAddr := chain.SenderAccount.GetAddress()
|
|
granteePrivKey := secp256k1.GenPrivKey()
|
|
granteeAddr := sdk.AccAddress(granteePrivKey.PubKey().Address().Bytes())
|
|
otherPrivKey := secp256k1.GenPrivKey()
|
|
otherAddr := sdk.AccAddress(otherPrivKey.PubKey().Address().Bytes())
|
|
|
|
chain.Fund(granteeAddr, sdkmath.NewInt(1_000_000))
|
|
chain.Fund(otherAddr, sdkmath.NewInt(1_000_000))
|
|
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
|
|
|
|
specs := map[string]struct {
|
|
codeHash []byte
|
|
instantiatePermission types.AccessConfig
|
|
senderKey cryptotypes.PrivKey
|
|
expErr *errorsmod.Error
|
|
}{
|
|
"any code hash": {
|
|
codeHash: []byte("*"),
|
|
instantiatePermission: types.AllowEverybody,
|
|
senderKey: granteePrivKey,
|
|
},
|
|
"match code hash and permission": {
|
|
codeHash: reflectCodeChecksum,
|
|
instantiatePermission: types.AllowEverybody,
|
|
senderKey: granteePrivKey,
|
|
},
|
|
"not match code hash": {
|
|
codeHash: []byte("any_valid_checksum"),
|
|
instantiatePermission: types.AllowEverybody,
|
|
senderKey: granteePrivKey,
|
|
expErr: sdkerrors.ErrUnauthorized,
|
|
},
|
|
"not match permission": {
|
|
codeHash: []byte("*"),
|
|
instantiatePermission: types.AllowNobody,
|
|
senderKey: granteePrivKey,
|
|
expErr: sdkerrors.ErrUnauthorized,
|
|
},
|
|
"non authorized sender address": {
|
|
codeHash: []byte("*"),
|
|
instantiatePermission: types.AllowEverybody,
|
|
senderKey: otherPrivKey,
|
|
expErr: authz.ErrNoAuthorizationFound,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
// setup grant
|
|
grant, err := types.NewCodeGrant(spec.codeHash, &spec.instantiatePermission) //nolint:gosec
|
|
require.NoError(t, err)
|
|
authorization := types.NewStoreCodeAuthorization(*grant)
|
|
expiry := time.Now().Add(time.Hour)
|
|
grantMsg, err := authz.NewMsgGrant(granterAddr, granteeAddr, authorization, &expiry)
|
|
require.NoError(t, err)
|
|
_, err = chain.SendMsgs(grantMsg)
|
|
require.NoError(t, err)
|
|
|
|
// when
|
|
execMsg := authz.NewMsgExec(spec.senderKey.PubKey().Address().Bytes(), []sdk.Msg{&types.MsgStoreCode{
|
|
Sender: granterAddr.String(),
|
|
WASMByteCode: reflectWasmCode,
|
|
InstantiatePermission: &types.AllowEverybody,
|
|
}})
|
|
_, gotErr := chain.SendNonDefaultSenderMsgs(spec.senderKey, &execMsg)
|
|
|
|
// then
|
|
if spec.expErr != nil {
|
|
assert.ErrorContains(t, gotErr, fmt.Sprintf("%s/%d:", spec.expErr.Codespace(), spec.expErr.ABCICode()))
|
|
return
|
|
}
|
|
require.NoError(t, gotErr)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGzipStoreCodeGrant(t *testing.T) {
|
|
hackatomWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/hackatom.wasm")
|
|
require.NoError(t, err)
|
|
|
|
hackatomGzipWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/hackatom.wasm.gzip")
|
|
require.NoError(t, err)
|
|
|
|
hackatomCodeChecksum, err := wasmvm.CreateChecksum(hackatomWasmCode)
|
|
require.NoError(t, err)
|
|
|
|
coord := wasmibctesting.NewCoordinator(t, 1)
|
|
chain := wasmibctesting.NewWasmTestChain(coord.GetChain(ibctesting.GetChainID(1)))
|
|
|
|
granterAddr := chain.SenderAccount.GetAddress()
|
|
granteePrivKey := secp256k1.GenPrivKey()
|
|
granteeAddr := sdk.AccAddress(granteePrivKey.PubKey().Address().Bytes())
|
|
otherPrivKey := secp256k1.GenPrivKey()
|
|
otherAddr := sdk.AccAddress(otherPrivKey.PubKey().Address().Bytes())
|
|
|
|
chain.Fund(granteeAddr, sdkmath.NewInt(1_000_000))
|
|
chain.Fund(otherAddr, sdkmath.NewInt(1_000_000))
|
|
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
|
|
|
|
specs := map[string]struct {
|
|
codeHash []byte
|
|
instantiatePermission types.AccessConfig
|
|
senderKey cryptotypes.PrivKey
|
|
expErr *errorsmod.Error
|
|
}{
|
|
"any code hash": {
|
|
codeHash: []byte("*"),
|
|
instantiatePermission: types.AllowEverybody,
|
|
senderKey: granteePrivKey,
|
|
},
|
|
"match code hash and permission": {
|
|
codeHash: hackatomCodeChecksum,
|
|
instantiatePermission: types.AllowEverybody,
|
|
senderKey: granteePrivKey,
|
|
},
|
|
"not match code hash": {
|
|
codeHash: []byte("any_valid_checksum"),
|
|
instantiatePermission: types.AllowEverybody,
|
|
senderKey: granteePrivKey,
|
|
expErr: sdkerrors.ErrUnauthorized,
|
|
},
|
|
"not match permission": {
|
|
codeHash: []byte("*"),
|
|
instantiatePermission: types.AllowNobody,
|
|
senderKey: granteePrivKey,
|
|
expErr: sdkerrors.ErrUnauthorized,
|
|
},
|
|
"non authorized sender address": {
|
|
codeHash: []byte("*"),
|
|
instantiatePermission: types.AllowEverybody,
|
|
senderKey: otherPrivKey,
|
|
expErr: authz.ErrNoAuthorizationFound,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
// setup grant
|
|
grant, err := types.NewCodeGrant(spec.codeHash, &spec.instantiatePermission) //nolint:gosec
|
|
require.NoError(t, err)
|
|
authorization := types.NewStoreCodeAuthorization(*grant)
|
|
expiry := time.Now().Add(time.Hour)
|
|
grantMsg, err := authz.NewMsgGrant(granterAddr, granteeAddr, authorization, &expiry)
|
|
require.NoError(t, err)
|
|
_, err = chain.SendMsgs(grantMsg)
|
|
require.NoError(t, err)
|
|
|
|
// when
|
|
execMsg := authz.NewMsgExec(spec.senderKey.PubKey().Address().Bytes(), []sdk.Msg{&types.MsgStoreCode{
|
|
Sender: granterAddr.String(),
|
|
WASMByteCode: hackatomGzipWasmCode,
|
|
InstantiatePermission: &types.AllowEverybody,
|
|
}})
|
|
_, gotErr := chain.SendNonDefaultSenderMsgs(spec.senderKey, &execMsg)
|
|
|
|
// then
|
|
if spec.expErr != nil {
|
|
assert.ErrorContains(t, gotErr, fmt.Sprintf("%s/%d:", spec.expErr.Codespace(), spec.expErr.ABCICode()))
|
|
return
|
|
}
|
|
require.NoError(t, gotErr)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBrokenGzipStoreCodeGrant(t *testing.T) {
|
|
brokenGzipWasmCode, err := os.ReadFile("../../x/wasm/keeper/testdata/broken_crc.gzip")
|
|
require.NoError(t, err)
|
|
|
|
coord := wasmibctesting.NewCoordinator(t, 1)
|
|
chain := wasmibctesting.NewWasmTestChain(coord.GetChain(ibctesting.GetChainID(1)))
|
|
|
|
granterAddr := chain.SenderAccount.GetAddress()
|
|
granteePrivKey := secp256k1.GenPrivKey()
|
|
granteeAddr := sdk.AccAddress(granteePrivKey.PubKey().Address().Bytes())
|
|
otherPrivKey := secp256k1.GenPrivKey()
|
|
otherAddr := sdk.AccAddress(otherPrivKey.PubKey().Address().Bytes())
|
|
|
|
chain.Fund(granteeAddr, sdkmath.NewInt(1_000_000))
|
|
chain.Fund(otherAddr, sdkmath.NewInt(1_000_000))
|
|
assert.Equal(t, sdkmath.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
|
|
|
|
codeHash := []byte("*")
|
|
instantiatePermission := types.AllowEverybody
|
|
senderKey := granteePrivKey
|
|
|
|
// setup grant
|
|
grant, err := types.NewCodeGrant(codeHash, &instantiatePermission)
|
|
require.NoError(t, err)
|
|
authorization := types.NewStoreCodeAuthorization(*grant)
|
|
expiry := time.Now().Add(time.Hour)
|
|
grantMsg, err := authz.NewMsgGrant(granterAddr, granteeAddr, authorization, &expiry)
|
|
require.NoError(t, err)
|
|
_, err = chain.SendMsgs(grantMsg)
|
|
require.NoError(t, err)
|
|
|
|
// when
|
|
execMsg := authz.NewMsgExec(senderKey.PubKey().Address().Bytes(), []sdk.Msg{&types.MsgStoreCode{
|
|
Sender: granterAddr.String(),
|
|
WASMByteCode: brokenGzipWasmCode,
|
|
InstantiatePermission: &types.AllowEverybody,
|
|
}})
|
|
_, gotErr := chain.SendNonDefaultSenderMsgs(senderKey, &execMsg)
|
|
|
|
// then
|
|
require.Error(t, gotErr)
|
|
}
|