Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions aclmapping/dependency_generator.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
package aclmapping

import (
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper"
aclbankmapping "github.com/sei-protocol/sei-chain/aclmapping/bank"
acldexmapping "github.com/sei-protocol/sei-chain/aclmapping/dex"
aclwasmmapping "github.com/sei-protocol/sei-chain/aclmapping/wasm"
)

type CustomDependencyGenerator struct {
WasmKeeper wasmkeeper.Keeper
}
type CustomDependencyGenerator struct{}

func NewCustomDependencyGenerator(wasmKeeper wasmkeeper.Keeper) CustomDependencyGenerator {
return CustomDependencyGenerator{WasmKeeper: wasmKeeper}
func NewCustomDependencyGenerator() CustomDependencyGenerator {
return CustomDependencyGenerator{}
}

func (customDepGen CustomDependencyGenerator) GetCustomDependencyGenerators() aclkeeper.DependencyGeneratorMap {
dependencyGeneratorMap := make(aclkeeper.DependencyGeneratorMap)

dependencyGeneratorMap.Merge(acldexmapping.GetDexDependencyGenerators())
dependencyGeneratorMap.Merge(aclbankmapping.GetBankDepedencyGenerator())
wasmDependencyGenerators := aclwasmmapping.NewWasmDependencyGenerator(customDepGen.WasmKeeper)
wasmDependencyGenerators := aclwasmmapping.NewWasmDependencyGenerator()
dependencyGeneratorMap.Merge(wasmDependencyGenerators.GetWasmDependencyGenerators())

return dependencyGeneratorMap
Expand Down
35 changes: 4 additions & 31 deletions aclmapping/wasm/mappings.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package aclwasmmapping

import (
"encoding/json"
"fmt"

wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol"
Expand All @@ -18,14 +16,10 @@ var (
ErrWasmFunctionDependenciesDisabled = fmt.Errorf("wasm function dependency mapping disabled")
)

type WasmDependencyGenerator struct {
WasmKeeper wasmkeeper.Keeper
}
type WasmDependencyGenerator struct{}

func NewWasmDependencyGenerator(wasmKeeper wasmkeeper.Keeper) WasmDependencyGenerator {
return WasmDependencyGenerator{
WasmKeeper: wasmKeeper,
}
func NewWasmDependencyGenerator() WasmDependencyGenerator {
return WasmDependencyGenerator{}
}

func (wasmDepGen WasmDependencyGenerator) GetWasmDependencyGenerators() aclkeeper.DependencyGeneratorMap {
Expand All @@ -47,28 +41,7 @@ func (wasmDepGen WasmDependencyGenerator) WasmExecuteContractGenerator(keeper ac
if err != nil {
return []sdkacltypes.AccessOperation{}, err
}
contractInfo := wasmDepGen.WasmKeeper.GetContractInfo(ctx, contractAddr)
codeID := contractInfo.CodeID

jsonObj := make(map[string]interface{})
jsonErr := json.Unmarshal(executeContractMsg.Msg, &jsonObj)
var wasmFunction string
if jsonErr != nil {
// try unmarshalling to string for execute function with no params
jsonErr2 := json.Unmarshal(executeContractMsg.Msg, &wasmFunction)
if jsonErr2 != nil {
return []sdkacltypes.AccessOperation{}, ErrInvalidWasmFunction
}
} else {
if len(jsonObj) != 1 {
return []sdkacltypes.AccessOperation{}, ErrInvalidWasmFunction
}
for fieldName := range jsonObj {
// this should only run once based on the check above
wasmFunction = fieldName
}
}
wasmDependencyMapping, err := keeper.GetWasmFunctionDependencyMapping(ctx, codeID, wasmFunction)
wasmDependencyMapping, err := keeper.GetWasmDependencyMapping(ctx, contractAddr)
if err != nil {
return []sdkacltypes.AccessOperation{}, err
}
Expand Down
33 changes: 24 additions & 9 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,10 +499,33 @@ func New(
app.BankKeeper.(bankkeeper.BaseKeeper).WithMintCoinsRestriction(tokenfactorytypes.NewTokenFactoryDenomMintCoinsRestriction()),
app.DistrKeeper,
)
customDependencyGenerators := aclmapping.NewCustomDependencyGenerator()
aclOpts = append(aclOpts, aclkeeper.WithDependencyGeneratorMappings(customDependencyGenerators.GetCustomDependencyGenerators()))
app.AccessControlKeeper = aclkeeper.NewKeeper(
appCodec,
app.keys[acltypes.StoreKey],
app.GetSubspace(acltypes.ModuleName),
aclOpts...,
)
// The last arguments can contain custom message handlers, and custom query handlers,
// if we want to allow any custom callbacks
supportedFeatures := "iterator,staking,stargate,sei"
wasmOpts = append(wasmbinding.RegisterCustomPlugins(&app.OracleKeeper, &app.DexKeeper, &app.EpochKeeper), wasmOpts...)
wasmOpts = append(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come we need to register all plugins now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it b/c we any tx's may be dependent on any of the other modules?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because now we create the message handler itself, and we need the inputs to create the message handler as well

wasmbinding.RegisterCustomPlugins(
&app.OracleKeeper,
&app.DexKeeper,
&app.EpochKeeper,
&app.AccountKeeper,
app.MsgServiceRouter(),
app.IBCKeeper.ChannelKeeper,
scopedWasmKeeper,
app.BankKeeper,
appCodec,
app.TransferKeeper,
app.AccessControlKeeper,
),
wasmOpts...,
)
app.WasmKeeper = wasm.NewKeeper(
appCodec,
keys[wasm.StoreKey],
Expand All @@ -526,14 +549,6 @@ func New(
dexModule := dexmodule.NewAppModule(appCodec, app.DexKeeper, app.AccountKeeper, app.BankKeeper, app.WasmKeeper, app.tracingInfo)
epochModule := epochmodule.NewAppModule(appCodec, app.EpochKeeper, app.AccountKeeper, app.BankKeeper)

customDependencyGenerators := aclmapping.NewCustomDependencyGenerator(app.WasmKeeper)
aclOpts = append(aclOpts, aclkeeper.WithDependencyGeneratorMappings(customDependencyGenerators.GetCustomDependencyGenerators()))
app.AccessControlKeeper = aclkeeper.NewKeeper(
appCodec,
app.keys[acltypes.StoreKey],
app.GetSubspace(acltypes.ModuleName),
aclOpts...,
)
// register the proposal types
govRouter := govtypes.NewRouter()
govRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler).
Expand Down
8 changes: 1 addition & 7 deletions cmd/seid/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"path/filepath"

"github.com/CosmWasm/wasmd/x/wasm"
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
Expand All @@ -31,7 +30,6 @@ import (
"github.com/sei-protocol/sei-chain/app"
"github.com/sei-protocol/sei-chain/app/params"
"github.com/sei-protocol/sei-chain/utils/tracing"
"github.com/sei-protocol/sei-chain/wasmbinding"
"github.com/spf13/cast"
"github.com/spf13/cobra"
tmcli "github.com/tendermint/tendermint/libs/cli"
Expand Down Expand Up @@ -240,10 +238,6 @@ func newApp(
panic(err)
}

wasmopts := []wasm.Option{wasmkeeper.WithMessageEncoders(&wasmkeeper.MessageEncoders{
Custom: wasmbinding.CustomEncoder,
})}

return app.New(
logger,
db,
Expand All @@ -255,7 +249,7 @@ func newApp(
app.MakeEncodingConfig(),
wasm.EnableAllProposals,
appOpts,
wasmopts,
[]wasm.Option{},
[]aclkeeper.Option{},
baseapp.SetPruning(pruningOpts),
baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))),
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ require (
)

replace (
github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.1.114
github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.1.153
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
github.com/keybase/go-keychain => github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4
github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.1.59
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1097,8 +1097,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/securego/gosec/v2 v2.11.0/go.mod h1:SX8bptShuG8reGC0XS09+a4H2BoWSJi+fscA+Pulbpo=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/sei-protocol/sei-cosmos v0.1.114 h1:Cy5MnBdvql5VJw5pC104DsivQxPg0xkvVOuq6VwDiRk=
github.com/sei-protocol/sei-cosmos v0.1.114/go.mod h1:8ccWQxpBkWbpvBos/T4QO9K9gQxFs0duTqKRnagKo+0=
github.com/sei-protocol/sei-cosmos v0.1.153 h1:6jDUjEicctFtcwZ+NjiNSGe1owFRlLGcam5bR+PFT64=
github.com/sei-protocol/sei-cosmos v0.1.153/go.mod h1:8ccWQxpBkWbpvBos/T4QO9K9gQxFs0duTqKRnagKo+0=
github.com/sei-protocol/sei-tendermint v0.1.59 h1:POGL60PumMQHF4EzAHzvkGfDnodQJLHpl65LuiwSO/Y=
github.com/sei-protocol/sei-tendermint v0.1.59/go.mod h1:Olwbjyagrpoxj5DAUhHxMTWDVEfQ3FYdpypaJ3+6Hs8=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
Expand Down
157 changes: 157 additions & 0 deletions wasmbinding/message_plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package wasmbinding

import (
"fmt"

wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol"
aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper"
acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types"
)

var ErrUnexpectedWasmDependency = fmt.Errorf("unexpected wasm dependency detected")

// forked from wasm
func CustomMessageHandler(
router wasmkeeper.MessageRouter,
channelKeeper wasmtypes.ChannelKeeper,
capabilityKeeper wasmtypes.CapabilityKeeper,
bankKeeper wasmtypes.Burner,
unpacker codectypes.AnyUnpacker,
portSource wasmtypes.ICS20TransferPortSource,
aclKeeper aclkeeper.Keeper,
) wasmkeeper.Messenger {
encoders := wasmkeeper.DefaultEncoders(unpacker, portSource)
encoders = encoders.Merge(
&wasmkeeper.MessageEncoders{
Custom: CustomEncoder,
})
return wasmkeeper.NewMessageHandlerChain(
NewSDKMessageDependencyDecorator(wasmkeeper.NewSDKMessageHandler(router, encoders), aclKeeper, encoders),
wasmkeeper.NewIBCRawPacketHandler(channelKeeper, capabilityKeeper),
wasmkeeper.NewBurnCoinMessageHandler(bankKeeper),
)
}

// SDKMessageHandler can handles messages that can be encoded into sdk.Message types and routed.
type SDKMessageDependencyDecorator struct {
wrapped wasmkeeper.Messenger
aclKeeper aclkeeper.Keeper
encoders wasmkeeper.MessageEncoders
}

func NewSDKMessageDependencyDecorator(handler wasmkeeper.Messenger, aclKeeper aclkeeper.Keeper, encoders wasmkeeper.MessageEncoders) SDKMessageDependencyDecorator {
return SDKMessageDependencyDecorator{
wrapped: handler,
aclKeeper: aclKeeper,
encoders: encoders,
}
}

func BuildWasmDependencyLookupMap(accessOps []sdkacltypes.AccessOperation) map[acltypes.ResourceAccess]map[string]struct{} {
lookupMap := make(map[acltypes.ResourceAccess]map[string]struct{})
for _, accessOp := range accessOps {
resourceAccess := acltypes.ResourceAccess{
ResourceType: accessOp.ResourceType,
AccessType: accessOp.AccessType,
}
if _, ok := lookupMap[resourceAccess]; !ok {
// we haven't added any identifiers for this resource type, so lets initialize the nested map (set)
lookupMap[resourceAccess] = make(map[string]struct{})
}
lookupMap[resourceAccess][accessOp.IdentifierTemplate] = struct{}{}
}
return lookupMap
}

func GenerateAllowedResourceAccess(resource sdkacltypes.ResourceType, access sdkacltypes.AccessType) []acltypes.ResourceAccess {
// by default, write, and unknown are ok
accesses := []acltypes.ResourceAccess{
{
ResourceType: resource,
AccessType: sdkacltypes.AccessType_WRITE,
},
{
ResourceType: resource,
AccessType: sdkacltypes.AccessType_UNKNOWN,
},
}
if access == sdkacltypes.AccessType_READ {
accesses = append(accesses, acltypes.ResourceAccess{
ResourceType: resource,
AccessType: access,
})
}
return accesses
}

func AreDependenciesFulfilled(lookupMap map[acltypes.ResourceAccess]map[string]struct{}, accessOp sdkacltypes.AccessOperation) bool {
currResourceAccesses := GenerateAllowedResourceAccess(accessOp.ResourceType, accessOp.AccessType)
for _, currResourceAccess := range currResourceAccesses {
if identifierMap, ok := lookupMap[currResourceAccess]; ok {
if _, ok := identifierMap[accessOp.IdentifierTemplate]; ok {
// we found a proper listed dependency, we can go to the next access op
return true
}
}
}

// what about parent resources
parentResources := accessOp.ResourceType.GetParentResources()
// for each of the parent resources, we need at least one to be defined in the wasmDependencies
for _, parentResource := range parentResources {
// make parent resource access with same access type
parentResourceAccesses := GenerateAllowedResourceAccess(parentResource, accessOp.AccessType)
// for each of the parent resources, we check to see if its in the lookup map (identifier doesnt matter bc parent)
for _, parentResourceAccess := range parentResourceAccesses {
if _, parentResourcePresent := lookupMap[parentResourceAccess]; parentResourcePresent {
// we can continue to the next access op
return true
}
}
}
return false
}

func (decorator SDKMessageDependencyDecorator) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
sdkMsgs, err := decorator.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg)
if err != nil {
return nil, nil, err
}
// get the dependencies for the contract to validate against
wasmDependency, err := decorator.aclKeeper.GetWasmDependencyMapping(ctx, contractAddr)
// If no mapping exists, or mapping is disabled, this message would behave as blocking for all resources
if err == aclkeeper.ErrWasmDependencyMappingNotFound {
// no mapping, we can just continue
return decorator.wrapped.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg)
}
if err != nil {
return nil, nil, err
}
if !wasmDependency.Enabled {
// if not enabled, just move on
// TODO: confirm that this is ok, is there ever a case where we should still verify dependencies for a disabled dependency? IDTS
return decorator.wrapped.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg)
}
// convert wasm dependency to a map of resource access and identifier we can look up in
lookupMap := BuildWasmDependencyLookupMap(wasmDependency.AccessOps)
// wasm dependency enabled, we need to validate the message dependencies
for _, msg := range sdkMsgs {
accessOps := decorator.aclKeeper.GetMessageDependencies(ctx, msg)
// go through each access op, and check if there is a completion signal for it OR a parent
for _, accessOp := range accessOps {
// first check for our specific resource access AND identifier template
depsFulfilled := AreDependenciesFulfilled(lookupMap, accessOp)
if !depsFulfilled {
return nil, nil, ErrUnexpectedWasmDependency
}
}
}
// we've gone through all of the messages
// and verified their dependencies with the declared dependencies in the wasm contract dependencies, we can process it now
return decorator.wrapped.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg)
}
Loading