Skip to content

Commit

Permalink
fix(deps): dymint bump to fix da grpc issue (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
srene authored Sep 27, 2024
1 parent 16e9706 commit d6e15ba
Show file tree
Hide file tree
Showing 18 changed files with 61 additions and 39 deletions.
2 changes: 1 addition & 1 deletion contracts/callback-test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ pub mod sudo {
}
```

Relevant test has been added as well in contract.rs and the default counter init/execute tests removed
Relevant test has been added as well in contract.rs and the default counter init/execute tests removed
6 changes: 3 additions & 3 deletions e2e/testing/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ func NewTestChain(t *testing.T, chainIdx int, opts ...interface{}) *TestChain {

// Split options by groups (each group is applied in a different init step)
var chainCfgOpts []TestChainConfigOption
var consensusParamsOpts []TestChainConsensusParamsOption
//var consensusParamsOpts []TestChainConsensusParamsOption
var genStateOpts []TestChainGenesisOption
for i, opt := range opts {
switch opt := opt.(type) {
case TestChainConfigOption:
chainCfgOpts = append(chainCfgOpts, opt)
case TestChainConsensusParamsOption:
consensusParamsOpts = append(consensusParamsOpts, opt)
// case TestChainConsensusParamsOption:
// consensusParamsOpts = append(consensusParamsOpts, opt)
case TestChainGenesisOption:
genStateOpts = append(genStateOpts, opt)
default:
Expand Down
4 changes: 2 additions & 2 deletions e2e/testing/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"context"
"fmt"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
abci "github.com/tendermint/tendermint/abci/types"
"google.golang.org/grpc"

"github.com/dymensionxyz/rollapp-wasm/app"
Expand All @@ -27,7 +27,7 @@ func (c grpcClient) Invoke(ctx context.Context, method string, args, reply inter
})

if resp.Code != abci.CodeTypeOK {
return fmt.Errorf(resp.Log)
return fmt.Errorf("query response: %s", resp.Log)
}

c.app.AppCodec().MustUnmarshal(resp.Value, reply.(codec.ProtoMarshaler))
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/cosmos/ibc-go/v6 v6.3.0
github.com/dvsekhvalnov/jose2go v1.5.0
github.com/dymensionxyz/dymension-rdk v1.6.1-0.20240916194645-3fe31b2db4b2
github.com/dymensionxyz/dymint v1.2.0-rc01.0.20240916140329-d51b961e7e0d
github.com/dymensionxyz/dymint v1.2.0-rc01.0.20240919105350-66f9b353655d
github.com/ethereum/go-ethereum v1.12.0
github.com/evmos/evmos/v12 v12.1.6
github.com/gogo/protobuf v1.3.3
Expand Down Expand Up @@ -117,7 +117,6 @@ require (
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20240821081230-b4018b2bac13 // indirect
github.com/dymensionxyz/dymension/v3 v3.1.0-rc03.0.20240411195658-f7cd96f53b56 // indirect
github.com/dymensionxyz/gerr-cosmos v1.0.0 // indirect
github.com/dymensionxyz/sdk-utils v0.1.2-0.20240905104639-19dc09f5c6f5 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
Expand Down Expand Up @@ -164,7 +163,7 @@ require (
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.1 // indirect
github.com/hashicorp/go-getter v1.7.5 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
Expand Down Expand Up @@ -251,6 +250,7 @@ require (
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
Expand Down
10 changes: 4 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -572,10 +572,8 @@ github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20240821081230-b4018b2bac13 h
github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20240821081230-b4018b2bac13/go.mod h1:jabDQYXrccscSE0fXkh7eQFYPWJCRiuWKonFGObVq6s=
github.com/dymensionxyz/dymension-rdk v1.6.1-0.20240916194645-3fe31b2db4b2 h1:Qex0iUhBenRhOIMwrv2eYPWNIySlWVJDZ9D70iLd9eQ=
github.com/dymensionxyz/dymension-rdk v1.6.1-0.20240916194645-3fe31b2db4b2/go.mod h1:/4liuSPJFSyxlLg19KLngisZynYpa3clYuPuB460des=
github.com/dymensionxyz/dymension/v3 v3.1.0-rc03.0.20240411195658-f7cd96f53b56 h1:cmpJYdRviuUfmlJdHrcAND8Jd6JIY4rp63bWAQzPr54=
github.com/dymensionxyz/dymension/v3 v3.1.0-rc03.0.20240411195658-f7cd96f53b56/go.mod h1:3Pfrr8j/BR9ztNKztGfC5PqDiO6CcrzMLCJtFtPEVW4=
github.com/dymensionxyz/dymint v1.2.0-rc01.0.20240916140329-d51b961e7e0d h1:zL456H//aGkqTP3L2Al4f4zX2aoHgYW4YMLIt9X/EAA=
github.com/dymensionxyz/dymint v1.2.0-rc01.0.20240916140329-d51b961e7e0d/go.mod h1:SH96V6FQ213EDtJrc6OqZ9Co2E6QBuLQ7Hx/LC0qMXA=
github.com/dymensionxyz/dymint v1.2.0-rc01.0.20240919105350-66f9b353655d h1:YZ49Dd17SA//VBTKVncav7DhV5VE6M9n4a9Slm/hQeM=
github.com/dymensionxyz/dymint v1.2.0-rc01.0.20240919105350-66f9b353655d/go.mod h1:eEUBqDHi7EiO3CK1Fqct5joa5UeNzcEDJnXzvXuP5oA=
github.com/dymensionxyz/evmos/v12 v12.1.6-dymension-v0.4.2 h1:aVP3off7u2vsvRH7lHAUPTLdf9/AfnzC/rvvi0wC/co=
github.com/dymensionxyz/evmos/v12 v12.1.6-dymension-v0.4.2/go.mod h1:CI6D89pkoiIm4BjoMFNnEaCLdKBEobLuwvhS0c1zh7Y=
github.com/dymensionxyz/gerr-cosmos v1.0.0 h1:oi91rgOkpJWr41oX9JOyjvvBnhGY54tj513x8VlDAEc=
Expand Down Expand Up @@ -917,8 +915,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY=
github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4=
github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
Expand Down
4 changes: 3 additions & 1 deletion x/callback/spec/01_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Refer to the [callback.proto](../../../proto/rollapp/callback/v1/callback.proto)
The params value can only be updated by x/gov module via a governance upgrade proposal.

Storage keys:

* Params: `ParamsKey -> ProtocolBuffer(Params)`

## Callback
Expand All @@ -20,4 +21,5 @@ Storage keys:
The callbacks are pruned after they are executed.

Storage keys:
* Callback: `CallbacksKey | BlockHeight | ContractAddress | JobID -> ProtocolBuffer(Callback)`

* Callback: `CallbacksKey | BlockHeight | ContractAddress | JobID -> ProtocolBuffer(Callback)`
18 changes: 11 additions & 7 deletions x/callback/spec/02_messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,36 @@ Section describes the processing of the module messages
A new callback can be registered by using the [MsgRequestCallback](../../../proto/rollapp/callback/v1/tx.proto#L39) message.

On success:

* A callback is queued to be executed at the given height.
* The fee amount specified is transferred from the sender's account to the module account

This message is expected to fail if:

* Insufficient fees are sent
* The account has insufficient balance
* The contract with given address does not exist
* A callback with at given height for specified height with given job id already exists
* The callback request height is in the past or in the current block
* The sender is not authorized to request a callback. The callback can only be request by the following
* The contract itself
* The contract admin as set in the x/wasmd module
* The contract owner as set in the x/rewards module
* The contract itself
* The contract admin as set in the x/wasmd module
* The contract owner as set in the x/rewards module

## MsgCancelCallback

An existing callback can be cancelled by using th [MsgCancelCallback](../../../proto/rollapp/callback/v1/tx.proto#L58) message,

On success:

* The exisiting callback is removed from the execution queue.
* The txFee and surplusFee amount is refunded back to the sender.
* The rest of the fees are sent to fee_collector to be distributed to validators and stakers

This message is expected to fail if:

* Callback with specified block height, contract address and job id does not exist
* The sender is not authorized to cancel the callback. The callback can only be cancelled by the following
* The contract itself
* The contract admin as set in the x/wasmd module
* The contract owner as set in the x/rewards module
* The sender is not authorized to cancel the callback. The callback can only be cancelled by the following:
* The contract itself
* The contract admin as set in the x/wasmd module
* The contract owner as set in the x/rewards module
4 changes: 2 additions & 2 deletions x/callback/spec/03_end_block.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Section describes the module state changes on the ABCI end block call

Every end block we iterate over all the callbacks registered at that height. For each of the registered callback we,

1. Create a CallbackMsg
1. Create a CallbackMsg

It is a json encoded msg which includes the job id and is sent to the contract

Expand All @@ -30,4 +30,4 @@ Every end block we iterate over all the callbacks registered at that height. For

6. Cleanup

Remove the callback entry from the state
Remove the callback entry from the state
2 changes: 1 addition & 1 deletion x/callback/spec/04_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ The module emits the following proto-events
| Message | `MsgRequestCallback` | [CallbackRegisteredEvent](../../../proto/rollapp/callback/v1/events.proto#L11) |
| Message | `MsgCancelCallback` | [CallbackCancelledEvent](../../../proto/rollapp/callback/v1/events.proto#L25) |
| Module | `EndBlocker` | [CallbackExecutedSuccessEvent](../../../proto/rollapp/callback/v1/events.proto#L39) |
| Module | `EndBlocker` | [CallbackExecutedFailedEvent](../../../proto/rollapp/callback/v1/events.proto#L53) |
| Module | `EndBlocker` | [CallbackExecutedFailedEvent](../../../proto/rollapp/callback/v1/events.proto#L53) |
4 changes: 2 additions & 2 deletions x/callback/spec/05_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ Use the `-h`/`--help` flag to get a help description of a command.

Create a new callback for the given contract at specified height and given job id by paying the mentioned fees

Usage:
Usage:

`rollapp-wasm tx callback request-callback [contract-address] [job-id] [callback-height] [fee-amount] [flags]`

Expand All @@ -129,4 +129,4 @@ Usage:

Example:

`rollapp-wasm tx callback cancel-callback cosmos1wug8sewp6cedgkmrmvhl3 1 1234 --from myAccountKey`
`rollapp-wasm tx callback cancel-callback cosmos1wug8sewp6cedgkmrmvhl3 1 1234 --from myAccountKey`
3 changes: 2 additions & 1 deletion x/callback/spec/06_wasm_bindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type CallbackMsg struct {
```

The above struct is converted into the json encoded string in the following way.

```json
{"callback":{"job_id":1}}
```
Expand All @@ -28,4 +29,4 @@ The contract can request a callback by using proto msg [MsgRequestCallback](./02

## Cancelling Callback

The contract can cancel an existing callback by using proto msg [MsgCancelCallback](./02_messages.md#msgcancelcallback)
The contract can cancel an existing callback by using proto msg [MsgCancelCallback](./02_messages.md#msgcancelcallback)
2 changes: 1 addition & 1 deletion x/callback/spec/07_errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ enum ModuleErrors {
// ERR_CONTRACT_EXECUTION_FAILED is the error code when the contract callback execution fails
ERR_CONTRACT_EXECUTION_FAILED = 2;
}
```
```
10 changes: 9 additions & 1 deletion x/callback/spec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This module enables CosmWasm based smart contracts to receive callbacks at the e
Callbacks are an intent submitted by a smart contract or a contract admin or a contract owner(as set in x/rewards), which requests the protocol to execute an endpoint on the given contract for the desired height. The data structure of a callback can be found at [callback.proto](../../../proto/rollapp/callback/v1/callback.proto#L12).

The authorized user can register a callback by providing the following:

1. Contract Address - The address of the contract which will receive the callback.
2. Job ID - User given number which can be used by the contract to handle different callbacks with custom logic.
3. Callback Height - The height at which the callback will be executed.
Expand All @@ -19,17 +20,20 @@ There are three types of fees that need to be paid to register a callback.
$fees = txFee + blockFee + futureFee$

where,

* fees is the total amount of fees to be paid to register a callback
* txFee is the transaction fee. [More](#1-transaction-fees)
* blockFee is the block reservation fee. [More](#2-block-reservation-fee)
* futureFee is the future reservation fee. [More](#3-future-reservation-fee)

#### 1. Transaction Fees

As the callbacks are executed by the protocol, the computation is subsidized by the validators. To ensure that the validators receive fair compensation, the transaction fees are paid upfront when registering a callback. As the gas consumption of the callback is not known at registration time, the user has to overpay for the callback. However, post completion of callback execution, any extra tx fee is refunded.

$txFee = callbackGasLimit_{params} \times estimateFees(1)$

where,

* txFee is the total transaction fees which need to be paid
* callbackGasLimit is a module param. [More](./01_state.md)
* estimateFees is the x/rewards endpoint used to calculate the current block price of gas. [More](../../rewards/spec/07_client.md#estimate-fees)
Expand All @@ -39,27 +43,31 @@ where,
> The transaction fee to be paid at the time of registration is calculated based on the x/rewards [EstimateGasFees](../../../proto/rollapp/rewards/v1/query.proto#L39) endpoint for the current height. The refund is calculated based on the gas fees at the execution height. If the gas fee goes up enough in the duration that the tx fee provided during registration is not enough, the validators swallow the loss.
#### 2. Block Reservation Fee

This part of the fee is calculated based on how many callbacks are registered at the current block. The more filled a block's callback queue is, the more expensive it is to request further callbacks in that block.

$blockFee = count(callbacks_{currentHeight}) \times blockReservationFeeMultiplier_{params}$

where,

* blockFee is the block reservation fees which need to be paid
* count(callbacks) is the total number of callbacks already registered for the current block
* blockReservationFeeMultiplier is a module param. [More](./01_state.md)

#### 3. Future Reservation Fee

This part of the fee is calculated based on how far in the future does the user want to register their callback. The further in the future it is, the more expensive it is to request a callback.

$futureFee = (blockHeight_{callback} - blockHeight_{current}) \times futureReservationFeeMultiplier_{params}$

where,

* futureFee is the future reservation fees which need to be paid
* blockHeight is the respective height at the callback request and the current height
* futureReservationFeeMultiplier is a module param. [More](./01_state.md)

> **Note**
> Any extra fees paid, is kept as surplus fee and is refunded in case the callback is cancelled.
> Any extra fees paid, is kept as surplus fee and is refunded in case the callback is cancelled.
Post execution of a callback, all the fees are sent to the `fee_collector` account and are distributed to the validators and stakers

Expand Down
12 changes: 10 additions & 2 deletions x/cwerrors/spec/01_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Section describes all stored by the module objects and their storage keys
The params value can only be updated by x/gov module via a governance upgrade proposal. [More](./02_messages.md#msgupdateparams)

Storage keys:

* Params: `ParamsKey -> ProtocolBuffer(Params)`

```protobuf
Expand All @@ -27,20 +28,23 @@ message Params {
ErrorID is a sequence number used to increment error ID.

Storage keys:

* ErrorID: `ErrorIDKey -> uint64`

## Contract Errors

Contract Errors is a collection of all the error ids associated with a given contract address. This is used to query contract errors.

Storage keys:

* ContractErrors: `ContractErrorsKeyPrefix | contractAddress | errorID -> errorID`

## Errors

Errors is a collections of all the [SudoErrors](../../../proto/rollapp/cwerrors/v1/cwerrors.proto) currently stored by the module which can be queried.

Storage keys:

* Errors: `ErrorsKeyPrefix | errorID -> protobuf(SudoError)`

```protobuf
Expand All @@ -63,25 +67,29 @@ message SudoError {
Deletion Blocks is a collection of all the error ids which need to be pruned in a given block height

Storage keys:

* DeletionBlocks: `DeletionBlocksKeyPrefix | blockHeight | errorID -> errorID`

## Contract Subscriptions

Contract Subscriptions is a map of the contract addresses which have subscriptions and the height when the subscription expires

Storage keys:

* Contract Subscriptions: `ContractSubscriptionsKeyPrefix | contractAddress -> deletionHeight`

## Subscription End Block

Subscritption End Block is a collections of all the subscriptions which need to be cleared at the given block height

Storage keys:

* Subscription End Block: `SubscriptionEndBlockKeyPrefix | blockHeight | contractAddress -> contractAddress`

# Transient State
## Transient State

The sudo errors which belong to the contracts with subscription are stored in the transient state of the block.

Transient Storage keys:
* SudoErrors: `ErrorsForSudoCallbackKey | errorId -> SudoError`

* SudoErrors: `ErrorsForSudoCallbackKey | errorId -> SudoError`
4 changes: 3 additions & 1 deletion x/cwerrors/spec/02_messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ message MsgSubscribeToError {
```

On success

* A subscription is created valid for the duration as specified in the module params.
* The subscription fees are sent to the fee collector
* In case a subscription already exists, it is extended.

This message is expected to fail if:

* The sender address and contract address are not valid addresses
* There is no contract with given address
* The sender is not authorized to subscribe - the sender is not the contract owner/admin or the contract itself
* The user does not send enough funds or doesnt have enough funds
* The user does not send enough funds or doesnt have enough funds
2 changes: 1 addition & 1 deletion x/cwerrors/spec/04_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ The module emits the following proto-events
| Message | `MsgUpdateParams` | [ParamsUpdatedEvent](../../../proto/rollapp/cwerrors/v1/events.proto#L12) |
| Message | `MsgSubscribeToError` | [SubscribedToErrorsEvent](../../../proto/rollapp/cwerrors/v1/events.proto#L20) |
| Keeper | `SetErrorInState` | [StoringErrorEvent](../../../proto/rollapp/cwerrors/v1/events.proto#L32) |
| Module | `EndBlocker` | [SudoErrorCallbackFailedEvent](../../../proto/rollapp/cwerrors/v1/events.proto#L40) |
| Module | `EndBlocker` | [SudoErrorCallbackFailedEvent](../../../proto/rollapp/cwerrors/v1/events.proto#L40) |
5 changes: 2 additions & 3 deletions x/cwerrors/spec/05_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,14 @@ Use the `-h`/`--help` flag to get a help description of a command.

`rollapp-wasm tx cwerrors -h`


#### subscribe-to-error

Create a new subscription which will register a contract for a sudo callback on errors

Usage:
Usage:

`rollapp-wasm tx cwerrors subscribe-to-error [contract-address] [fee-amount] [flags]`

Example:

`rollapp-wasm tx cwerrors subscribe-to-error cosmos1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtqukxvuk 7000stake --from myAccountKey`
`rollapp-wasm tx cwerrors subscribe-to-error cosmos1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtqukxvuk 7000stake --from myAccountKey`
Loading

0 comments on commit d6e15ba

Please sign in to comment.