Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve setup cost calculation #1798

Closed
webmaster128 opened this issue Jan 26, 2024 · 0 comments · Fixed by #1987
Closed

Improve setup cost calculation #1798

webmaster128 opened this issue Jan 26, 2024 · 0 comments · Fixed by #1987

Comments

@webmaster128
Copy link
Member

webmaster128 commented Jan 26, 2024

Setup cost is the gas charged every time a contract is set up for execution trhough any entry point (execute/instantiate/sudo/query/migrate/reply/....). Right now it is implemented like this:

// SetupContractCost costs when interacting with a wasm contract
func (g WasmGasRegister) SetupContractCost(pinned bool, msgLen int) storetypes.Gas {
	if msgLen < 0 {
		panic(errorsmod.Wrap(ErrInvalid, "negative length"))
	}
	dataCosts := storetypes.Gas(msgLen) * g.c.ContractMessageDataCost
	if pinned {
		return dataCosts
	}
	return g.c.InstanceCost + dataCosts
}

i.e. we charge for the message sent to it as well as creating the executable contract instance in memory. So the pinned flag has a significant impact on the gas usage. It is set to true in two cases:

  1. k.IsPinnedCode(ctx, contractInfo.CodeID) is true, i.e. the contract is pinnend
  2. We setup a contract for reply

Case 2. is actually a misuse of the flag, or at least in its current name. We use the assumption that the contract is still in the in-memory cache when we send the reply. This assumption is plausible but with a node-specific setting of the cache size can lead to situtions when we charge low gas.

In addition to reply, there are other cases in which a a contract is executed multiple times in a tx or block. Following the idea of reply in 2., we can say that the gas discount is given for all calls in a transaction or block that have been seen before. So instead of the current logic in reply

	// always consider this pinned
	replyCosts := k.gasRegister.ReplyCosts(true, reply)

we can say that if code (identified by checksum) was used in this transaction before, give a discount. This then always includes replys but many other cases as well. It would requiring a map from checksum to boolean that is maintained for the lifetime of the transaction.

I think the scope for the discount should be transaction, not block for the following reasons:

  • A block can have more contract executions than there is space in the in-memory cache, creating a risk for underpricing
  • The gas simulation becomes inacurate when the gas usage depends on other transactions in the block.

The reason for the discount for pinned contracts and contracts in the in-memory cache is that their Wasmer instance is created in ~45µs instead of 1.5ms (33x faster).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant