diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml index 45ac6f0f609..95665e2e9a7 100644 --- a/.github/workflows/sims.yml +++ b/.github/workflows/sims.yml @@ -88,7 +88,7 @@ jobs: needs: [test-sim-multi-seed-short, test-sim-after-import, test-sim-import-export] runs-on: ubuntu-latest - if: ${{ success() }} + if: ${{ false }} # Disabled due to requiring Slack integration steps: - name: Check out repository uses: actions/checkout@v3 @@ -116,7 +116,7 @@ jobs: needs: [test-sim-multi-seed-short, test-sim-after-import, test-sim-import-export] runs-on: ubuntu-latest - if: ${{ failure() }} + if: ${{ false }} # Disabled due to requiring Slack integration steps: - name: Notify Slack on failure uses: rtCamp/action-slack-notify@v2.2.0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 76fa60202e4..4be37422ee4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -142,6 +142,7 @@ jobs: path: ./tests/e2e-profile.out repo-analysis: + if: ${{ false }} # Disabled due to requiring SonarCloud integration runs-on: ubuntu-latest needs: [tests, test-integration, test-e2e] steps: @@ -181,7 +182,7 @@ jobs: name: "${{ github.sha }}-e2e-coverage" continue-on-error: true - name: sonarcloud - if: env.GIT_DIFF + if: env.GIT_DIFF && secrets.SONAR_TOKEN uses: SonarSource/sonarcloud-github-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -272,7 +273,7 @@ jobs: cd simapp go test -mod=readonly -timeout 30m -tags='app_v1 norace ledger test_ledger_mock rocksdb_build' ./... - name: sonarcloud - if: env.GIT_DIFF + if: env.GIT_DIFF && secrets.SONAR_TOKEN uses: SonarSource/sonarcloud-github-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index ee572bbe0c1..94764c3a14f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,43 @@ +# dYdX Fork of CosmosSDK + +This is a lightweight fork of CosmosSDK. The current version of the forked code resides on the [default branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches#about-the-default-branch). + +## Making Changes to the Fork + +1. Open a PR against the current default branch (i.e. `dydx-fork-v0.47.1`). +2. Get approval, and merge. *DO NOT SQUASH AND MERGE. PLEASE REBASE AND MERGE* +3. After merging, update the `v4` repository's `go.mod`, and `go.sum` files with your merged `$COMMIT_HASH`. +4. (In `dydxprotocol/v4`) `go mod edit -replace github.com/cosmos/cosmos-sdk=github.com/dydxprotocol/cosmos-sdk@$COMMIT_HASH` +5. (In `dydxprotocol/v4`) `go mod tidy` +6. (In `dydxprotocol/v4`) update package references in `mocks/Makefile`. See [here](https://github.com/dydxprotocol/v4/pull/848) for an example. +7. Open a PR in `dydxprotocol/v4` to bump the version of the fork. + +## Fork maintenance + +We'd like to keep the `main` branch up to date with `cosmos/cosmos-sdk`. You can utilize GitHub's [sync fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork) button to accomplish this. ⚠️ Please only use this on the `main` branch, not on the fork branches as it will discard our commits.⚠️ + +Before these steps, please set the `upstream` remote to be the `cosmos/cosmos-sdk` repo. If you use http auth, you will have to switch the upstream url to be http. +`git remote add upstream git@github.com:cosmos/cosmos-sdk.git` + +Note that this doesn't pull in upstream tags, so in order to do this follow these steps: +1. `git fetch upstream` +2. `git push --tags` + +## Updating CosmosSDK to new versions + +When a new version of CosmosSDK is published, we may want to adopt the changes in our fork. This process can be somewhat tedious, but below are the recommended steps to accomplish this. + +1. Ensure the `main` branch and all tags are up to date by following the steps above in "Fork maintenance". +2. Create a new branch off the desired CosmosSDK commit using tags. `git checkout -b dydx-fork-$VERSION `. The new branch should be named something like `dydx-fork-$VERSION` where `$VERSION` is the version of CosmosSDK being forked (should match the CosmosSDK repo's tag name). i.e. `dydx-fork-v0.47.1`. +3. Push the new branch (i.e `dydx-fork-v0.47.1`). +4. Off of this new branch, create a new branch. (i.e `totoro/dydxCommits`) +5. Cherry-pick each dydx-created commit from the current default branch, in order, on to the new `dydx-fork-$VERSION` branch (note: you may want to consider creating multiple PRs for this process if there are difficulties or merge conflicts). For example, `git cherry-pick `. You can verify the first commit by seeing the most recent commit sha for the `$VERSION` (i.e `v0.47.1`) tag on the `cosmos/cosmos-sdk` repo, and taking the next commit from that sha. +6. Open a PR to merge the second branch (`totoro/dydxCommits`) into the first (`dydx-fork-v0.47.1`). Get approval, and merge. *DO NOT SQUASH AND MERGE. PLEASE REBASE AND MERGE* +7. Update `dydxprotocol/v4` by following the steps in "Making Changes to the fork" above. +8. Set `dydx-fork-$VERSION` as the [default branch](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/changing-the-default-branch) in this repository. + +Note that the github CI workflows need permissioning. If they fail with a permissioning error, i.e `Resource not accessible through integration`, a Github admin will need to whitelist the workflow. +

Cosmos SDK

