[wip] refactor laconic app cli
- use runtime, server v2 - move generic tx decoder to utils
This commit is contained in:
parent
c7e0753f08
commit
dd39fb2365
146
app/app.go
146
app/app.go
@ -2,35 +2,36 @@ package app
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
corestore "cosmossdk.io/core/store"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"cosmossdk.io/core/transaction"
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/depinject/appconfig"
|
||||
"cosmossdk.io/log"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
|
||||
"cosmossdk.io/runtime/v2"
|
||||
server "cosmossdk.io/server/v2"
|
||||
serverstore "cosmossdk.io/server/v2/store"
|
||||
"cosmossdk.io/store/v2"
|
||||
"cosmossdk.io/store/v2/root"
|
||||
// crypto/keys/ed25519/keys.pb.go:123
|
||||
coreserver "cosmossdk.io/core/server"
|
||||
bankkeeper "cosmossdk.io/x/bank/keeper"
|
||||
consensuskeeper "cosmossdk.io/x/consensus/keeper"
|
||||
distrkeeper "cosmossdk.io/x/distribution/keeper"
|
||||
govkeeper "cosmossdk.io/x/gov/keeper"
|
||||
slashingkeeper "cosmossdk.io/x/slashing/keeper"
|
||||
stakingkeeper "cosmossdk.io/x/staking/keeper"
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
auctionkeeper "git.vdb.to/cerc-io/laconicd/x/auction/keeper"
|
||||
bondkeeper "git.vdb.to/cerc-io/laconicd/x/bond/keeper"
|
||||
onboardingkeeper "git.vdb.to/cerc-io/laconicd/x/onboarding/keeper"
|
||||
registrykeeper "git.vdb.to/cerc-io/laconicd/x/registry/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/api"
|
||||
"github.com/cosmos/cosmos-sdk/server/config"
|
||||
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
|
||||
@ -48,6 +49,7 @@ import (
|
||||
_ "git.vdb.to/cerc-io/laconicd/x/bond/module" // import for side-effects
|
||||
_ "git.vdb.to/cerc-io/laconicd/x/onboarding/module" // import for side-effects
|
||||
_ "git.vdb.to/cerc-io/laconicd/x/registry/module" // import for side-effects
|
||||
_ "github.com/cosmos/cosmos-sdk/crypto/codec" // import for side-effects
|
||||
_ "github.com/cosmos/cosmos-sdk/x/auth" // import for side-effects
|
||||
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import for side-effects
|
||||
)
|
||||
@ -59,19 +61,19 @@ var DefaultNodeHome string
|
||||
var AppConfigYAML []byte
|
||||
|
||||
var (
|
||||
_ runtime.AppI = (*LaconicApp)(nil)
|
||||
_ servertypes.Application = (*LaconicApp)(nil)
|
||||
_ server.AppI[transaction.Tx] = (*LaconicApp)(nil)
|
||||
)
|
||||
|
||||
// LaconicApp extends an ABCI application, but with most of its parameters exported.
|
||||
// They are exported for convenience in creating helper functions, as object
|
||||
// capabilities aren't needed for testing.
|
||||
type LaconicApp struct {
|
||||
*runtime.App
|
||||
*runtime.App[transaction.Tx]
|
||||
// legacyAmino *codec.LegacyAmino
|
||||
appCodec codec.Codec
|
||||
txConfig client.TxConfig
|
||||
interfaceRegistry codectypes.InterfaceRegistry
|
||||
store store.RootStore
|
||||
|
||||
// keepers
|
||||
AccountKeeper authkeeper.AccountKeeper
|
||||
@ -92,6 +94,11 @@ type LaconicApp struct {
|
||||
sm *module.SimulationManager
|
||||
}
|
||||
|
||||
type (
|
||||
AppTx = transaction.Tx
|
||||
AppBuilder = runtime.AppBuilder[AppTx]
|
||||
)
|
||||
|
||||
func init() {
|
||||
userHomeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
@ -105,32 +112,53 @@ func init() {
|
||||
func AppConfig() depinject.Config {
|
||||
return depinject.Configs(
|
||||
appconfig.LoadYAML(AppConfigYAML),
|
||||
runtime.DefaultServiceBindings(),
|
||||
depinject.Supply(
|
||||
utils.NewAddressCodec,
|
||||
utils.NewValAddressCodec,
|
||||
utils.NewConsAddressCodec,
|
||||
),
|
||||
depinject.Provide(
|
||||
codec.ProvideInterfaceRegistry,
|
||||
codec.ProvideAddressCodec,
|
||||
codec.ProvideProtoCodec,
|
||||
codec.ProvideLegacyAmino,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// NewLaconicApp returns a reference to an initialized LaconicApp.
|
||||
func NewLaconicApp(
|
||||
logger log.Logger,
|
||||
db corestore.KVStoreWithBatch,
|
||||
traceStore io.Writer,
|
||||
// db corestore.KVStoreWithBatch,
|
||||
// traceStore io.Writer,
|
||||
viper *viper.Viper,
|
||||
loadLatest bool,
|
||||
appOpts servertypes.AppOptions,
|
||||
baseAppOptions ...func(*baseapp.BaseApp),
|
||||
// appOpts server.AppOptions, // TODO migrate?
|
||||
appBuilderOpts ...runtime.AppBuilderOption[AppTx],
|
||||
) (*LaconicApp, error) {
|
||||
var (
|
||||
app = &LaconicApp{}
|
||||
appBuilder *runtime.AppBuilder
|
||||
app LaconicApp
|
||||
appBuilder *AppBuilder
|
||||
storeBuilder root.Builder
|
||||
err error
|
||||
)
|
||||
|
||||
if err := depinject.Inject(
|
||||
logfile := "/Users/roy/vulcanize/dump/laconic-debug/app_depinject.log"
|
||||
if err := depinject.InjectDebug(
|
||||
// depinject.Debug(),
|
||||
depinject.DebugOptions(
|
||||
depinject.FileLogger(logfile),
|
||||
),
|
||||
depinject.Configs(
|
||||
AppConfig(),
|
||||
depinject.Supply(
|
||||
logger,
|
||||
appOpts,
|
||||
// appOpts,
|
||||
),
|
||||
),
|
||||
&appBuilder,
|
||||
&storeBuilder,
|
||||
&app.appCodec,
|
||||
// &app.legacyAmino,
|
||||
&app.txConfig,
|
||||
@ -150,27 +178,44 @@ func NewLaconicApp(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app.App = appBuilder.Build(db, traceStore, baseAppOptions...)
|
||||
// store/v2 follows a slightly more eager config life cycle than server components
|
||||
storeConfig, err := serverstore.UnmarshalConfig(viper.AllSettings())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
app.store, err = storeBuilder.Build(logger, storeConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// register streaming services
|
||||
if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil {
|
||||
// TODO: db config correct?
|
||||
// TODO: store tracer injection?
|
||||
if app.App, err = appBuilder.Build(appBuilderOpts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO
|
||||
// // register streaming services
|
||||
// if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
/**** Module Options ****/
|
||||
|
||||
// create the simulation manager and define the order of the modules for deterministic simulations
|
||||
// NOTE: this is not required apps that don't use the simulator for fuzz testing transactions
|
||||
// NOTE: this is not required for apps that don't use the simulator for fuzz testing transactions
|
||||
app.sm = module.NewSimulationManagerFromAppModules(
|
||||
app.ModuleManager.Modules,
|
||||
app.ModuleManager().Modules(),
|
||||
make(map[string]module.AppModuleSimulation, 0))
|
||||
app.sm.RegisterStoreDecoders()
|
||||
|
||||
if err := app.Load(loadLatest); err != nil {
|
||||
return nil, err
|
||||
// TODO: remove
|
||||
if loadLatest {
|
||||
if err = app.LoadLatest(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return app, nil
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
// // LegacyAmino returns LaconicApp's amino codec.
|
||||
@ -178,38 +223,27 @@ func NewLaconicApp(
|
||||
// return app.legacyAmino
|
||||
// }
|
||||
|
||||
func (app *LaconicApp) InterfaceRegistry() coreserver.InterfaceRegistry {
|
||||
return app.interfaceRegistry
|
||||
}
|
||||
|
||||
// GetKey returns the KVStoreKey for the provided store key.
|
||||
func (app *LaconicApp) GetKey(storeKey string) *storetypes.KVStoreKey {
|
||||
sk := app.UnsafeFindStoreKey(storeKey)
|
||||
kvStoreKey, ok := sk.(*storetypes.KVStoreKey)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return kvStoreKey
|
||||
func (app *LaconicApp) GetStore() store.RootStore {
|
||||
return app.store
|
||||
}
|
||||
|
||||
func (app *LaconicApp) kvStoreKeys() map[string]*storetypes.KVStoreKey {
|
||||
keys := make(map[string]*storetypes.KVStoreKey)
|
||||
for _, k := range app.GetStoreKeys() {
|
||||
if kv, ok := k.(*storetypes.KVStoreKey); ok {
|
||||
keys[kv.Name()] = kv
|
||||
}
|
||||
}
|
||||
// func (app *LaconicApp) kvStoreKeys() map[string]*store.KVStoreKey {
|
||||
// keys := make(map[string]*store.KVStoreKey)
|
||||
// for _, k := range app.GetStoreKeys() {
|
||||
// if kv, ok := k.(*storetypes.KVStoreKey); ok {
|
||||
// keys[kv.Name()] = kv
|
||||
// }
|
||||
// }
|
||||
|
||||
return keys
|
||||
}
|
||||
// return keys
|
||||
// }
|
||||
|
||||
// SimulationManager implements the SimulationApp interface
|
||||
func (app *LaconicApp) SimulationManager() *module.SimulationManager {
|
||||
return app.sm
|
||||
}
|
||||
|
||||
// RegisterAPIRoutes registers all application module routes with the provided
|
||||
// API server.
|
||||
func (app *LaconicApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
|
||||
app.App.RegisterAPIRoutes(apiSvr, apiConfig)
|
||||
// register swagger API in app.go so that other applications can override easily
|
||||
if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,10 @@ modules:
|
||||
- bond
|
||||
- registry
|
||||
- onboarding
|
||||
gas_config:
|
||||
validate_tx_gas_limit: 100000,
|
||||
query_gas_limit: 100000,
|
||||
simulation_gas_limit: 100000,
|
||||
override_store_keys:
|
||||
- module_name: auth
|
||||
kv_store_key: acc
|
||||
|
270
app/export.go
270
app/export.go
@ -1,264 +1,48 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"context"
|
||||
|
||||
"cosmossdk.io/collections"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
slashingtypes "cosmossdk.io/x/slashing/types"
|
||||
"cosmossdk.io/runtime/v2/services"
|
||||
"cosmossdk.io/x/staking"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
tmproto "github.com/cometbft/cometbft/api/cometbft/types/v1"
|
||||
cmttypes "github.com/cometbft/cometbft/types"
|
||||
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2"
|
||||
)
|
||||
|
||||
// ExportAppStateAndValidators exports the state of the application for a genesis file.
|
||||
// ExportAppStateAndValidators exports the state of the application for a genesis
|
||||
// file.
|
||||
// This is a demonstation of how to export a genesis file. Export may need extended at
|
||||
// the user discretion for cleaning the genesis state at the end provided with jailAllowedAddrs
|
||||
func (app *LaconicApp) ExportAppStateAndValidators(
|
||||
forZeroHeight bool,
|
||||
jailAllowedAddrs []string,
|
||||
modulesToExport []string,
|
||||
) (servertypes.ExportedApp, error) {
|
||||
// as if they could withdraw from the start of the next block
|
||||
ctx := app.NewContextLegacy(true, tmproto.Header{Height: app.LastBlockHeight()})
|
||||
) (v2.ExportedApp, error) {
|
||||
ctx := context.Background()
|
||||
var exportedApp v2.ExportedApp
|
||||
|
||||
// We export at last height + 1, because that's the height at which
|
||||
// CometBFT will start InitChain.
|
||||
height := app.LastBlockHeight() + 1
|
||||
if forZeroHeight {
|
||||
height = 0
|
||||
app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
|
||||
}
|
||||
|
||||
genState, err := app.ModuleManager.ExportGenesis(ctx)
|
||||
latestHeight, err := app.LoadLatestHeight()
|
||||
if err != nil {
|
||||
return servertypes.ExportedApp{}, fmt.Errorf("failed to export genesis state: %w", err)
|
||||
return exportedApp, err
|
||||
}
|
||||
|
||||
appState, err := json.MarshalIndent(genState, "", " ")
|
||||
genesis, err := app.ExportGenesis(ctx, latestHeight)
|
||||
if err != nil {
|
||||
return servertypes.ExportedApp{}, err
|
||||
return exportedApp, err
|
||||
}
|
||||
|
||||
validators, err := staking.WriteValidators(ctx, app.StakingKeeper)
|
||||
readerMap, err := app.GetStore().StateAt(latestHeight)
|
||||
if err != nil {
|
||||
return servertypes.ExportedApp{}, err
|
||||
return exportedApp, err
|
||||
}
|
||||
genesisCtx := services.NewGenesisContext(readerMap)
|
||||
err = genesisCtx.Read(ctx, func(ctx context.Context) error {
|
||||
exportedApp.Validators, err = staking.WriteValidators(ctx, app.StakingKeeper)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return exportedApp, err
|
||||
}
|
||||
|
||||
cmtvalidators := make([]cmttypes.GenesisValidator, len(validators))
|
||||
for i := range validators {
|
||||
cmtvalidators[i] = cmttypes.GenesisValidator{
|
||||
Address: validators[i].Address.Bytes(),
|
||||
PubKey: validators[i].PubKey,
|
||||
Power: validators[i].Power,
|
||||
Name: validators[i].Name,
|
||||
}
|
||||
}
|
||||
return servertypes.ExportedApp{
|
||||
AppState: appState,
|
||||
Validators: cmtvalidators,
|
||||
Height: height,
|
||||
ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
|
||||
}, err
|
||||
}
|
||||
|
||||
// prepare for fresh start at zero height
|
||||
// NOTE zero height genesis is a temporary feature, which will be deprecated in favor of export at a block height
|
||||
func (app *LaconicApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) {
|
||||
applyAllowedAddrs := false
|
||||
|
||||
// check if there is a allowed address list
|
||||
if len(jailAllowedAddrs) > 0 {
|
||||
applyAllowedAddrs = true
|
||||
}
|
||||
|
||||
addrCodec := utils.NewAddressCodec()
|
||||
valAddrCodec := utils.NewValAddressCodec()
|
||||
|
||||
allowedAddrsMap := make(map[string]bool)
|
||||
for _, addr := range jailAllowedAddrs {
|
||||
_, err := valAddrCodec.StringToBytes(addr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
allowedAddrsMap[addr] = true
|
||||
}
|
||||
|
||||
/* Handle fee distribution state. */
|
||||
|
||||
// withdraw all validator commission
|
||||
_ = app.StakingKeeper.IterateValidators(ctx, func(_ int64, val sdk.ValidatorI) (stop bool) {
|
||||
valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, valBz)
|
||||
return false
|
||||
})
|
||||
|
||||
// withdraw all delegator rewards
|
||||
dels, err := app.StakingKeeper.GetAllDelegations(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, delegation := range dels {
|
||||
valAddr, err := valAddrCodec.StringToBytes(delegation.ValidatorAddress)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
delAddr, err := addrCodec.StringToBytes(delegation.DelegatorAddress)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr)
|
||||
}
|
||||
|
||||
// clear validator slash events
|
||||
app.DistrKeeper.ValidatorSlashEvents.Clear(ctx, nil)
|
||||
|
||||
// clear validator historical rewards
|
||||
app.DistrKeeper.ValidatorHistoricalRewards.Clear(ctx, nil)
|
||||
|
||||
// set context height to zero
|
||||
height := ctx.BlockHeight()
|
||||
ctx = ctx.WithBlockHeight(0)
|
||||
|
||||
// reinitialize all validators
|
||||
_ = app.StakingKeeper.IterateValidators(ctx, func(_ int64, val sdk.ValidatorI) (stop bool) {
|
||||
valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// donate any unwithdrawn outstanding reward fraction tokens to the community pool
|
||||
scraps, err := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, valBz)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
feePool, err := app.DistrKeeper.FeePool.Get(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
|
||||
if err := app.DistrKeeper.FeePool.Set(ctx, feePool); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, valBz); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// reinitialize all delegations
|
||||
for _, del := range dels {
|
||||
valAddr, err := valAddrCodec.StringToBytes(del.ValidatorAddress)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
delAddr, err := addrCodec.StringToBytes(del.DelegatorAddress)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr); err != nil {
|
||||
// never called as BeforeDelegationCreated always returns nil
|
||||
panic(fmt.Errorf("error while incrementing period: %w", err))
|
||||
}
|
||||
|
||||
if err := app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr); err != nil {
|
||||
// never called as AfterDelegationModified always returns nil
|
||||
panic(fmt.Errorf("error while creating a new delegation period record: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
// reset context height
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
|
||||
/* Handle staking state. */
|
||||
|
||||
// iterate through redelegations, reset creation height
|
||||
_ = app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) {
|
||||
for i := range red.Entries {
|
||||
red.Entries[i].CreationHeight = 0
|
||||
}
|
||||
_ = app.StakingKeeper.SetRedelegation(ctx, red)
|
||||
return false
|
||||
})
|
||||
|
||||
// iterate through unbonding delegations, reset creation height
|
||||
_ = app.StakingKeeper.UnbondingDelegations.Walk(
|
||||
ctx, nil,
|
||||
func(_ collections.Pair[[]byte, []byte], ubd stakingtypes.UnbondingDelegation) (stop bool, err error) {
|
||||
for i := range ubd.Entries {
|
||||
ubd.Entries[i].CreationHeight = 0
|
||||
}
|
||||
_ = app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
|
||||
return false, nil
|
||||
})
|
||||
|
||||
// Iterate through validators by power descending, reset bond heights, and
|
||||
// update bond intra-tx counters.
|
||||
store := ctx.KVStore(app.GetKey(stakingtypes.StoreKey))
|
||||
iter := storetypes.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey)
|
||||
counter := int16(0)
|
||||
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key()))
|
||||
validator, err := app.StakingKeeper.GetValidator(ctx, addr)
|
||||
if errors.Is(err, stakingtypes.ErrNoValidatorFound) {
|
||||
panic("expected validator, not found")
|
||||
} else if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
validator.UnbondingHeight = 0
|
||||
if applyAllowedAddrs && !allowedAddrsMap[addr.String()] {
|
||||
validator.Jailed = true
|
||||
}
|
||||
|
||||
_ = app.StakingKeeper.SetValidator(ctx, validator)
|
||||
counter++
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
app.Logger().Error("error while closing the key-value store reverse prefix iterator: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
/* Handle slashing state. */
|
||||
|
||||
// reset start height on signing infos
|
||||
err = app.SlashingKeeper.ValidatorSigningInfo.Walk(
|
||||
ctx, nil,
|
||||
func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool, err error) {
|
||||
info.StartHeight = 0
|
||||
err = app.SlashingKeeper.ValidatorSigningInfo.Set(ctx, addr, info)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return false, nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
exportedApp.AppState = genesis
|
||||
exportedApp.Height = int64(latestHeight)
|
||||
return exportedApp, nil
|
||||
}
|
||||
|
@ -2,33 +2,35 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
corestore "cosmossdk.io/core/store"
|
||||
corectx "cosmossdk.io/core/context"
|
||||
"cosmossdk.io/log"
|
||||
serverv2 "cosmossdk.io/server/v2"
|
||||
"cosmossdk.io/server/v2/api/grpc"
|
||||
"cosmossdk.io/server/v2/api/rest"
|
||||
"cosmossdk.io/server/v2/api/telemetry"
|
||||
"cosmossdk.io/server/v2/cometbft"
|
||||
serverstore "cosmossdk.io/server/v2/store"
|
||||
confixcmd "cosmossdk.io/tools/confix/cmd"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/debug"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/pruning"
|
||||
"github.com/cosmos/cosmos-sdk/client/snapshot"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
genutilv2 "github.com/cosmos/cosmos-sdk/x/genutil/v2"
|
||||
genutilv2cli "github.com/cosmos/cosmos-sdk/x/genutil/v2/cli"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app"
|
||||
"git.vdb.to/cerc-io/laconicd/gql"
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
)
|
||||
|
||||
func initRootCmd(rootCmd *cobra.Command, txConfig client.TxConfig, moduleManager moduleManager) {
|
||||
@ -39,30 +41,47 @@ func initRootCmd(rootCmd *cobra.Command, txConfig client.TxConfig, moduleManager
|
||||
genutilcli.InitCmd(moduleManager),
|
||||
debug.Cmd(),
|
||||
confixcmd.ConfigCommand(),
|
||||
pruning.Cmd(newApp),
|
||||
snapshot.Cmd(newApp),
|
||||
// TODO
|
||||
// pruning.Cmd(newApp),
|
||||
// snapshot.Cmd(newApp),
|
||||
)
|
||||
|
||||
server.AddCommands(rootCmd, newApp, server.StartCmdOptions[*app.LaconicApp]{
|
||||
PostSetup: func(
|
||||
_ *app.LaconicApp,
|
||||
svrCtx *server.Context,
|
||||
clientCtx client.Context,
|
||||
ctx context.Context,
|
||||
g *errgroup.Group,
|
||||
) error {
|
||||
g.Go(func() error {
|
||||
return gql.Server(ctx, clientCtx, svrCtx.Logger.With("module", "gql-server"))
|
||||
})
|
||||
return nil
|
||||
},
|
||||
},
|
||||
)
|
||||
if err := serverv2.AddCommands(
|
||||
rootCmd,
|
||||
newApp,
|
||||
initServerConfig(),
|
||||
cometbft.New(
|
||||
utils.GenericTxDecoder[app.AppTx]{txConfig},
|
||||
initCometOptions[app.AppTx](),
|
||||
initCometConfig(),
|
||||
),
|
||||
grpc.New[app.AppTx](),
|
||||
serverstore.New[app.AppTx](),
|
||||
telemetry.New[app.AppTx](),
|
||||
rest.New[app.AppTx](),
|
||||
|
||||
// serverv2.StartCmdOptions[*app.LaconicApp]{
|
||||
// PostSetup: func(
|
||||
// _ *app.LaconicApp,
|
||||
// svrCtx *server.Context,
|
||||
// clientCtx client.Context,
|
||||
// ctx context.Context,
|
||||
// g *errgroup.Group,
|
||||
// ) error {
|
||||
// g.Go(func() error {
|
||||
// return gql.Server(ctx, clientCtx, svrCtx.Logger.With("module", "gql-server"))
|
||||
// })
|
||||
// return nil
|
||||
// },
|
||||
// },
|
||||
); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// add keybase, auxiliary RPC, query, genesis, and tx child commands
|
||||
rootCmd.AddCommand(
|
||||
server.StatusCommand(),
|
||||
genutilcli.Commands(
|
||||
genutilv2cli.Commands(
|
||||
moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule),
|
||||
moduleManager,
|
||||
appExport),
|
||||
@ -117,69 +136,118 @@ func txCommand() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// newApp is an appCreator
|
||||
func newApp(
|
||||
logger log.Logger,
|
||||
db corestore.KVStoreWithBatch,
|
||||
traceStore io.Writer,
|
||||
appOpts servertypes.AppOptions,
|
||||
) *app.LaconicApp {
|
||||
var _ = db
|
||||
baseappOptions := server.DefaultBaseappOptions(appOpts)
|
||||
app, err := app.NewLaconicApp(logger, db, traceStore, true, appOpts, baseappOptions...)
|
||||
func newApp(logger log.Logger, viper *viper.Viper) serverv2.AppI[app.AppTx] {
|
||||
viper.Set(serverv2.FlagHome, app.DefaultNodeHome)
|
||||
lacapp, err := app.NewLaconicApp(logger, viper, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return app
|
||||
return serverv2.AppI[app.AppTx](lacapp)
|
||||
}
|
||||
|
||||
// appExport creates a new app (optionally at a given height) and exports state.
|
||||
// // newApp is an appCreator
|
||||
// func newApp(
|
||||
// logger log.Logger,
|
||||
// db corestore.KVStoreWithBatch,
|
||||
// traceStore io.Writer,
|
||||
// appOpts servertypes.AppOptions,
|
||||
// ) *app.LaconicApp {
|
||||
// var _ = db
|
||||
// // baseappOptions := server.DefaultBaseappOptions(appOpts)
|
||||
// app, err := app.NewLaconicApp(logger, viper, true)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// return app
|
||||
// }
|
||||
|
||||
// appExport creates a new simapp (optionally at a given height) and exports state.
|
||||
func appExport(
|
||||
logger log.Logger,
|
||||
db corestore.KVStoreWithBatch,
|
||||
traceStore io.Writer,
|
||||
ctx context.Context,
|
||||
height int64,
|
||||
forZeroHeight bool,
|
||||
jailAllowedAddrs []string,
|
||||
appOpts servertypes.AppOptions,
|
||||
modulesToExport []string,
|
||||
) (servertypes.ExportedApp, error) {
|
||||
var (
|
||||
laconicApp *app.LaconicApp
|
||||
err error
|
||||
)
|
||||
|
||||
// this check is necessary as we use the flag in x/upgrade.
|
||||
// we can exit more gracefully by checking the flag here.
|
||||
homePath, ok := appOpts.Get(flags.FlagHome).(string)
|
||||
if !ok || homePath == "" {
|
||||
return servertypes.ExportedApp{}, errors.New("application home not set")
|
||||
}
|
||||
|
||||
viperAppOpts, ok := appOpts.(*viper.Viper)
|
||||
) (genutilv2.ExportedApp, error) {
|
||||
value := ctx.Value(corectx.ViperContextKey)
|
||||
viper, ok := value.(*viper.Viper)
|
||||
if !ok {
|
||||
return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper")
|
||||
return genutilv2.ExportedApp{},
|
||||
fmt.Errorf("incorrect viper type %T: expected *viper.Viper in context", value)
|
||||
}
|
||||
value = ctx.Value(corectx.LoggerContextKey)
|
||||
logger, ok := value.(log.Logger)
|
||||
if !ok {
|
||||
return genutilv2.ExportedApp{},
|
||||
fmt.Errorf("incorrect logger type %T: expected log.Logger in context", value)
|
||||
}
|
||||
|
||||
// overwrite the FlagInvCheckPeriod
|
||||
viperAppOpts.Set(server.FlagInvCheckPeriod, 1)
|
||||
appOpts = viperAppOpts
|
||||
viper.Set(server.FlagInvCheckPeriod, 1)
|
||||
viper.Set(serverv2.FlagHome, app.DefaultNodeHome)
|
||||
|
||||
lacapp, err := app.NewLaconicApp(logger, viper, false)
|
||||
if err != nil {
|
||||
return genutilv2.ExportedApp{}, err
|
||||
}
|
||||
if height != -1 {
|
||||
laconicApp, err = app.NewLaconicApp(logger, db, traceStore, false, appOpts)
|
||||
if err != nil {
|
||||
return servertypes.ExportedApp{}, err
|
||||
}
|
||||
|
||||
if err := laconicApp.LoadHeight(height); err != nil {
|
||||
return servertypes.ExportedApp{}, err
|
||||
}
|
||||
err = lacapp.LoadHeight(uint64(height))
|
||||
} else {
|
||||
laconicApp, err = app.NewLaconicApp(logger, db, traceStore, true, appOpts)
|
||||
if err != nil {
|
||||
return servertypes.ExportedApp{}, err
|
||||
}
|
||||
err = lacapp.LoadLatest()
|
||||
}
|
||||
if err != nil {
|
||||
return genutilv2.ExportedApp{}, err
|
||||
}
|
||||
|
||||
return laconicApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
|
||||
return lacapp.ExportAppStateAndValidators(jailAllowedAddrs)
|
||||
}
|
||||
|
||||
// // appExport creates a new app (optionally at a given height) and exports state.
|
||||
// func appExport(
|
||||
// logger log.Logger,
|
||||
// db corestore.KVStoreWithBatch,
|
||||
// traceStore io.Writer,
|
||||
// height int64,
|
||||
// forZeroHeight bool,
|
||||
// jailAllowedAddrs []string,
|
||||
// appOpts servertypes.AppOptions,
|
||||
// modulesToExport []string,
|
||||
// ) (genutilv2.ExportedApp, error) {
|
||||
// var (
|
||||
// laconicApp *app.LaconicApp
|
||||
// err error
|
||||
// )
|
||||
|
||||
// // this check is necessary as we use the flag in x/upgrade.
|
||||
// // we can exit more gracefully by checking the flag here.
|
||||
// homePath, ok := appOpts.Get(flags.FlagHome).(string)
|
||||
// if !ok || homePath == "" {
|
||||
// return servertypes.ExportedApp{}, errors.New("application home not set")
|
||||
// }
|
||||
|
||||
// viperAppOpts, ok := appOpts.(*viper.Viper)
|
||||
// if !ok {
|
||||
// return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper")
|
||||
// }
|
||||
|
||||
// // overwrite the FlagInvCheckPeriod
|
||||
// viperAppOpts.Set(server.FlagInvCheckPeriod, 1)
|
||||
// appOpts = viperAppOpts
|
||||
|
||||
// if height != -1 {
|
||||
// laconicApp, err = app.NewLaconicApp(logger, db, false)
|
||||
// if err != nil {
|
||||
// return servertypes.ExportedApp{}, err
|
||||
// }
|
||||
|
||||
// if err := laconicApp.LoadHeight(uint64(height)); err != nil {
|
||||
// return servertypes.ExportedApp{}, err
|
||||
// }
|
||||
// } else {
|
||||
// panic("height cannot be < 0")
|
||||
// laconicApp, err = app.NewLaconicApp(logger, db, true)
|
||||
// if err != nil {
|
||||
// return servertypes.ExportedApp{}, err
|
||||
// }
|
||||
// }
|
||||
|
||||
// return laconicApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
|
||||
// }
|
||||
|
106
cmd/laconicd/cmd/config.go
Normal file
106
cmd/laconicd/cmd/config.go
Normal file
@ -0,0 +1,106 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cmtcfg "github.com/cometbft/cometbft/config"
|
||||
|
||||
"cosmossdk.io/core/transaction"
|
||||
serverv2 "cosmossdk.io/server/v2"
|
||||
"cosmossdk.io/server/v2/cometbft"
|
||||
|
||||
clientconfig "github.com/cosmos/cosmos-sdk/client/config"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
)
|
||||
|
||||
// initAppConfig helps to override default client config template and configs.
|
||||
// return "", nil if no custom configuration is required for the application.
|
||||
func initClientConfig() (string, interface{}) {
|
||||
type GasConfig struct {
|
||||
GasAdjustment float64 `mapstructure:"gas-adjustment"`
|
||||
}
|
||||
|
||||
type CustomClientConfig struct {
|
||||
clientconfig.Config `mapstructure:",squash"`
|
||||
|
||||
GasConfig GasConfig `mapstructure:"gas"`
|
||||
}
|
||||
|
||||
// Optionally allow the chain developer to overwrite the SDK's default client config.
|
||||
clientCfg := clientconfig.DefaultConfig()
|
||||
|
||||
// The SDK's default keyring backend is set to "os".
|
||||
// This is more secure than "test" and is the recommended value.
|
||||
//
|
||||
// In simapp, we set the default keyring backend to test, as SimApp is meant
|
||||
// to be an example and testing application.
|
||||
clientCfg.KeyringBackend = keyring.BackendTest
|
||||
|
||||
// Now we set the custom config default values.
|
||||
customClientConfig := CustomClientConfig{
|
||||
Config: *clientCfg,
|
||||
GasConfig: GasConfig{
|
||||
GasAdjustment: 1.5,
|
||||
},
|
||||
}
|
||||
|
||||
// The default SDK app template is defined in serverconfig.DefaultConfigTemplate.
|
||||
// We append the custom config template to the default one.
|
||||
// And we set the default config to the custom app template.
|
||||
customClientConfigTemplate := clientconfig.DefaultClientConfigTemplate + strings.TrimSpace(`
|
||||
# This is default the gas adjustment factor used in tx commands.
|
||||
# It can be overwritten by the --gas-adjustment flag in each tx command.
|
||||
gas-adjustment = {{ .GasConfig.GasAdjustment }}
|
||||
`)
|
||||
|
||||
return customClientConfigTemplate, customClientConfig
|
||||
}
|
||||
|
||||
// Allow the chain developer to overwrite the server default app toml config.
|
||||
func initServerConfig() serverv2.ServerConfig {
|
||||
serverCfg := serverv2.DefaultServerConfig()
|
||||
// The server's default minimum gas price is set to "0stake" inside
|
||||
// app.toml. However, the chain developer can set a default app.toml value for their
|
||||
// validators here. Please update value based on chain denom.
|
||||
//
|
||||
// In summary:
|
||||
// - if you set serverCfg.MinGasPrices value, validators CAN tweak their
|
||||
// own app.toml to override, or use this default value.
|
||||
//
|
||||
// In simapp, we set the min gas prices to 0.
|
||||
serverCfg.MinGasPrices = "0stake"
|
||||
|
||||
return serverCfg
|
||||
}
|
||||
|
||||
// initCometConfig helps to override default comet config template and configs.
|
||||
func initCometConfig() cometbft.CfgOption {
|
||||
cfg := cmtcfg.DefaultConfig()
|
||||
|
||||
// display only warn logs by default except for p2p and state
|
||||
cfg.LogLevel = "*:warn,server:info,p2p:info,state:info"
|
||||
// increase block timeout
|
||||
cfg.Consensus.TimeoutCommit = 5 * time.Second
|
||||
// overwrite default pprof listen address
|
||||
cfg.RPC.PprofListenAddress = "localhost:6060"
|
||||
|
||||
return cometbft.OverwriteDefaultConfigTomlConfig(cfg)
|
||||
}
|
||||
|
||||
func initCometOptions[T transaction.Tx]() cometbft.ServerOptions[T] {
|
||||
serverOptions := cometbft.DefaultServerOptions[T]()
|
||||
|
||||
// overwrite app mempool, using max-txs option
|
||||
// serverOptions.Mempool = func(cfg map[string]any) mempool.Mempool[T] {
|
||||
// if maxTxs := cast.ToInt(cfg[cometbft.FlagMempoolMaxTxs]); maxTxs >= 0 {
|
||||
// return sdkmempool.NewSenderNonceMempool(
|
||||
// sdkmempool.SenderNonceMaxTxOpt(maxTxs),
|
||||
// )
|
||||
// }
|
||||
|
||||
// return mempool.NoOpMempool[T]{}
|
||||
// }
|
||||
|
||||
return serverOptions
|
||||
}
|
@ -31,7 +31,6 @@ import (
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app"
|
||||
"git.vdb.to/cerc-io/laconicd/gql"
|
||||
"git.vdb.to/cerc-io/laconicd/utils"
|
||||
)
|
||||
|
||||
const EnvPrefix = "LACONIC"
|
||||
@ -54,16 +53,8 @@ func NewRootCmd() *cobra.Command {
|
||||
app.AppConfig(),
|
||||
depinject.Supply(
|
||||
log.NewNopLogger(),
|
||||
utils.NewAddressCodec,
|
||||
utils.NewValAddressCodec,
|
||||
utils.NewConsAddressCodec,
|
||||
),
|
||||
runtime.DefaultServiceBindings(),
|
||||
depinject.Provide(
|
||||
codec.ProvideInterfaceRegistry,
|
||||
codec.ProvideAddressCodec,
|
||||
codec.ProvideProtoCodec,
|
||||
codec.ProvideLegacyAmino,
|
||||
ProvideClientContext,
|
||||
ProvideKeyring,
|
||||
),
|
||||
@ -171,8 +162,8 @@ func ProvideClientContext(
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Workaround: Unset clientCtx.HomeDir and clientCtx.KeyringDir from depinject clientCtx as they are given precedence over
|
||||
// the CLI args (--home flag) in some commands
|
||||
// Workaround: Unset clientCtx.HomeDir and clientCtx.KeyringDir from depinject clientCtx as they
|
||||
// are given precedence over the CLI args (--home flag) in some commands
|
||||
// TODO: Implement proper fix
|
||||
clientCtx.HomeDir = ""
|
||||
clientCtx.KeyringDir = ""
|
||||
@ -186,5 +177,5 @@ func ProvideKeyring(clientCtx client.Context, addressCodec address.Codec) (clien
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return keyring.NewAutoCLIKeyring(kb)
|
||||
return keyring.NewAutoCLIKeyring(kb, addressCodec)
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
svrcmd "cosmossdk.io/server/v2"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app"
|
||||
|
@ -4,18 +4,18 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
|
||||
|
||||
"git.vdb.to/cerc-io/laconicd/app"
|
||||
"git.vdb.to/cerc-io/laconicd/app/params"
|
||||
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
|
||||
|
||||
clientv2helpers "cosmossdk.io/client/v2/helpers"
|
||||
serverv2 "cosmossdk.io/server/v2"
|
||||
|
||||
_ "git.vdb.to/cerc-io/laconicd/app/params" // import for side-effects
|
||||
)
|
||||
|
||||
func main() {
|
||||
params.SetAddressPrefixes()
|
||||
|
||||
rootCmd := cmd.NewRootCmd()
|
||||
if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil {
|
||||
if err := serverv2.Execute(rootCmd, clientv2helpers.EnvPrefix, app.DefaultNodeHome); err != nil {
|
||||
fmt.Fprintln(rootCmd.OutOrStderr(), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
12
go.mod
12
go.mod
@ -27,7 +27,7 @@ require (
|
||||
cosmossdk.io/tools/confix v0.1.0
|
||||
github.com/99designs/gqlgen v0.17.22
|
||||
github.com/cometbft/cometbft v1.0.0-rc1.0.20240908111210-ab0be101882f
|
||||
github.com/cometbft/cometbft/api v1.0.0-rc.1
|
||||
github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect
|
||||
github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.5
|
||||
github.com/cosmos/cosmos-sdk v1.0.0
|
||||
@ -48,7 +48,7 @@ require (
|
||||
github.com/statechannels/go-nitro v0.1.2
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/vektah/gqlparser/v2 v2.5.11
|
||||
golang.org/x/sync v0.8.0
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142
|
||||
google.golang.org/grpc v1.67.1
|
||||
google.golang.org/protobuf v1.35.1
|
||||
@ -56,6 +56,8 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
cosmossdk.io/server/v2/cometbft v0.0.0-20241017154543-c1707b830856
|
||||
cosmossdk.io/store/v2 v2.0.0-00010101000000-000000000000
|
||||
cosmossdk.io/x/accounts v1.0.0-alpha.4
|
||||
cosmossdk.io/x/bank v1.0.0-alpha.4
|
||||
cosmossdk.io/x/consensus v0.0.0-20241007000829-38662ecb209f
|
||||
@ -73,9 +75,8 @@ require (
|
||||
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 // indirect
|
||||
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect
|
||||
cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac // indirect
|
||||
cosmossdk.io/server/v2/appmanager v0.0.0-00010101000000-000000000000 // indirect
|
||||
cosmossdk.io/server/v2/stf v0.0.0-00010101000000-000000000000 // indirect
|
||||
cosmossdk.io/store/v2 v2.0.0-00010101000000-000000000000 // indirect
|
||||
cosmossdk.io/server/v2/appmanager v0.0.0-20240802110823-cffeedff643d // indirect
|
||||
cosmossdk.io/server/v2/stf v0.0.0-20240708142107-25e99c54bac1 // indirect
|
||||
cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect
|
||||
cosmossdk.io/x/tx v0.13.3 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
@ -254,6 +255,7 @@ replace (
|
||||
cosmossdk.io/runtime/v2 => ../cosmos-sdk/runtime/v2
|
||||
cosmossdk.io/server/v2 => ../cosmos-sdk/server/v2
|
||||
cosmossdk.io/server/v2/appmanager => ../cosmos-sdk/server/v2/appmanager
|
||||
cosmossdk.io/server/v2/cometbft => ../cosmos-sdk/server/v2/cometbft
|
||||
cosmossdk.io/server/v2/stf => ../cosmos-sdk/server/v2/stf
|
||||
cosmossdk.io/store => ../cosmos-sdk/store
|
||||
cosmossdk.io/store/v2 => ../cosmos-sdk/store/v2
|
||||
|
48
utils/tx.go
Normal file
48
utils/tx.go
Normal file
@ -0,0 +1,48 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"cosmossdk.io/core/transaction"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
)
|
||||
|
||||
var _ transaction.Codec[transaction.Tx] = &GenericTxDecoder[transaction.Tx]{}
|
||||
|
||||
type GenericTxDecoder[T transaction.Tx] struct {
|
||||
TxConfig client.TxConfig
|
||||
}
|
||||
|
||||
// Decode implements transaction.Codec.
|
||||
func (t GenericTxDecoder[T]) Decode(bz []byte) (T, error) {
|
||||
var out T
|
||||
tx, err := t.TxConfig.TxDecoder()(bz)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
out, ok = tx.(T)
|
||||
if !ok {
|
||||
return out, errors.New("unexpected Tx type")
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DecodeJSON implements transaction.Codec.
|
||||
func (t GenericTxDecoder[T]) DecodeJSON(bz []byte) (T, error) {
|
||||
var out T
|
||||
tx, err := t.TxConfig.TxJSONDecoder()(bz)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
out, ok = tx.(T)
|
||||
if !ok {
|
||||
return out, errors.New("unexpected Tx type")
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user