From bbc7aaedb828959ee1865ab24042e1ec2c15366d Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Wed, 8 Mar 2023 14:39:50 +0100 Subject: [PATCH] feat(logic): handle wasm uri on consult/1 predicate --- x/logic/interpreter/fs/fs.go | 37 +++-------------- x/logic/interpreter/fs/parser.go | 35 ++++++++++++++++ x/logic/interpreter/fs/wasm.go | 64 ++++++++++++++++++++++++++++++ x/logic/interpreter/interpreter.go | 5 +-- x/logic/keeper/interpreter.go | 5 ++- 5 files changed, 111 insertions(+), 35 deletions(-) create mode 100644 x/logic/interpreter/fs/parser.go create mode 100644 x/logic/interpreter/fs/wasm.go diff --git a/x/logic/interpreter/fs/fs.go b/x/logic/interpreter/fs/fs.go index 21cbc1b6..d8c9bb39 100644 --- a/x/logic/interpreter/fs/fs.go +++ b/x/logic/interpreter/fs/fs.go @@ -2,27 +2,21 @@ package fs import ( goctx "context" - "encoding/base64" - "encoding/json" - "fmt" "io/fs" "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/okp4/okp4d/x/logic/types" ) type FileSystem struct { - ctx goctx.Context - wasmKeeper types.WasmKeeper + ctx goctx.Context + parser Parser } // New return a new FileSystem object that will handle all virtual file on the interpreter. // File can be provided from different sources like CosmWasm cw-storage smart contract. -func New(ctx goctx.Context, keeper types.WasmKeeper) FileSystem { +func New(ctx goctx.Context, handlers []URIHandler) FileSystem { return FileSystem{ - ctx: ctx, - wasmKeeper: keeper, + ctx: ctx, + parser: Parser{handlers}, } } @@ -39,26 +33,7 @@ func (f FileSystem) Open(name string) (fs.File, error) { // The caller is permitted to modify the returned byte slice. // This method should return a copy of the underlying data. func (f FileSystem) ReadFile(name string) ([]byte, error) { - sdkCtx := sdk.UnwrapSDKContext(f.ctx) - - req := []byte(fmt.Sprintf("{\"object_data\":{\"id\": \"%s\"}}", name)) - contractAddr, err := sdk.AccAddressFromBech32("okp415ekvz3qdter33mdnk98v8whv5qdr53yusksnfgc08xd26fpdn3ts8gddht") - if err != nil { - return nil, err - } - - data, err := f.wasmKeeper.QuerySmart(sdkCtx, contractAddr, req) - if err != nil { - return nil, err - } - var program string - err = json.Unmarshal(data, &program) - if err != nil { - return nil, err - } - - decoded, err := base64.StdEncoding.DecodeString(program) - return decoded, err + return f.parser.Parse(f.ctx, name) } type Object []byte diff --git a/x/logic/interpreter/fs/parser.go b/x/logic/interpreter/fs/parser.go new file mode 100644 index 00000000..0c4e8d0d --- /dev/null +++ b/x/logic/interpreter/fs/parser.go @@ -0,0 +1,35 @@ +package fs + +import ( + "context" + "fmt" + "net/url" +) + +type URIHandler interface { + CanOpen(ctx context.Context, uri *url.URL) bool + Open(ctx context.Context, uri *url.URL) ([]byte, error) +} + +type Parser struct { + Handlers []URIHandler +} + +func (p *Parser) Parse(ctx context.Context, name string) ([]byte, error) { + uri, err := url.Parse(name) + if err != nil { + return nil, err + } + + if uri.Scheme != "okp4" { + return nil, fmt.Errorf("incompatible schema '%s' for %s", uri.Scheme, name) + } + + for _, handler := range p.Handlers { + if handler.CanOpen(ctx, uri) { + return handler.Open(ctx, uri) + } + } + + return nil, fmt.Errorf("could not find handler for load %s file", name) +} diff --git a/x/logic/interpreter/fs/wasm.go b/x/logic/interpreter/fs/wasm.go new file mode 100644 index 00000000..1f7d6804 --- /dev/null +++ b/x/logic/interpreter/fs/wasm.go @@ -0,0 +1,64 @@ +package fs + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "net/url" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/okp4/okp4d/x/logic/types" +) + +const queryKey = "query" +const hostName = "wasm" + +type WasmFS struct { + wasmKeeper types.WasmKeeper +} + +func NewWasmFS(keeper types.WasmKeeper) WasmFS { + return WasmFS{wasmKeeper: keeper} +} + +func (w WasmFS) CanOpen(ctx context.Context, uri *url.URL) bool { + return uri.Host == hostName +} + +func (w WasmFS) Open(ctx context.Context, uri *url.URL) ([]byte, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + paths := strings.SplitAfter(uri.Path, "/") + if len(paths) != 2 { + return nil, fmt.Errorf("incorect path, should contains only contract address : '://wasm/{contractAddr}?query={query}'") + } + + contractAddr, err := sdk.AccAddressFromBech32(paths[1]) + if err != nil { + return nil, fmt.Errorf("failed convert path '%s' to contract address: %w", uri.Path, err) + } + + if !uri.Query().Has(queryKey) { + return nil, fmt.Errorf("uri should contains query params") + } + query := uri.Query().Get(queryKey) + + data, err := w.wasmKeeper.QuerySmart(sdkCtx, contractAddr, []byte(query)) + if err != nil { + return nil, fmt.Errorf("failed query wasm keeper: %w", err) + } + + var program string + err = json.Unmarshal(data, &program) + if err != nil { + return nil, fmt.Errorf("failed unmarshal json wasm response to string: %w", err) + } + + decoded, err := base64.StdEncoding.DecodeString(program) + if err != nil { + return nil, fmt.Errorf("failed decode wasm base64 respone: %w", err) + } + return decoded, nil +} diff --git a/x/logic/interpreter/interpreter.go b/x/logic/interpreter/interpreter.go index 78bba085..eb85338d 100644 --- a/x/logic/interpreter/interpreter.go +++ b/x/logic/interpreter/interpreter.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ichiban/prolog" "github.com/okp4/okp4d/x/logic/interpreter/fs" - "github.com/okp4/okp4d/x/logic/types" ) // New creates a new prolog.Interpreter with: @@ -22,10 +21,10 @@ func New( predicates []string, bootstrap string, meter sdk.GasMeter, - wasmKeeper types.WasmKeeper, + uriHandlers []fs.URIHandler, ) (*prolog.Interpreter, error) { var i prolog.Interpreter - i.FS = fs.New(ctx, wasmKeeper) + i.FS = fs.New(ctx, uriHandlers) for _, o := range predicates { if err := Register(&i, o, meter); err != nil { diff --git a/x/logic/keeper/interpreter.go b/x/logic/keeper/interpreter.go index 5ebc7619..d61c043c 100644 --- a/x/logic/keeper/interpreter.go +++ b/x/logic/keeper/interpreter.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ichiban/prolog" "github.com/okp4/okp4d/x/logic/interpreter" + "github.com/okp4/okp4d/x/logic/interpreter/fs" "github.com/okp4/okp4d/x/logic/types" "github.com/okp4/okp4d/x/logic/util" ) @@ -97,12 +98,14 @@ func (k Keeper) newInterpreter(ctx goctx.Context) (*prolog.Interpreter, error) { interpreterParams := params.GetInterpreter() + wasmHandler := fs.NewWasmFS(k.WasmKeeper) + interpreted, err := interpreter.New( ctx, util.NonZeroOrDefault(interpreterParams.GetRegisteredPredicates(), interpreter.RegistryNames), util.NonZeroOrDefault(interpreterParams.GetBootstrap(), interpreter.Bootstrap()), sdkctx.GasMeter(), - k.WasmKeeper, + []fs.URIHandler{wasmHandler}, ) return interpreted, err