diff --git a/baseapp/abci.go b/baseapp/abci.go index 32a6d868322..7b850ee06f1 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -35,6 +35,9 @@ const ( // InitChain implements the ABCI interface. It runs the initialization logic // directly on the CommitMultiStore. func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain) { + app.mtx.Lock() + defer app.mtx.Unlock() + if req.ChainId != app.chainID { panic(fmt.Sprintf("invalid chain-id on InitChain; expected: %s, got: %s", app.chainID, req.ChainId)) } @@ -68,6 +71,16 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC app.StoreConsensusParams(app.deliverState.ctx, req.ConsensusParams) } + defer func() { + // InitChain represents the state of the application BEFORE the first block, + // i.e. the genesis block. This means that when processing the app's InitChain + // handler, the block height is zero by default. However, after Commit is called + // the height needs to reflect the true block height. + initHeader.Height = req.InitialHeight + app.checkState.ctx = app.checkState.ctx.WithBlockHeader(initHeader) + app.deliverState.ctx = app.deliverState.ctx.WithBlockHeader(initHeader) + }() + if app.initChainer == nil { return } @@ -110,8 +123,8 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC appHash = emptyHash[:] } - // NOTE: We don't commit, but BeginBlock for block `initial_height` starts from this - // deliverState. + // NOTE: We don't commit, but BeginBlock for block InitialHeight starts from + // this deliverState. return abci.ResponseInitChain{ ConsensusParams: res.ConsensusParams, Validators: res.Validators, @@ -121,6 +134,9 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC // Info implements the ABCI interface. func (app *BaseApp) Info(req abci.RequestInfo) abci.ResponseInfo { + app.mtx.Lock() + defer app.mtx.Unlock() + lastCommitID := app.cms.LastCommitID() return abci.ResponseInfo{ @@ -152,6 +168,9 @@ func (app *BaseApp) FilterPeerByID(info string) abci.ResponseQuery { // BeginBlock implements the ABCI application interface. func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) { + app.mtx.Lock() + defer app.mtx.Unlock() + if req.Header.ChainID != app.chainID { panic(fmt.Sprintf("invalid chain-id on BeginBlock; expected: %s, got: %s", app.chainID, req.Header.ChainID)) } @@ -211,6 +230,9 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg // EndBlock implements the ABCI interface. func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBlock) { + app.mtx.Lock() + defer app.mtx.Unlock() + if app.deliverState.ms.TracingEnabled() { app.deliverState.ms = app.deliverState.ms.SetTracingContext(nil).(sdk.CacheMultiStore) } @@ -248,6 +270,9 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/tendermint/tendermint/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci.ResponsePrepareProposal) { + app.mtx.Lock() + defer app.mtx.Unlock() + if app.prepareProposal == nil { panic("PrepareProposal method not set") } @@ -305,6 +330,9 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci. // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/tendermint/tendermint/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) (resp abci.ResponseProcessProposal) { + app.mtx.Lock() + defer app.mtx.Unlock() + if app.processProposal == nil { panic("app.ProcessProposal is not set") } @@ -367,7 +395,7 @@ func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { panic(fmt.Sprintf("unknown RequestCheckTx type: %s", req.Type)) } - gInfo, result, anteEvents, priority, err := app.runTx(mode, req.Tx) + gInfo, result, anteEvents, priority, err := app.runCheckTxConcurrently(mode, req.Tx) if err != nil { return sdkerrors.ResponseCheckTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace) } @@ -388,6 +416,18 @@ func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { // Regardless of tx execution outcome, the ResponseDeliverTx will contain relevant // gas execution context. func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliverTx) { + return app.DeliverTxShouldLock(req, true) +} + +// DeliverTxShouldLock enables control of whether the lock should be acquired. The golang mutex +// is not reentrant so we enable conditional locking to prevent deadlock since cosmos-sdk/x/genutil.InitGenesis +// invokes DeliverTx from the ABCI++ InitGenesis method which already holds the lock. +func (app *BaseApp) DeliverTxShouldLock(req abci.RequestDeliverTx, needsLock bool) (res abci.ResponseDeliverTx) { + if needsLock { + app.mtx.Lock() + defer app.mtx.Unlock() + } + gInfo := sdk.GasInfo{} resultStr := "successful" @@ -429,6 +469,9 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliv // against that height and gracefully halt if it matches the latest committed // height. func (app *BaseApp) Commit() abci.ResponseCommit { + app.mtx.Lock() + defer app.mtx.Unlock() + header := app.deliverState.ctx.BlockHeader() retainHeight := app.GetBlockRetentionHeight(header.Height) @@ -466,6 +509,10 @@ func (app *BaseApp) Commit() abci.ResponseCommit { // empty/reset the deliver state app.deliverState = nil + if app.commiter != nil { + app.commiter(app.checkState.ctx) + } + var halt bool switch { @@ -514,6 +561,9 @@ func (app *BaseApp) halt() { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { + app.mtx.Lock() + defer app.mtx.Unlock() + // Add panic recovery for all queries. // ref: https://github.com/cosmos/cosmos-sdk/pull/8039 defer func() { @@ -563,6 +613,9 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { // ListSnapshots implements the ABCI interface. It delegates to app.snapshotManager if set. func (app *BaseApp) ListSnapshots(req abci.RequestListSnapshots) abci.ResponseListSnapshots { + app.mtx.Lock() + defer app.mtx.Unlock() + resp := abci.ResponseListSnapshots{Snapshots: []*abci.Snapshot{}} if app.snapshotManager == nil { return resp @@ -588,6 +641,9 @@ func (app *BaseApp) ListSnapshots(req abci.RequestListSnapshots) abci.ResponseLi // LoadSnapshotChunk implements the ABCI interface. It delegates to app.snapshotManager if set. func (app *BaseApp) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abci.ResponseLoadSnapshotChunk { + app.mtx.Lock() + defer app.mtx.Unlock() + if app.snapshotManager == nil { return abci.ResponseLoadSnapshotChunk{} } @@ -607,6 +663,9 @@ func (app *BaseApp) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abci.Re // OfferSnapshot implements the ABCI interface. It delegates to app.snapshotManager if set. func (app *BaseApp) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOfferSnapshot { + app.mtx.Lock() + defer app.mtx.Unlock() + if app.snapshotManager == nil { app.logger.Error("snapshot manager not configured") return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT} @@ -656,6 +715,9 @@ func (app *BaseApp) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOf // ApplySnapshotChunk implements the ABCI interface. It delegates to app.snapshotManager if set. func (app *BaseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.ResponseApplySnapshotChunk { + app.mtx.Lock() + defer app.mtx.Unlock() + if app.snapshotManager == nil { app.logger.Error("snapshot manager not configured") return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ABORT} diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 61f8a7d551f..9349d149ed5 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - dbm "github.com/cometbft/cometbft-db" abci "github.com/cometbft/cometbft/abci/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + dbm "github.com/cometbft/cometbft-db" "github.com/cosmos/gogoproto/jsonpb" "github.com/stretchr/testify/require" @@ -39,6 +39,21 @@ func TestABCI_Info(t *testing.T) { require.Equal(t, suite.baseApp.AppVersion(), res.AppVersion) } +func TestABCI_First_block_Height(t *testing.T) { + suite := NewBaseAppSuite(t, baseapp.SetChainID("test-chain-id")) + app := suite.baseApp + + app.InitChain(abci.RequestInitChain{ + ChainId: "test-chain-id", + ConsensusParams: &cmtproto.ConsensusParams{Block: &cmtproto.BlockParams{MaxGas: 5000000}}, + InitialHeight: 1, + }) + _ = app.Commit() + + ctx := app.GetContextForCheckTx(nil) + require.Equal(t, int64(1), ctx.BlockHeight()) +} + func TestABCI_InitChain(t *testing.T) { name := t.Name() db := dbm.NewMemDB() @@ -596,6 +611,33 @@ func TestABCI_EndBlock(t *testing.T) { require.Equal(t, cp.Block.MaxGas, res.ConsensusParamUpdates.Block.MaxGas) } +func TestBaseApp_Commit(t *testing.T) { + db := dbm.NewMemDB() + name := t.Name() + logger := defaultLogger() + + cp := &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ + MaxGas: 5000000, + }, + } + + app := baseapp.NewBaseApp(name, logger, db, nil) + app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) + app.InitChain(abci.RequestInitChain{ + ConsensusParams: cp, + }) + + wasCommiterCalled := false + app.SetCommiter(func(ctx sdk.Context) { + wasCommiterCalled = true + }) + app.Seal() + + app.Commit() + require.Equal(t, true, wasCommiterCalled) +} + func TestABCI_CheckTx(t *testing.T) { // This ante handler reads the key and checks that the value matches the // current counter. This ensures changes to the KVStore persist across @@ -1320,6 +1362,28 @@ func TestABCI_GetBlockRetentionHeight(t *testing.T) { } } +// Verifies that the Commiter is called with the checkState. +func TestCommiterCalledWithCheckState(t *testing.T) { + t.Parallel() + + logger := defaultLogger() + db := dbm.NewMemDB() + name := t.Name() + app := baseapp.NewBaseApp(name, logger, db, nil) + + wasCommiterCalled := false + app.SetCommiter(func(ctx sdk.Context) { + // Make sure context is for next block + require.Equal(t, true, ctx.IsCheckTx()) + wasCommiterCalled = true + }) + + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 1}}) + app.Commit() + + require.Equal(t, true, wasCommiterCalled) +} + func TestABCI_Proposal_HappyPath(t *testing.T) { anteKey := []byte("ante-key") pool := mempool.NewSenderNonceMempool() diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 3a90eaf2b81..4214fe1f98c 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -5,6 +5,7 @@ import ( "fmt" "sort" "strings" + "sync" dbm "github.com/cometbft/cometbft-db" abci "github.com/cometbft/cometbft/abci/types" @@ -68,6 +69,7 @@ type BaseApp struct { //nolint: maligned processProposal sdk.ProcessProposalHandler // the handler which runs on ABCI ProcessProposal prepareProposal sdk.PrepareProposalHandler // the handler which runs on ABCI PrepareProposal endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes + commiter sdk.Commiter // logic to run during commit addrPeerFilter sdk.PeerFilter // filter peers by address and port idPeerFilter sdk.PeerFilter // filter peers by node ID fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed. @@ -144,6 +146,9 @@ type BaseApp struct { //nolint: maligned abciListeners []ABCIListener chainID string + + // Used to synchronize the application when using an unsynchronized ABCI++ client. + mtx sync.Mutex } // NewBaseApp returns a reference to an initialized BaseApp. It accepts a @@ -614,6 +619,141 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context return ctx.WithMultiStore(msCache), msCache } +// runCheckTxConcurrently processes a transaction with either the checkTx or recheckTx modes, encoded transaction +// bytes, and the decoded transaction itself. All state transitions occur through +// a cached Context depending on the mode provided. +// +// Note, gas execution info is always returned. A reference to a Result is +// returned if the tx does not run out of gas and if all the messages are valid +// and execute successfully. An error is returned otherwise. +func (app *BaseApp) runCheckTxConcurrently(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, priority int64, err error) { + if mode != runTxModeCheck && mode != runTxModeReCheck { + panic("runCheckTxConcurrently can only be invoked for CheckTx and RecheckTx.") + } + + // Strip out the post handler + if app.postHandler != nil { + panic("CheckTx/RecheckTx does not support a post hander.") + } + + // NOTE: GasWanted should be returned by the AnteHandler. GasUsed is + // determined by the GasMeter. We need access to the context to get the gas + // meter, so we initialize upfront. + var gasWanted uint64 + + tx, err := app.txDecoder(txBytes) + if err != nil { + return sdk.GasInfo{}, nil, nil, 0, err + } + + msgs := tx.GetMsgs() + if err := validateBasicTxMsgs(msgs); err != nil { + return sdk.GasInfo{}, nil, nil, 0, err + } + + // Execute the critical section under lock. + // + // Note that careful consideration is needed in the block below to ensure that we don't redefine + // gInfo, result, anteEvents, priority, or err local variables. Also note that this function is + // embedded here to ensure that the lifetime of the mutex is limited to only this function allowing + // for the return values to be computed without holding the lock. + func() { + app.mtx.Lock() + defer app.mtx.Unlock() + + ctx := app.getContextForTx(mode, txBytes) + ms := ctx.MultiStore() + + defer func() { + if r := recover(); r != nil { + recoveryMW := newOutOfGasRecoveryMiddleware(gasWanted, ctx, app.runTxRecoveryMiddleware) + err, result = processRecovery(r, recoveryMW), nil + } + + gInfo = sdk.GasInfo{GasWanted: gasWanted, GasUsed: ctx.GasMeter().GasConsumed()} + }() + + if app.anteHandler != nil { + var ( + anteCtx sdk.Context + msCache sdk.CacheMultiStore + newCtx sdk.Context + ) + + // Branch context before AnteHandler call in case it aborts. + // This is required for both CheckTx and DeliverTx. + // Ref: https://github.com/cosmos/cosmos-sdk/issues/2772 + // + // NOTE: Alternatively, we could require that AnteHandler ensures that + // writes do not happen if aborted/failed. This may have some + // performance benefits, but it'll be more difficult to get right. + anteCtx, msCache = app.cacheTxContext(ctx, txBytes) + anteCtx = anteCtx.WithEventManager(sdk.NewEventManager()) + newCtx, err = app.anteHandler(anteCtx, tx, mode == runTxModeSimulate) + + if !newCtx.IsZero() { + // At this point, newCtx.MultiStore() is a store branch, or something else + // replaced by the AnteHandler. We want the original multistore. + // + // Also, in the case of the tx aborting, we need to track gas consumed via + // the instantiated gas meter in the AnteHandler, so we update the context + // prior to returning. + ctx = newCtx.WithMultiStore(ms) + } + + events := ctx.EventManager().Events() + + // GasMeter expected to be set in AnteHandler + gasWanted = ctx.GasMeter().Limit() + + if err != nil { + // Note that we set the outputs here and return from the critical function back into + // runCheckTxConcurrently which will check `err` and return immediately. + result = nil + anteEvents = nil + priority = 0 + return + } + + priority = ctx.Priority() + msCache.Write() + anteEvents = events.ToABCIEvents() + } + + if mode == runTxModeCheck { + err = app.mempool.Insert(ctx, tx) + if err != nil { + result = nil + return + } + } + }() + if err != nil { + return gInfo, result, anteEvents, priority, err + } + + // Execute a stripped down version of runMsgs that is only used for CheckTx and RecheckTx + var msgResponses []*codectypes.Any + data, err := makeABCIData(msgResponses) + if err != nil { + return gInfo, result, anteEvents, priority, sdkerrors.Wrap(err, "failed to marshal tx data") + } + + msgLogs := make(sdk.ABCIMessageLogs, 0, len(msgs)) + result = &sdk.Result{ + Data: data, + Log: strings.TrimSpace(msgLogs.String()), + Events: sdk.EmptyEvents().ToABCIEvents(), + MsgResponses: msgResponses, + } + + // We don't support the post handler specifically to avoid creating a branched MultiStore and since dYdX + // doesn't need support for it. Once support is necessary or when we are trying to upstream these changes + // we can guard creation of the MultiStore to only occur when the post handler is specified. + + return gInfo, result, anteEvents, priority, err +} + // runTx processes a transaction within a given execution mode, encoded transaction // bytes, and the decoded transaction itself. All state transitions occur through // a cached Context depending on the mode provided. State only gets persisted @@ -622,6 +762,10 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context // returned if the tx does not run out of gas and if all the messages are valid // and execute successfully. An error is returned otherwise. func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, priority int64, err error) { + if mode == runTxModeCheck || mode == runTxModeReCheck { + panic("Expected CheckTx and RecheckTx to be executed via runCheckTxConcurrently") + } + // NOTE: GasWanted should be returned by the AnteHandler. GasUsed is // determined by the GasMeter. We need access to the context to get the gas // meter, so we initialize upfront. diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index a821ca1e445..7cba6f1753d 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -390,6 +390,9 @@ func TestBaseAppOptionSeal(t *testing.T) { require.Panics(t, func() { suite.baseApp.SetEndBlocker(nil) }) + require.Panics(t, func() { + suite.baseApp.SetCommiter(nil) + }) require.Panics(t, func() { suite.baseApp.SetAnteHandler(nil) }) diff --git a/baseapp/options.go b/baseapp/options.go index e669495f647..9a9bb4eba81 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -166,6 +166,14 @@ func (app *BaseApp) SetEndBlocker(endBlocker sdk.EndBlocker) { app.endBlocker = endBlocker } +func (app *BaseApp) SetCommiter(commiter sdk.Commiter) { + if app.sealed { + panic("SetCommiter() on sealed BaseApp") + } + + app.commiter = commiter +} + func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) { if app.sealed { panic("SetAnteHandler() on sealed BaseApp") diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index a8ecee084d5..7b100e24959 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -16,7 +16,7 @@ func (app *BaseApp) SimCheck(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, * if err != nil { return sdk.GasInfo{}, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, _, err := app.runTx(runTxModeCheck, bz) + gasInfo, result, _, _, err := app.runCheckTxConcurrently(runTxModeCheck, bz) return gasInfo, result, err } @@ -53,3 +53,7 @@ func (app *BaseApp) NewUncachedContext(isCheckTx bool, header tmproto.Header) sd func (app *BaseApp) GetContextForDeliverTx(txBytes []byte) sdk.Context { return app.getContextForTx(runTxModeDeliver, txBytes) } + +func (app *BaseApp) GetContextForCheckTx(txBytes []byte) sdk.Context { + return app.getContextForTx(runTxModeCheck, txBytes) +} diff --git a/go.mod b/go.mod index 1914ca20b33..632a1f0b195 100644 --- a/go.mod +++ b/go.mod @@ -194,3 +194,5 @@ retract ( // do not use v0.43.0 ) + +replace github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-bc5c0e0243ac diff --git a/go.sum b/go.sum index ff5d5848d83..9cc7abf80de 100644 --- a/go.sum +++ b/go.sum @@ -309,8 +309,6 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.37.1 h1:KLxkQTK2hICXYq21U2hn1W5hOVYUdQgDQ1uB+90xPIg= -github.com/cometbft/cometbft v0.37.1/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= @@ -379,6 +377,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-bc5c0e0243ac h1:OJojXWgxMUhuGvn/p6fhzC1yV75JiKrO8y81cWkIlzY= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-bc5c0e0243ac/go.mod h1:cpghf0+1GJpJvrqpTHE6UyTcD05m/xllo0xpufL3PgA= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= diff --git a/runtime/module.go b/runtime/module.go index ed3b5c8c71e..5cb3ff18c00 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -136,8 +136,10 @@ func ProvideMemoryStoreKey(key depinject.ModuleKey, app *AppBuilder) *storetypes return storeKey } -func ProvideDeliverTx(appBuilder *AppBuilder) func(abci.RequestDeliverTx) abci.ResponseDeliverTx { - return func(tx abci.RequestDeliverTx) abci.ResponseDeliverTx { - return appBuilder.app.BaseApp.DeliverTx(tx) +// We modify this method explicitly to require an additional parameter so that any additional usages +// will be audited to ensure that the usage of the function is already holding the baseapp mutex lock. +func ProvideDeliverTx(appBuilder *AppBuilder) func(abci.RequestDeliverTx, bool) abci.ResponseDeliverTx { + return func(tx abci.RequestDeliverTx, needsLock bool) abci.ResponseDeliverTx { + return appBuilder.app.BaseApp.DeliverTxShouldLock(tx, needsLock) } } diff --git a/server/start.go b/server/start.go index 061b736cf6a..f3f4f657d67 100644 --- a/server/start.go +++ b/server/start.go @@ -321,7 +321,7 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App cfg, pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()), nodeKey, - proxy.NewLocalClientCreator(app), + proxy.NewUnsynchronizedLocalClientCreator(app), genDocProvider, node.DefaultDBProvider, node.DefaultMetricsProvider(cfg.Instrumentation), diff --git a/server/util.go b/server/util.go index 0d88fb19095..6049ef61c36 100644 --- a/server/util.go +++ b/server/util.go @@ -234,8 +234,10 @@ func interceptConfigs(rootViper *viper.Viper, customAppTemplate string, customCo } defaultCometCfg := tmcfg.DefaultConfig() - // The SDK is opinionated about those comet values, so we set them here. - // We verify first that the user has not changed them for not overriding them. + // Use the same logic from latest cosmos-sdk: only set the `timeout_commit` value + // if it has not been overridden by the user. This allows the application to + // pass in a custom `timeout_commit` value. + // Source: https://github.com/cosmos/cosmos-sdk/blob/a827f42ae34ded4daa4b523b615b493e1b0b180d/server/util.go#L253-L255 if conf.Consensus.TimeoutCommit == defaultCometCfg.Consensus.TimeoutCommit { conf.Consensus.TimeoutCommit = 5 * time.Second } diff --git a/simapp/app.go b/simapp/app.go index 078bda01933..ab7f3ba9892 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -396,7 +396,7 @@ func NewSimApp( // must be passed by reference here. app.ModuleManager = module.NewManager( genutil.NewAppModule( - app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, + app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTxShouldLock, encodingConfig.TxConfig, ), auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), diff --git a/simapp/go.mod b/simapp/go.mod index 7a2315dd682..7e81b633db5 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -173,3 +173,5 @@ replace ( // replace broken goleveldb github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 ) + +replace github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a diff --git a/simapp/go.sum b/simapp/go.sum index 896f6661b07..8ffef7a92b9 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -308,8 +308,6 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.37.1 h1:KLxkQTK2hICXYq21U2hn1W5hOVYUdQgDQ1uB+90xPIg= -github.com/cometbft/cometbft v0.37.1/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= @@ -377,6 +375,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a h1:OjTAQDrBzoHoRqYXCEDwrQk8RUn93dhd3uJ58W7H4Mo= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a/go.mod h1:cpghf0+1GJpJvrqpTHE6UyTcD05m/xllo0xpufL3PgA= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= diff --git a/telemetry/wrapper.go b/telemetry/wrapper.go index e6542df86e1..fa6aae10221 100644 --- a/telemetry/wrapper.go +++ b/telemetry/wrapper.go @@ -11,6 +11,7 @@ const ( MetricKeyBeginBlocker = "begin_blocker" MetricKeyEndBlocker = "end_blocker" MetricLabelNameModule = "module" + MetricKeyCommit = "commit" ) // NewLabel creates a new instance of Label with name and value diff --git a/tests/go.mod b/tests/go.mod index dfc4f7a7776..0b2b7ed5026 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -174,3 +174,5 @@ replace ( // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0 ) + +replace github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a diff --git a/tests/go.sum b/tests/go.sum index 23b319b8815..e980fbf144a 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -308,8 +308,6 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.37.1 h1:KLxkQTK2hICXYq21U2hn1W5hOVYUdQgDQ1uB+90xPIg= -github.com/cometbft/cometbft v0.37.1/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= @@ -377,6 +375,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a h1:OjTAQDrBzoHoRqYXCEDwrQk8RUn93dhd3uJ58W7H4Mo= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a/go.mod h1:cpghf0+1GJpJvrqpTHE6UyTcD05m/xllo0xpufL3PgA= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= diff --git a/tests/integration/genutil/gentx_test.go b/tests/integration/genutil/gentx_test.go index 9562fd6b24e..588adec9f12 100644 --- a/tests/integration/genutil/gentx_test.go +++ b/tests/integration/genutil/gentx_test.go @@ -293,13 +293,13 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { if tc.expPass { suite.Require().NotPanics(func() { genutil.DeliverGenTxs( - suite.ctx, genTxs, suite.stakingKeeper, suite.baseApp.DeliverTx, + suite.ctx, genTxs, suite.stakingKeeper, suite.baseApp.DeliverTxShouldLock, suite.encodingConfig.TxConfig, ) }) } else { _, err := genutil.DeliverGenTxs( - suite.ctx, genTxs, suite.stakingKeeper, suite.baseApp.DeliverTx, + suite.ctx, genTxs, suite.stakingKeeper, suite.baseApp.DeliverTxShouldLock, suite.encodingConfig.TxConfig, ) diff --git a/testutil/mock/types_module_module.go b/testutil/mock/types_module_module.go index 8b3a79c80fa..ca77ba57f18 100644 --- a/testutil/mock/types_module_module.go +++ b/testutil/mock/types_module_module.go @@ -879,3 +879,116 @@ func (mr *MockEndBlockAppModuleMockRecorder) RegisterLegacyAminoCodec(arg0 inter mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockEndBlockAppModule)(nil).RegisterLegacyAminoCodec), arg0) } + +// MockCommitAppModule is a mock of CommitAppModule interface. +type MockCommitAppModule struct { + ctrl *gomock.Controller + recorder *MockCommitAppModuleMockRecorder +} + +// MockCommitAppModuleMockRecorder is the mock recorder for MockCommitAppModule. +type MockCommitAppModuleMockRecorder struct { + mock *MockCommitAppModule +} + +// NewMockCommitAppModule creates a new mock instance. +func NewMockCommitAppModule(ctrl *gomock.Controller) *MockCommitAppModule { + mock := &MockCommitAppModule{ctrl: ctrl} + mock.recorder = &MockCommitAppModuleMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCommitAppModule) EXPECT() *MockCommitAppModuleMockRecorder { + return m.recorder +} + +// Commit mocks base method. +func (m *MockCommitAppModule) Commit(arg0 types1.Context) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Commit", arg0) +} + +// Commit indicates an expected call of Commit. +func (mr *MockCommitAppModuleMockRecorder) Commit(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockCommitAppModule)(nil).Commit), arg0) +} + +// GetQueryCmd mocks base method. +func (m *MockCommitAppModule) GetQueryCmd() *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQueryCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetQueryCmd indicates an expected call of GetQueryCmd. +func (mr *MockCommitAppModuleMockRecorder) GetQueryCmd() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockCommitAppModule)(nil).GetQueryCmd)) +} + +// GetTxCmd mocks base method. +func (m *MockCommitAppModule) GetTxCmd() *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTxCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetTxCmd indicates an expected call of GetTxCmd. +func (mr *MockCommitAppModuleMockRecorder) GetTxCmd() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockCommitAppModule)(nil).GetTxCmd)) +} + +// Name mocks base method. +func (m *MockCommitAppModule) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name. +func (mr *MockCommitAppModuleMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockCommitAppModule)(nil).Name)) +} + +// RegisterGRPCGatewayRoutes mocks base method. +func (m *MockCommitAppModule) RegisterGRPCGatewayRoutes(arg0 client.Context, arg1 *runtime.ServeMux) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterGRPCGatewayRoutes", arg0, arg1) +} + +// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes. +func (mr *MockCommitAppModuleMockRecorder) RegisterGRPCGatewayRoutes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCGatewayRoutes", reflect.TypeOf((*MockCommitAppModule)(nil).RegisterGRPCGatewayRoutes), arg0, arg1) +} + +// RegisterInterfaces mocks base method. +func (m *MockCommitAppModule) RegisterInterfaces(arg0 types0.InterfaceRegistry) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterInterfaces", arg0) +} + +// RegisterInterfaces indicates an expected call of RegisterInterfaces. +func (mr *MockCommitAppModuleMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockCommitAppModule)(nil).RegisterInterfaces), arg0) +} + +// RegisterLegacyAminoCodec mocks base method. +func (m *MockCommitAppModule) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) +} + +// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec. +func (mr *MockCommitAppModuleMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockCommitAppModule)(nil).RegisterLegacyAminoCodec), arg0) +} diff --git a/testutil/network/util.go b/testutil/network/util.go index 24ad548f941..b7e7e7475ac 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -45,7 +45,7 @@ func startInProcess(cfg Config, val *Validator) error { tmCfg, pvm.LoadOrGenFilePV(tmCfg.PrivValidatorKeyFile(), tmCfg.PrivValidatorStateFile()), nodeKey, - proxy.NewLocalClientCreator(app), + proxy.NewUnsynchronizedLocalClientCreator(app), genDocProvider, node.DefaultDBProvider, node.DefaultMetricsProvider(tmCfg.Instrumentation), diff --git a/tools/cosmovisor/go.mod b/tools/cosmovisor/go.mod index cb0102a8df4..db490790008 100644 --- a/tools/cosmovisor/go.mod +++ b/tools/cosmovisor/go.mod @@ -140,3 +140,5 @@ require ( pgregory.net/rapid v0.5.5 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +replace github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a diff --git a/tools/cosmovisor/go.sum b/tools/cosmovisor/go.sum index 3fae4718202..6bce3be452c 100644 --- a/tools/cosmovisor/go.sum +++ b/tools/cosmovisor/go.sum @@ -267,8 +267,6 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= -github.com/cometbft/cometbft v0.37.0 h1:M005vBaSaugvYYmNZwJOopynQSjwLoDTwflnQ/I/eYk= -github.com/cometbft/cometbft v0.37.0/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= @@ -321,6 +319,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a h1:OjTAQDrBzoHoRqYXCEDwrQk8RUn93dhd3uJ58W7H4Mo= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a/go.mod h1:cpghf0+1GJpJvrqpTHE6UyTcD05m/xllo0xpufL3PgA= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= diff --git a/tools/rosetta/go.mod b/tools/rosetta/go.mod index 95dec28e33d..4fb5a655ea7 100644 --- a/tools/rosetta/go.mod +++ b/tools/rosetta/go.mod @@ -115,3 +115,5 @@ require ( pgregory.net/rapid v0.5.5 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +replace github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a diff --git a/tools/rosetta/go.sum b/tools/rosetta/go.sum index 7deba08476d..a1046c636a2 100644 --- a/tools/rosetta/go.sum +++ b/tools/rosetta/go.sum @@ -102,8 +102,6 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.37.1 h1:KLxkQTK2hICXYq21U2hn1W5hOVYUdQgDQ1uB+90xPIg= -github.com/cometbft/cometbft v0.37.1/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= @@ -156,6 +154,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a h1:OjTAQDrBzoHoRqYXCEDwrQk8RUn93dhd3uJ58W7H4Mo= +github.com/dydxprotocol/cometbft v0.37.2-0.20230703183317-3b10b8dfd96a/go.mod h1:cpghf0+1GJpJvrqpTHE6UyTcD05m/xllo0xpufL3PgA= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= diff --git a/types/abci.go b/types/abci.go index ebae95e92c3..f9d9e2dd897 100644 --- a/types/abci.go +++ b/types/abci.go @@ -19,6 +19,10 @@ type BeginBlocker func(ctx Context, req abci.RequestBeginBlock) abci.ResponseBeg // e.g. BFT timestamps rather than block height for any periodic EndBlock logic type EndBlocker func(ctx Context, req abci.RequestEndBlock) abci.ResponseEndBlock +// Commiter runs code during commit after the block number has been incremented and the `checkState` has been +// branched for the new block. +type Commiter func(ctx Context) + // PeerFilter responds to p2p filtering queries from Tendermint type PeerFilter func(info string) abci.ResponseQuery diff --git a/types/module/module.go b/types/module/module.go index 95e35f3546e..e8b898d3974 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -205,6 +205,12 @@ type EndBlockAppModule interface { EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate } +// CommitAppModule is an extension interface that contains information about the AppModule and Commit. +type CommitAppModule interface { + AppModule + Commit(sdk.Context) +} + // GenesisOnlyAppModule is an AppModule that only has import/export functionality type GenesisOnlyAppModule struct { AppModuleGenesis @@ -251,6 +257,7 @@ type Manager struct { OrderExportGenesis []string OrderBeginBlockers []string OrderEndBlockers []string + OrderCommiters []string OrderMigrations []string } @@ -268,6 +275,7 @@ func NewManager(modules ...AppModule) *Manager { OrderInitGenesis: modulesStr, OrderExportGenesis: modulesStr, OrderBeginBlockers: modulesStr, + OrderCommiters: modulesStr, OrderEndBlockers: modulesStr, } } @@ -309,6 +317,11 @@ func (m *Manager) SetOrderBeginBlockers(moduleNames ...string) { m.OrderBeginBlockers = moduleNames } +// SetOrderCommiters sets the order of set commiter calls +func (m *Manager) SetOrderCommiters(moduleNames ...string) { + m.OrderCommiters = moduleNames +} + // SetOrderEndBlockers sets the order of set end-blocker calls func (m *Manager) SetOrderEndBlockers(moduleNames ...string) { m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames) @@ -599,6 +612,17 @@ func (m *Manager) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) abci.Respo } } +// Commit performs commit functionality for all modules. +func (m *Manager) Commit(ctx sdk.Context) { + for _, moduleName := range m.OrderCommiters { + module, ok := m.Modules[moduleName].(CommitAppModule) + if !ok { + continue + } + module.Commit(ctx) + } +} + // GetVersionMap gets consensus version from all modules func (m *Manager) GetVersionMap() VersionMap { vermap := make(VersionMap) diff --git a/types/module/module_test.go b/types/module/module_test.go index 56bfbe7dd79..e49b4471a05 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -101,6 +101,10 @@ func TestManagerOrderSetters(t *testing.T) { require.Equal(t, []string{"module1", "module2"}, mm.OrderEndBlockers) mm.SetOrderEndBlockers("module2", "module1") require.Equal(t, []string{"module2", "module1"}, mm.OrderEndBlockers) + + require.Equal(t, []string{"module1", "module2"}, mm.OrderCommiters) + mm.SetOrderCommiters("module2", "module1") + require.Equal(t, []string{"module2", "module1"}, mm.OrderCommiters) } func TestManager_RegisterInvariants(t *testing.T) { @@ -251,3 +255,20 @@ func TestManager_EndBlock(t *testing.T) { mockAppModule2.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{{}}) require.Panics(t, func() { mm.EndBlock(sdk.Context{}, req) }) } + +func TestManager_Commit(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mock.NewMockCommitAppModule(mockCtrl) + mockAppModule2 := mock.NewMockCommitAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + mockAppModule1.EXPECT().Commit(gomock.Any()).Times(1) + mockAppModule2.EXPECT().Commit(gomock.Any()).Times(1) + mm.Commit(sdk.Context{}) +} diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go index 49eb5349bb7..efcd979b1ae 100644 --- a/x/genutil/gentx.go +++ b/x/genutil/gentx.go @@ -84,7 +84,7 @@ func ValidateAccountInGenesis( return nil } -type deliverTxfn func(abci.RequestDeliverTx) abci.ResponseDeliverTx +type deliverTxfn func(abci.RequestDeliverTx, bool) abci.ResponseDeliverTx // DeliverGenTxs iterates over all genesis txs, decodes each into a Tx and // invokes the provided deliverTxfn with the decoded Tx. It returns the result @@ -105,7 +105,7 @@ func DeliverGenTxs( return nil, fmt.Errorf("failed to encode GenTx '%s': %s", genTx, err) } - res := deliverTx(abci.RequestDeliverTx{Tx: bz}) + res := deliverTx(abci.RequestDeliverTx{Tx: bz}, false) if !res.IsOK() { return nil, fmt.Errorf("failed to execute DeliverTx for '%s': %s", genTx, res.Log) } diff --git a/x/genutil/gentx_test.go b/x/genutil/gentx_test.go index 6df2bd578f4..093ea5e990c 100644 --- a/x/genutil/gentx_test.go +++ b/x/genutil/gentx_test.go @@ -247,7 +247,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { testCases := []struct { msg string malleate func() - deliverTxFn func(abci.RequestDeliverTx) abci.ResponseDeliverTx + deliverTxFn func(abci.RequestDeliverTx, bool) abci.ResponseDeliverTx expPass bool }{ { @@ -261,7 +261,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { suite.Require().NoError(err) genTxs[0] = tx }, - func(_ abci.RequestDeliverTx) abci.ResponseDeliverTx { + func(_ abci.RequestDeliverTx, _ bool) abci.ResponseDeliverTx { return abci.ResponseDeliverTx{ Code: sdkerrors.ErrNoSignatures.ABCICode(), GasWanted: int64(10000000), @@ -294,7 +294,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { suite.Require().NoError(err) genTxs[0] = genTx }, - func(tx abci.RequestDeliverTx) abci.ResponseDeliverTx { + func(tx abci.RequestDeliverTx, _ bool) abci.ResponseDeliverTx { return abci.ResponseDeliverTx{ Code: sdkerrors.ErrUnauthorized.ABCICode(), GasWanted: int64(10000000), diff --git a/x/genutil/module.go b/x/genutil/module.go index 57b5a4a88d8..85be28f1012 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -137,7 +137,7 @@ type GenutilInputs struct { AccountKeeper types.AccountKeeper StakingKeeper types.StakingKeeper - DeliverTx func(abci.RequestDeliverTx) abci.ResponseDeliverTx + DeliverTx func(abci.RequestDeliverTx, bool) abci.ResponseDeliverTx Config client.TxConfig } diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index d3592e91fc5..5e926b0eab4 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -25,8 +25,8 @@ import ( var ( DefaultTokens = sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) defaultAmount = DefaultTokens.String() + sdk.DefaultBondDenom - defaultCommissionRate = "0.1" - defaultCommissionMaxRate = "0.2" + defaultCommissionRate = "1" + defaultCommissionMaxRate = "1" defaultCommissionMaxChangeRate = "0.01" defaultMinSelfDelegation = "1" )