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.gox/bank/keeper/migrations.gox/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:
| Symbol | Upstream type | Fork type |
|---|---|---|
msgServer.keeper field | Keeper (embedded) | *BaseKeeper |
keeper.NewMsgServerImpl parameter | Keeper | *BaseKeeper |
bank.AppModule.keeper field | keeper.Keeper | *keeper.BaseKeeper |
depinject ModuleOutputs.BankKeeper | keeper.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
-
Bank hooks via depinject. Dchain installs bank hooks through depinject (see the preceding work on the same branch: the
add-bank-hooksPRs#4and#5, and the commitfeat: use depInjection for bankhooks). Hooks must mutate keeper state that is visible to every consumer of the keeper. When depinject emitsBankKeeperas a value (keeper.BaseKeeper), each consumer receives an independent copy and hooks installed on one copy are invisible to the others. Emitting*BaseKeeperinstead gives every consumer the same addressable keeper, so a hook installation is observed by all call sites. -
Eliminate runtime branching. Upstream's
Keeperinterface does not expose internal fields such asak(the account keeper). To reach them the upstreammsgServer.Sendperforms a runtime type assertionk.Keeper.(BaseKeeper)and returnssdkerrors.ErrInvalidRequeston failure. Replacing the interface parameter with*BaseKeepermakes those fields reachable at compile time and removes a whole class of runtimeinvalid keeper typeerrors. 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:
- Pull the new upstream tag.
- Cherry-pick
01564570c5and resolve conflicts inx/bank/keeper/msg_server.go,x/bank/keeper/migrations.go, andx/bank/module.go. - Re-tag as
vX.Y.Z-dchain-vN. - Bump the replace directive in
protocol/go.modand any consumer forks (d-foundation/evm,d-foundation/wasmd). - 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.