# CosmWasm Events State-Breakage Currently, there is a bug that leads to gas being charged for newly added events and attributes in `Cosmos SDK` messages that are called from `CosmWasm` contracts As a result, this prevents chain developers from adding useful events in a state-compatible manner. For example, [these events](https://github.com/osmosis-labs/osmosis/pull/7622/files) in the Osmosis concentrated liquidity module lead to a state-break due to diverging gas numbers in the `v23.x` release line. ## Source 1 The first source of the state-break stems from the fact that `wasmd` does not correctly filter out events for `StargateMsg` [here](https://github.com/osmosis-labs/wasmd/blob/aba521a80563ceb88d27d14e5d7527735f4aae5d/x/wasm/keeper/msg_dispatcher.go#L109-L125). As a result, the [ReplyCosts](https://github.com/osmosis-labs/wasmd/blob/aba521a80563ceb88d27d14e5d7527735f4aae5d/x/wasm/types/gas_register.go#L189) function ends up charging gas for the newly added event attributes. ## Source 2 The second source of the gas differences is affected by one of the following components: - `wasmvm` - `cosmwasm` - [Quasar CL vault contract](https://github.com/quasar-finance/quasar/tree/main/smart-contracts/contracts/cl-vault) The problem starts when we call [wasmvm.Reply()](https://github.com/osmosis-labs/wasmd/blob/aba521a80563ceb88d27d14e5d7527735f4aae5d/x/wasm/keeper/keeper.go#L552C1-L556C3) from `x/wasmd`. When called with new events, it returns a higher `gasUsed` value, causing a state-break. This call gets propagated all the way to wasm VM. ![image](https://hackmd.io/_uploads/SJl0DTM6p.png) - The above log shows the gas differences between Osmosis run with the new events (left) and witout (right) - Note that it also prints a structure called `gasReport` that internal `wasmvm` and `cosmwasm` logic operates on. Below is the definition of the printed structure: ```go= type GasReport struct { Limit uint64 Remaining uint64 UsedExternally uint64 UsedInternally uint64 } ``` Tracing the executes down the stack, we see that the divergence originates in the `gasReport` [here](https://github.com/CosmWasm/wasmvm/blob/c62cd6e770606238ce213b0090514eac8e87c44f/internal/api/lib.go#L399-L404). The `gasReport` that differs is created by the call to [instance.create_gas_report()](https://github.com/CosmWasm/wasmvm/blob/c62cd6e770606238ce213b0090514eac8e87c44f/libwasmvm/src/calls.rs#L485). Which is implemented [here](https://github.com/CosmWasm/cosmwasm/blob/453f297eb7c6b4a46220bef45adae30c671021e9/packages/vm/src/instance.rs#L352) With the newly emitted event, the `Remaining` gas is smaller while `UsedInternally` is larger (see log diff screenshot.) This is how we compute these values in `CosmWasm` to return back to `Go`: ```rust= GasReport { limit: state.gas_limit, remaining: gas_left, used_externally: state.externally_used_gas, // If externally_used_gas exceeds the gas limit, this will return 0. // no matter how much gas was used internally. But then we error with out of gas // anyways, and it does not matter much anymore where gas was spend. used_internally: state .gas_limit .saturating_sub(state.externally_used_gas) .saturating_sub(gas_left), } ``` We can see that `used_internally` is computed from `externally_used_gas`, `gas_limit` and `remaining`. Since `remaining` is the only one that changed based on logs, it is the cause of the divergence. Next, we should evaluate why `gas_left` that is set to `remaining` differs. [This function](https://github.com/CosmWasm/cosmwasm/blob/453f297eb7c6b4a46220bef45adae30c671021e9/packages/vm/src/environment.rs#L325-L336) returns the `gas_left` value from the `cosmwasm` layer of abstraction. That in turn taps into the `wasmer` runtime APIs [here](https://github.com/wasmerio/wasmer/blob/f2954815aff5e4f1e1996166f67f396a81653a86/lib/middlewares/src/metering.rs#L298C1-L306C38). As a result, the gas difference origin due to newly addded events is confirmed to be from the cosmwasm runtime. The following are the open theories: - The submessage event response difference affects the cosmwasm gas numbers. - A Quasar contract might be reading the response events and persisting them in state. Based on the initial investigations of the [affected message](https://github.com/quasar-finance/quasar/blob/8a8f6552eff514f20525604c4d168ac4831cfe4f/smart-contracts/contracts/cl-vault/src/contract.rs#L168) in the Quasar contract execute flow, the first theory is more likely since I do not see the contract storing any responses/chain events in state. I would appreciate any pointers on this matter from Quasar or CosmWasm experts. ### March 4 Update The cause of the second source of the event state breakage stems from the fact that we push all events into the reply to cosmwasm contracts. Some internal logic charges gas for these additional events. [This](https://github.com/CosmWasm/cosmwasm/blob/453f297eb7c6b4a46220bef45adae30c671021e9/packages/vm/src/calls.rs#L424) is where it is charged. Stepping inside [that call](https://github.com/CosmWasm/cosmwasm/blob/453f297eb7c6b4a46220bef45adae30c671021e9/packages/vm/src/calls.rs#L577-L581), we see instance.allocate() that makes wasmer runtime to consume internal gas. ~~I propose to avoid submitting any events to the smart contracts via reply~~ The proposal is non-trivial since there are already existing users relying on these events.