From 0661beec783268a7afe6cd1b8f7180a86e3426c1 Mon Sep 17 00:00:00 2001 From: Tomasz Kulik Date: Thu, 17 Oct 2024 09:30:27 +0200 Subject: [PATCH] docs: Move `spec` to cosmwasm documentation --- Makefile | 5 + README.md | 18 +-- spec/Architecture.md | 120 -------------------- spec/Index.md | 68 ------------ spec/Specification.md | 252 ------------------------------------------ 5 files changed, 11 insertions(+), 452 deletions(-) delete mode 100644 spec/Architecture.md delete mode 100644 spec/Index.md delete mode 100644 spec/Specification.md diff --git a/Makefile b/Makefile index f86eb96af..642041d1f 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,11 @@ build-libwasmvm: cp libwasmvm/target/release/$(SHARED_LIB_SRC) internal/api/$(SHARED_LIB_DST) make update-bindings +# build and show the Rust documentation of the wasmvm +.PHONY: doc-rust +doc-rust: + (cd libwasmvm && cargo doc --no-deps --open) + .PHONY: build-go build-go: go build ./... diff --git a/README.md b/README.md index 903e0ef5c..cb27f61bd 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ allows you to compile, initialize and execute CosmWasm smart contracts from Go applications, in particular from [x/wasm](https://github.com/CosmWasm/wasmd/tree/master/x/wasm). +More information on what is CosmWasm and how to use it can be found here: +[CosmWasm Docs](https://docs.cosmwasm.com). To generate and show +the Rust part documentation you can run `make doc-rust`. + ## Structure This repo contains both Rust and Go code. The Rust code is compiled into a @@ -37,7 +41,7 @@ make release-build-windows ### Go code -The Go code consistes of three packages: +The Go code consists of three packages: 1. The types (the `github.com/CosmWasm/wasmvm/types` import), using `package types` @@ -146,19 +150,9 @@ which for example excludes all 32 bit systems. -## Docs - -Run `(cd libwasmvm && cargo doc --no-deps --open)`. - -## Design - -Please read the [Documentation](./spec/Index.md) to understand both the general -[Architecture](./spec/Architecture.md), as well as the more detailed -[Specification](./spec/Specification.md) of the parameters and entry points. - ## Development -There are two halfs to this code - go and rust. The first step is to ensure that +There are two halves to this code - go and rust. The first step is to ensure that there is a proper dll built for your platform. This should be `api/libwasmvm.X`, where X is: diff --git a/spec/Architecture.md b/spec/Architecture.md deleted file mode 100644 index 9cf4d25de..000000000 --- a/spec/Architecture.md +++ /dev/null @@ -1,120 +0,0 @@ -# Architecture - -## The Handler Interface - -For the work below, we are just looking at the "Handler" interface. In go, this is -`type Handler func(ctx Context, msg Msg) Result`. In addition to the message to process, -it gets a Context that allows it to view and mutate state: - -```go -func (c Context) Context() context.Context { return c.ctx } -func (c Context) MultiStore() MultiStore { return c.ms } -func (c Context) BlockHeight() int64 { return c.header.Height } -func (c Context) BlockTime() time.Time { return c.header.Time } -func (c Context) ChainID() string { return c.chainID } -func (c Context) TxBytes() []byte { return c.txBytes } -func (c Context) Logger() log.Logger { return c.logger } -func (c Context) VoteInfos() []abci.VoteInfo { return c.voteInfo } -func (c Context) GasMeter() GasMeter { return c.gasMeter } -func (c Context) BlockGasMeter() GasMeter { return c.blockGasMeter } -func (c Context) IsCheckTx() bool { return c.checkTx } -func (c Context) MinGasPrices() DecCoins { return c.minGasPrice } -func (c Context) EventManager() *EventManager { return c.eventManager } -``` - -It is clearly not desirable to expose all this to arbitrary, unaudited code, but we can grab a subset of this to expose to the wasm contract. - -Readonly, verified by state machine: - -* Block Context - * BlockHeight - * BlockTime - * ChainID -* Transaction Data - * Signer (who authorized this message) - * Tokens Sent with message -* Contract State - * Contract Address - * Contract Account (just balance or more info?) - -Read/Write, to state machine: - -* A sandboxed sub-store -* Events(?) - -Untrusted data: - -* Arbitary user-defined message data (generally json request) - -## Security Model - -We clearly cannot just pass in a Controller to another module into an unknown wasm contract. But we do need some way to allow a wasm contract to integrate with other modules to make it interesting. Above we allow it access to its internal state and ability to read its own balance. - -In terms of security, we can view the wasm contract as a "client" on-chain with its own account and address. It can theoretically read any on-chain data, and send any message "signed" by its own address, without opening up security holes. Provided these messages are processed just like external messages, and that gas limits are enforced in CPU time and those queries. - -Note that the addition of "subkey functionality" in the upstream sdk will allow us to selectively allow smart contracts -to act on our behalf - but only up to the limits we impose. - -## Calling Other Modules - -Ethereum provides a nice dispatch model, where a contract can make arbitrary calls to the public API of any other contract. However, we have seen many issues and bugs, especially related to re-entrancy attacks. To simplify this, we propose that the contract cannot directly call any other contract, but instead *returns a list of messages*, which will be dispatched and validated *after contract execution* but in *the same transaction*. This means that if they fail, the contract will also roll back, but we don't allow any cycles or re-entrancy possibilities. - -We could conceive of this as something like: `ProcessMessage(info ReadOnlyInfo, db SubStore) []Msg`. -Note that we also want to allow it to return a `Result` and `Events`, so this may end up with a much larger -pseudo-function signature, like: `ProcessMessage(info ReadOnlyInfo, db SubStore) (*Result, []Event, []Msg, error)` - -This allows the contract to easily move the tokens it controls (via `SendMsg`) or even vote, stake tokens, or take any other action its account has authority to do. The potential actions increase with the delegation work being done as part of Key Management. - -Note that the contract cannot get the result of the other state-changing calls, but in pratice, this doesn't seem to be a blocker. What is important is to allow the contract to somehow query the state of other modules in the system. Since those are only reads, and performed before modifying any state, they don't allow for re-entrancy attacks. - -## Querying Other Modules - -While it is great to change state in other modules, the design until this point leave the contract blind. Sure, it can emit a message in order to stake some tokens, but it cannot check its current stake, or the number of tokens available to withdraw. To do so, we need to expose some interface to query other modules. - -Going along with the client analogy above , we definitely **do not** want to allow *write* access to the other substores. Instead we can allow something like the high level `abci_query` interface, where the smart contract would send a path and data (key), and receive the requested object - likely serialized as json rather than amino for ease -of parsing in the smart contract. - -Whether we wrap the existing `Query` interface or provide a different interface just for WASM contract is an open question, which we touch in the next section. - -## Exposing Queries - -We will also want to expose the state of the contract to clients, and possibly other modules (or contracts). The "contracts" module should contain generic code to do a raw key-value lookup on any contract. For example `contract/5/17/foo` should locate contract 5, instance 17 (assuming we auto-increment counters here... maybe this is a sha256 hash?), and in that sub-keystore for a raw query for `foo`, returning whatever data happens to be there (likely json). - -While this generic functionality is a good addition, we will want to support custom query handlers, just as all major sdk modules do. This allows us to abstract out the raw keys used in the store to something easier to understand. It also allows us to perform filters or aggregations on the results. We will expose a generic query handler interface in the store, but once a contract is deployed, the specific format will never change. Thus, one could actually allow one contract to query a previously deployed contract through such an interface without any chance for breaking changes. - -## Upgradeability - -This can be a **major problem** or even **blocker** for enabling Web Assembly contracts, unless we make some very conscious design decisions, both in the WASM interfaces, as well as the SDK as a whole. - -If we allow the contract to query arbitrary data in other modules, this contract is dependent on those not changing. If the chain upgrades (gracefully or hardfork) and the queries return data in a different format, or change the path they respond to, then the contract will break. The same is true with the format of the messages we return. If cosmos-sdk modifies the format of the staking message, after an upgrade the module will continue to emit staking messages in the old format, which will fail - leave the contract broken and fund stuck. - -One proposed solution was to allow us to "upgrade contracts" as well, but I find this highly problematic. A core pillar of most smart contract designs is immutability, which is what allows us to trust them. If the author could change them *after* I send it my funds, then there can be no trustless execution. Maybe we then decide that governance can update the contracts, or only change them in the context of a hard-fork. This provides safe-guards, but the issue arises that the contract author and those updating the application code, and the validators all are different entities. Do we now need to contact every contract author and involve them in preparing every upgrade? Or will the validators just re-wrire contracts as they see fit? Seems extremely risky in any case. - -One alternative here is to either freeze every API that a Handler touches in cosmos-sdk, as well as every data structure exposed over `abci_query`. But this would have the effect of a huge stagnation of the codebase and very determental to innovation. - -Another alternative, and what we propose here, is to limit the interfaces exposed to the wasm contracts to a minimalistic subset of all possible functionality. And provide a fixed format with strong immutability guarantees. This will likely require some wrapper between the structs used in the wasm interface, and those used elsewhere in the sdk. As we noticed, even the transaction type changed in the upgrade to Gaia 2.0. - -We could, for example, expose a custom SendMsg, `{type: 'send', to, from, amount}` and then in the Golang wrapper code (which can be updated easily during a hard-fork), we translate this *well-defined*, *immutable*, and *forward-comaptible* message definition into the actual structure used by the cosmos-sdk, before dispatching this to other modules. We would like-wise have to provide clear definitions for a minimal set of queries we want to expose, and then make sure to translate fields from the current struct into this static definition. - -This means we would have to manually enable each Message or Query we would want to expose to all Web Assembly contract, and provide strong guarantees to each of them *forever*. We could easily add new message types, or queries, such that new contracts deployed after version X could make use of them, but all the types that were exposed to the first contract deployed on the system must remain valid for the lifetime of the chain (including any hardforks, dump-state-and-reset, etc.). - -**WARNING** - -Even with a buffer class, this will have a noticeable strong impact on a number of development practices in the core cosmos-sdk team, especially related to version and migration, and we need to have a clear and open discussion on possible approaches here. - -Relevant link (recommended by Aaron): https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/Spec_ulation.md - -## Genesis File - -It is not desirable (or feasible) to run every smart contract to do a state dump and restore. However, since all the data of the contracts is in the kvstore, it is ultimately owned by the Go "contract" module, and we can build a generic import/export logic there. Serializing the contract should only consist in a base64 dump of the binary wasm code. For each instance of the contract (with its own substore), we can serialize the raw data as hex and then decode it. Often the keys are strings and values are (ascii) json, so a text representation is simpler to read and much smaller. Perhaps we can check this per contract and have an option to use the ascii encoding if possible, otherwise use a generic hex encoding of the store? - - - -## Summary - -* Contracts get *trusted context* from the state machine, as well as raw, *user-defined message* to specify the requested action -* Contracts can trigger state changes in other modules, by returning a list of "messages" that will be dispatched after contract execution, but **in the same atomic transaction** -* Contracts will have a (limited) way to query state in other modules as syncronous calls inside their logic -* Contracts can also expose a custom query handler for clients (or other contracts) -* Defining stable APIs decoupled from the actual SDK code is essential for allowing upgradeability (that old contracts still work after state machine upgrades) -* The "contract" module should be fully responsible for exporting and importing the data for all contracts in a generic manner diff --git a/spec/Index.md b/spec/Index.md deleted file mode 100644 index edc2db431..000000000 --- a/spec/Index.md +++ /dev/null @@ -1,68 +0,0 @@ -# WebAssembly integration in Cosmos-SDK - -This is a proposal for how to integrate the wasmer engine into the cosmos-sdk. Not on the technical details of the runtime implementation, but on how it connects to the rest of the SDK framework and all modules build upon it. - -## External Requirements - -This is based on work with the wasmer.io engine, including the following other repositories: - -[cosmwasm](https://github.com/confio/cosmwasm): - -* Configuration to build rust to WebAssembly -* Helper library to remove boilerplate (also see [cosmwasm-template](https://github.com/confio/cosmwasm-template)) -* Testing support for smart contracts - -[cosmwasm-vm](https://github.com/CosmWasm/cosmwasm/tree/main/packages/vm): - -* Repeatable gas metering (fixed backend compiler options) -* Feature flags for backends - -[cosmwasm-opt](https://github.com/confio/cosmwasm-opt): - -* Deterministic builds (so we can map rust to on-chain wasm) -* Small wasm binaries (~100KB typical) - -## Scope - -When we discuss Web Assembly, most people see it as a magic fix that -allows us to upload sandboxed, user-defined code *anywhere*. The truth -is that while Web Assembly allows us to upload sandboxed functions to -run, we need to design the connections (arguments, return value, and environment) -with one specific case in mind. - -As Aaron put it well, anywhere we accept a Go *interface* in the SDK, -we could place a WASM adapter there. But just as a struct only -implements one interface, we need to concentrate on one interface to adapt. - -The majority of the use cases could be covered by a properly designed adapter for *Handler* -and this is where we will focus our work. This is also where most zone development is going - -into modules that expose a custom Handler. The initial implementation should minimally allow -us to create such contracts: - -* Payment Channels -* Atomic Swap -* Escrow (with arbiter) -* Automatic payment distribution based on shares -* (maybe) Programmable NFTs: just as ethereum NFTs include some custom code to perform actions - -As we expand the allows messages and query options, we will enable more use-cases. -The extensions to the API should probably be driven by real use cases - -please add your needs as issues on this repo. - -### Future Directions - -However, there are a number of other places where we could potentially provide another interface -for custom web assembly contracts,to be added after the original integration work. Some other -important use cases that will need different adapters: - -* **IBC verification function** The current ICS23 spec mentions wasm uploaded code to verify external proofs. This should be easily creatable with a custom interface . -* **Delegation Rewards** Support different commission to different validators based on on-chain rules. -* **Signature Verification** Allow uploading new algorithms, like `ed25519` or `BLS`. These would obviously need to be enabled by a governance vote. - -## Contents - -More information on the current Web Assembly framework design: - -* [Architecture](./Architecture.md) - a high-level view of what capabilities we expose to the Wasm contracts -* [Specification](./Specification.md) - a more detailed look at interfaces, methods, and structs to be used -* [Tutorial](https://www.cosmwasm.com) - tutorials and reference on building with cosmwasm diff --git a/spec/Specification.md b/spec/Specification.md deleted file mode 100644 index b2edd2a32..000000000 --- a/spec/Specification.md +++ /dev/null @@ -1,252 +0,0 @@ -# Specification - -This section attempts to codify the [architecture](./Architecture.md) with a number of concrete -implementation details, function signatures, naming choices, etc. - -## Definitions - -**Contract** is as some wasm code uploaded to the system, initialized at the creation of the contract. This has no state except that which is contained in the wasm code (eg. static constants) - -**Instance** is one instantiation of the contract. This contains a reference to the contract, as well as some "local" state to this instance, initialized at the creation of the instance. This state is stored in the kvstore, meaning a reference to the code plus a reference to the (prefixed) data store uniquely defines the smart contract. - -Example: we could upload a generic "ERC20 mintable" contract, and many people could create independent instances of the same bytecode, where the local data defines the token name, the issuer, the max issuance, etc. - -- First you **create** a _contract_ -- Then you **instantiate** an _instance_ -- Finally users **invoke** the _instance_ - -_Contracts_ are immutible (code/logic is fixed), but _instances_ are mutible (state changes) - -## Serialization Format - -There are two pieces of data that must be considered here. **Message Data**, which is arbitrary binary data passed in the transaction by the end user signing it, and **Context Data**, which is passed in by the cosmos sdk runtime, providing some guaranteed context. Context data may include the signer's address, the instance's address, number of tokens sent, block height, and any other information a contract may need to control the internal logic. - -**Message Data** comes from a binary transaction and must be serialized. The most standard and flexible codec is (unfortunately) JSON. This allows the contract to define any schema it wants, and the client can easily provide the proper data. We recommend using a `string` field in the `InvokeMsg`, to contain the user-defined _message data_. - -**Contact Data** comes from the go runtime and can either be serialized by sdk and deserialized by the contract, or we can try to do some ffi magic and use the same memory layout for the struct in Go and Wasm and avoid any serialization overhead. Note that the context data struct will be well-defined at compile time and guaranteed not to change between invocations (the same cannot be said for _message data_). - -In spite of possible performance gains or compiler guarantees with C-types, I would recommend using JSON for this as well. Or another well-defined binary format, like protobuf. However, I will document some links below for those who would like to research the shared struct approach. - -- [repr( c )](https://doc.rust-lang.org/nomicon/other-reprs.html) is a rust directive to produce cannonical C-style memory layouts. This is typically used in FFI (which wasm calls are). -- [wasm-ffi](https://github.com/DeMille/wasm-ffi) demos how to pass structs between wasm/rust and javascript painlessly. Not into golang, but it provides a nice explanation and design overview. -- [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen/) also tries to convert types and you can [read some success and limitations of the approach](https://github.com/rustwasm/wasm-bindgen/issues/111) -- [cgo](https://golang.org/cmd/cgo/#hdr-Go_references_to_C) has some documentation about accessing C structs from Go (which is what we get with the repr( c ) directive) - -In short, go/cgo doesn't handle c-types very transparently, and these also don't support references to heap allocated data (eg. strings). All we get is a small performance gain for a lot of headaches... let's stick with json. - -## State Access - -**Instance State** is accessible only by one instance of the contract, with full read-write access. This can contain either a singleton (one key - simple contract or config) or a kvstore (subspace with many keys that can be accessed - like erc20 instance holding balances for many accounts). Sometimes the contract may want one or the other or even both (config + much data) access modes. - -We can set the instance state upon _instantiation_. We can read and modify it upon _invocation_. This is a unique "prefixed db" subspace that can only be accessed by this instance. The read-only contract state should suffice for shared data between all instances. (Discuss this design in light of all use cases) - -**Instance Account** is the sdk account controlled by this isntance. We pass in the address of the account, as well as it's current balance along with every invocation of the contract. This allows the contract to be somewhat self-aware of the external environment for the most common cases (eg. if it needs to release funds). - -## Function Definitions - -As discussed above, all data structures passed between web assembly and the cosmos-sdk will be sent in their JSON representation. For simplicity, I will show them as Go structs in this section, but only the json representation is used. - -The actual call to create a new contract (upload code) is quite simple, and returns a `ContractID` to be used in all future calls: -`Create(contract WasmCode) (ContractID, error)` - -Both Instantiating a contract, as well as invoking a contract (`Execute` method) have similar interfaces. The difference is that `Instantiate` requires the `store` to be empty, while `Execute` requires it to be non-empty: - -- `Instantiate(contract ContractID, params Params, userMsg []byte, store KVStore, gasLimit int64) (res *Result, err error)` -- `Execute(contract ContractID, params Params, userMsg []byte, store KVStore, gasLimit int64) (res *Result, err error)` - -We also expose a Query method to respond to abci.QueryRequests: - -- `Query(contract ContractID, path []byte, data []byte, store KVStore, gasLimit int64) ([]byte, error)` - -Here we pass in the remainder of the path (after directing to the contract) as well as a user-defined (json?) data from the query. We pass in the instances KVStore as above, and a gasLimit, as the computation takes some time. There is no gas for queries, but we should define some reasonable limit here to avoid any DoS vectors, such as a uploading a contract with an infinite loop in the query handler. QueryResult is JSON-encoded data in whatever format the contract decides. - -Note that no `InstanceID` is ever used. The reason being is that the code and the data define the entire instance state. The calling logic is responsible for prefixing the `KVStore` with the instance-specific prefix and passing the proper `ContractInfo` in the parameters. This `InstanceID` is managed on the SDK side, but not exposed over the general interface to the Wasm engine. - -### Parameters - -This Read-Only info is available to every contract: - -```go -// Params defines the state of the blockchain environment this contract is -// running in. This must contain only trusted data - nothing from the Tx itself -// that has not been verfied (like Signer). -// -// Params are json encoded to a byte slice before passing to the wasm contract. -type Params struct { - Block BlockInfo `json:"block"` - Message MessageInfo `json:"message"` - Contract ContractInfo `json:"contract"` -} - -type BlockInfo struct { - // block height this transaction is executed - Height uint64 `json:"height"` - // time in nanoseconds since unix epoch. Uses Uint64 to ensure JavaScript compatibility. - Time Uint64 `json:"time"` - ChainID string `json:"chain_id"` -} - -type MessageInfo struct { - // binary encoding of sdk.AccAddress executing the contract - Sender HumanAddress `json:"sender"` - // amount of funds send to the contract along with this message - Funds Coins `json:"funds"` -} - -type ContractInfo struct { - // sdk.AccAddress of the contract, to be used when sending messages - Address string `json:"address"` - // current balance of the account controlled by the contract - Balance []Coin `json:"send_amount"` -} - -// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int) -type Coin struct { - Denom string `json:"denom"` // string encoing of decimal value, eg. "12.3456" - Amount string `json:"amount"` // type, eg. "ATOM" -} -``` - -### Results - -This is the information the contract can return: - -```go -// Result defines the return value on a successful -type Result struct { - // Messages comes directly from the contract and is it's request for action - Messages []CosmosMsg `json:"msgs"` - // base64-encoded bytes to return as ABCI.Data field - Data string - // attributes for a log event to return over abci interface - Attributes []EventAttribute `json:"attributes"` -} -``` - -`CosmosMsg` is defined in the next section. - -Note: I intentionally redefine a number of core types, rather than importing them from sdk/types. This is to guarantee immutibility. These types will be passed to and from the contract, and the contract adapter code (in go) can convert them to the go types used in the rest of the app. But these are decoupled, so they can remain constant while other parts of the sdk evolve. - -I also consider adding Events to the return Result, but will delay that until there is a clear spec for how to use them - -## Dispatched Messages - -`CosmosMsg` is an abstraction of allowed message types that is designed to be consistent in spite of any changes to the underlying SDK. The "contract" module will maintain an adapter between these well-defined types and the current sdk implementation. - -The following are allowed types for `CosmosMsg` return values. To be expanded later: - -```go -// CosmosMsg is an rust enum and only (exactly) one of the fields should be set -// Should we do a cleaner approach in Go? (type/data?) -type CosmosMsg struct { - Send SendMsg `json:"send"` - Contract ContractMsg `json:"contract"` - Opaque OpaqueMsg `json:"opaque"` -} - -// SendMsg contains instructions for a Cosmos-SDK/SendMsg -// It has a fixed interface here and should be converted into the proper SDK format before dispatching -type SendMsg struct { - ToAddress string `json:"to_address"` - Amount []Coin `json:"amount"` -} - -// ContractMsg is used to call another defined contract on this chain. -// The calling contract requires the callee to be defined beforehand, -// and the address should have been defined in initialization. -// And we assume the developer tested the ABIs and coded them together. -// -// Since a contract is immutable once it is deployed, we don't need to transform this. -// If it was properly coded and worked once, it will continue to work throughout upgrades. -type ContractMsg struct { - // ContractAddr is the sdk.AccAddress of the contract, which uniquely defines - // the contract ID and instance ID. The sdk module should maintain a reverse lookup table. - ContractAddr string `json:"contract_addr"` - // Msg is assumed to be a json-encoded message, which will be passed directly - // as `userMsg` when calling `Execute` on the above-defined contract - Msg string `json:"msg"` -} - - -// OpaqueMsg is some raw sdk-transaction that is passed in from a user and then relayed -// by the contract under some given conditions. These should never be created or -// inspected by the contract, but allows to build eg. multisig, governance in a contract -// and allow the end users to make use of all sdk functionality. -// -// An example is submitting a proposal for a vote. This is assumed to be correct (from the user) -// and if the contract determines the vote passed, the contract can then re-send it. If the chain -// updates, the client can submit a new proposal in the new format. Since this never comes from the -// contract itself, we don't need to worry about upgrading. -type OpaqueMsg struct { - // Data is a custom msg that the sdk knows. - // Generally the base64-encoded of go-amino binary encoding of an sdk.Msg implementation. - // This should never be created by the contract, but allows for blindly passing through - // temporary data. - Data string `json:"data"` -} -``` - -## Exposed imports - -### Local Storage - -We expose a (sandboxed) `KVStore` to the contract that it can read and write to as it desires (with gas limits and perhaps absolute storage limits). This is then translated into a C struct and passed into rust to be adapted to the wasm contract. But in essence we expose the following: - -```go -type KVStore interface { - Get(key []byte) []byte - Set(key, value []byte) -} -``` - -If desired, we can add an Iterate method, but that adds yet another level of complexity, a method that returns yet another object with custom callbacks. And then ensuring proper cleanup. - -### Querying Other Modules - -We also pass in a callback to the smart contracts to make some well-defined queries - -```go -Query(query QueryRequest) (QueryModels, error) -``` - -Both of these are enums (interfaces) and there is a clear 1-to-1 relation between QueryRequest type to QueryModel type. We can not make any arbitrary queries, but only those well-specified below. - -## Well-defined Queries - -Here are request-model pairs that we can use in queries: - -```go -// QueryRequest is an enum. Exactly one field should be non-empty -type QueryRequest struct { - Account AccountRequest `json:"account"` -} - -// QueryModels is an enum. Exactly one field should be non-empty: the same one corresponding to the Request -type QueryModels struct { - Account []AccountModel `json:"account"` -} -``` - -**Account** - -```go -// AccountRequest asks to read the state of a given account -type AccountRequest struct { - // bech32 encoded sdk.AccAddres - Address string `json:"address"` -} - -// AccountModel is a basic description of an account -// (more fields may be added later, but none should change) -type AccountModel struct { - Address string `json:"address"` - Balance []Coin `json:"balance"` - // pubkey may be empty - PubKey struct { - // hex-encoded bytes of the raw public key - Data string `json:"data"` - // the algorithm of the pubkey, currently "secp256k1", possibly others in the future - Algo string `json:"algo"` - } `json:"pub_key"` -} -```