Skip to content

Commit

Permalink
Add implementation + some e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
pinosu committed Sep 1, 2023
1 parent f3d8249 commit 1adbe8d
Show file tree
Hide file tree
Showing 4 changed files with 322 additions and 10 deletions.
100 changes: 100 additions & 0 deletions tests/e2e/grants_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package e2e_test

import (
"fmt"
"os"
"testing"
"time"

Expand All @@ -10,6 +11,7 @@ import (

errorsmod "cosmossdk.io/errors"

wasmvm "github.com/CosmWasm/wasmvm"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -119,3 +121,101 @@ func TestGrants(t *testing.T) {
})
}
}

func TestStoreCodeGrant(t *testing.T) {
// Given a grant for address B by A created
// When B uploads code from A
// Then the grant is executed as defined
// And
// - balance A reduced (on success)
// - balance B not touched

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 := ibctesting.NewCoordinator(t, 1)
chain := 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, sdk.NewInt(1_000_000))
chain.Fund(otherAddr, sdk.NewInt(1_000_000))
assert.Equal(t, sdk.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("ABC"),
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)
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)

granterStartBalance := chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount

// 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 {
require.True(t, spec.expErr.Is(gotErr))
assert.Equal(t, sdk.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, sdk.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount)
//assert.True(t, granterStartBalance.GT(chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount))
})
}
}
40 changes: 34 additions & 6 deletions x/wasm/types/authz.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package types

import (
"bytes"
"strings"

"github.com/cosmos/gogoproto/proto"

errorsmod "cosmossdk.io/errors"

wasmvm "github.com/CosmWasm/wasmvm"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
Expand Down Expand Up @@ -35,14 +37,29 @@ func (a StoreCodeAuthorization) MsgTypeURL() string {
return sdk.MsgTypeURL(&MsgStoreCode{})
}

// NewAuthz factory method to create an Authorization with updated grants
func (a StoreCodeAuthorization) NewAuthz(g []CodeGrant) authztypes.Authorization {
return NewStoreCodeAuthorization(g...)
}

// Accept implements Authorization.Accept.
func (a *StoreCodeAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authztypes.AcceptResponse, error) {
panic("implement")
var code []byte
var permission AccessConfig
switch msg := msg.(type) {
case *MsgStoreCode:
code = msg.WASMByteCode
permission = *msg.InstantiatePermission
default:
return authztypes.AcceptResponse{}, sdkerrors.ErrInvalidRequest.Wrap("unknown msg type")
}

checksum, err := wasmvm.CreateChecksum(code)
if err != nil {
return authztypes.AcceptResponse{}, sdkerrors.ErrInvalidRequest.Wrap("checksum")
}

for _, grant := range a.Grants {
if grant.Accept(checksum, permission) {
return authztypes.AcceptResponse{Accept: true}, nil
}
}
return authztypes.AcceptResponse{Accept: false}, nil
}

// ValidateBasic implements Authorization.ValidateBasic.
Expand All @@ -68,6 +85,9 @@ func NewCodeGrant(codeHash []byte, instantiatePermission AccessConfig) (*CodeGra

// ValidateBasic validates the grant
func (g CodeGrant) ValidateBasic() error {
if len(g.CodeHash) == 0 {
return ErrEmpty.Wrap("code hash")
}
if g.InstantiatePermission != nil {
if err := g.InstantiatePermission.ValidateBasic(); err != nil {
return errorsmod.Wrap(err, "instantiate permission")
Expand All @@ -76,6 +96,14 @@ func (g CodeGrant) ValidateBasic() error {
return nil
}

// Accept checks if checksum and permission match the grant
func (g CodeGrant) Accept(checksum []byte, permission AccessConfig) bool {
if !bytes.Equal(g.CodeHash, []byte("*")) && !bytes.Equal(g.CodeHash, checksum) {
return false
}
return permission.IsSubset(*g.InstantiatePermission)
}

// AuthzableWasmMsg is abstract wasm tx message that is supported in authz
type AuthzableWasmMsg interface {
GetFunds() sdk.Coins
Expand Down
Loading

0 comments on commit 1adbe8d

Please sign in to comment.