Skip to main content

cosmos-sdk fork

Dchain replaces upstream github.com/cosmos/cosmos-sdk with the d-foundation fork via the go.mod replace directive:

github.com/cosmos/cosmos-sdk => github.com/d-foundation/cosmos-sdk v0.53.4-dchain-v5

Source: github.com/d-foundation/cosmos-sdk. The branch is pinned to the tag v0.53.4-dchain-v5.

Customisations

Bank keeper narrowed from interface to *BaseKeeper

Commit: 01564570c5 Move Bank keeper to BaseKeeper pointer

Files touched:

  • x/bank/keeper/msg_server.go
  • x/bank/keeper/migrations.go
  • x/bank/module.go

Surface change

The fork narrows the bank module's public API from the Keeper interface to the concrete *BaseKeeper pointer in four places:

SymbolUpstream typeFork type
msgServer.keeper fieldKeeper (embedded)*BaseKeeper
keeper.NewMsgServerImpl parameterKeeper*BaseKeeper
bank.AppModule.keeper fieldkeeper.Keeper*keeper.BaseKeeper
depinject ModuleOutputs.BankKeeperkeeper.BaseKeeper (value)*keeper.BaseKeeper

In the same commit the runtime type assertions of the form if base, ok := k.Keeper.(BaseKeeper); ok { ... } are removed in favour of direct field access on the concrete pointer.

Rationale

  1. Bank hooks via depinject. Dchain installs bank hooks through depinject (see the preceding work on the same branch: the add-bank-hooks PRs #4 and #5, and the commit feat: use depInjection for bankhooks). Hooks must mutate keeper state that is visible to every consumer of the keeper. When depinject emits BankKeeper as a value (keeper.BaseKeeper), each consumer receives an independent copy and hooks installed on one copy are invisible to the others. Emitting *BaseKeeper instead gives every consumer the same addressable keeper, so a hook installation is observed by all call sites.

  2. Eliminate runtime branching. Upstream's Keeper interface does not expose internal fields such as ak (the account keeper). To reach them the upstream msgServer.Send performs a runtime type assertion k.Keeper.(BaseKeeper) and returns sdkerrors.ErrInvalidRequest on failure. Replacing the interface parameter with *BaseKeeper makes those fields reachable at compile time and removes a whole class of runtime invalid keeper type errors. The msg server methods become straight-line field accesses.

Downstream consequence: cosmos/evm precompile

github.com/cosmos/evm's ERC-20 precompile is written against the upstream signature (NewMsgServerImpl(keeper Keeper)). Its type switch covers both a value BaseKeeper arm and a pointer *BaseKeeper arm, because the upstream interface parameter accepts either form:

switch keeper := m.BankKeeper.(type) {
case bankkeeper.BaseKeeper: // value arm
msgSrv := bankkeeper.NewMsgServerImpl(keeper)
...
case *bankkeeper.BaseKeeper: // pointer arm
msgSrv := bankkeeper.NewMsgServerImpl(keeper)
...
}

Go type-checks every arm of a type switch, not only the arm that runs. Against the narrowed fork signature the value arm fails to compile with cannot use keeper (variable of type bankkeeper.BaseKeeper) as *bankkeeper.BaseKeeper. The dchain bank keeper is stored as *BaseKeeper exclusively, so the value arm is also unreachable at runtime.

This is patched downstream in the d-foundation evm fork (see the cosmos/evm fork page).

Rebase strategy

This customisation is one commit on top of a vanilla v0.53.4 base. When rebasing onto a new upstream cosmos-sdk release:

  1. Pull the new upstream tag.
  2. Cherry-pick 01564570c5 and resolve conflicts in x/bank/keeper/msg_server.go, x/bank/keeper/migrations.go, and x/bank/module.go.
  3. Re-tag as vX.Y.Z-dchain-vN.
  4. Bump the replace directive in protocol/go.mod and any consumer forks (d-foundation/evm, d-foundation/wasmd).
  5. Re-verify the cosmos/evm ERC-20 precompile patch still applies; if upstream cosmos/evm has reshaped the type switch, the patch will need re-deriving.