Skip to content

Commit

Permalink
feat: additions for Terra Classic (#8)
Browse files Browse the repository at this point in the history
* Add prioritized oracle message
* Add delegation limit
* Make interblock cache configurable
  • Loading branch information
nghuyenthevinh2000 authored Aug 14, 2023
1 parent 2a48f6d commit c4e15be
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 41 deletions.
30 changes: 22 additions & 8 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,21 +241,35 @@ 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, tx, err := app.runTx(mode, req.Tx)
if err != nil {
return sdkerrors.ResponseCheckTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace)
}

return abci.ResponseCheckTx{
GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints?
GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints?
Log: result.Log,
Data: result.Data,
Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents),
Priority: priority,
GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints?
GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints?
Log: result.Log,
Data: result.Data,
Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents),
Priority: priority,
IsOracleTx: isOracleTx(tx.GetMsgs()),
}
}

func isOracleTx(msgs []sdk.Msg) bool {
for _, msg := range msgs {
if sdk.MsgTypeURL(msg) == "/terra.oracle.v1beta1.MsgAggregateExchangeRatePrevote" ||
sdk.MsgTypeURL(msg) == "/terra.oracle.v1beta1.MsgAggregateExchangeRateVote" {
continue
} else {
return false
}
}

return true
}

// DeliverTx implements the ABCI interface and executes a tx in DeliverTx mode.
// State only gets persisted if all messages are valid and get executed successfully.
// Otherwise, the ResponseDeliverTx will contain releveant error information.
Expand All @@ -280,7 +294,7 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliv
telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted")
}()

gInfo, result, anteEvents, _, err := app.runTx(runTxModeDeliver, req.Tx)
gInfo, result, anteEvents, _, _, err := app.runTx(runTxModeDeliver, req.Tx)
if err != nil {
resultStr = "failed"
return sdkerrors.ResponseDeliverTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, sdk.MarkEventsToIndex(anteEvents, app.indexEvents), app.trace)
Expand Down
16 changes: 8 additions & 8 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context
// 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) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, priority int64, err error) {
func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, priority int64, tx sdk.Tx, err error) {
// 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.
Expand All @@ -633,7 +633,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re

// only run the tx if there is block gas remaining
if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() {
return gInfo, nil, nil, 0, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx")
return gInfo, nil, nil, 0, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx")
}

defer func() {
Expand Down Expand Up @@ -666,14 +666,14 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
defer consumeBlockGas()
}

tx, err := app.txDecoder(txBytes)
tx, err = app.txDecoder(txBytes)
if err != nil {
return sdk.GasInfo{}, nil, nil, 0, err
return sdk.GasInfo{}, nil, nil, 0, nil, err
}

msgs := tx.GetMsgs()
if err := validateBasicTxMsgs(msgs); err != nil {
return sdk.GasInfo{}, nil, nil, 0, err
return sdk.GasInfo{}, nil, nil, 0, nil, err
}

if app.anteHandler != nil {
Expand Down Expand Up @@ -709,7 +709,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
gasWanted = ctx.GasMeter().Limit()

if err != nil {
return gInfo, nil, nil, 0, err
return gInfo, nil, nil, 0, nil, err
}

priority = ctx.Priority()
Expand Down Expand Up @@ -738,7 +738,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re

newCtx, err := app.postHandler(postCtx, tx, mode == runTxModeSimulate)
if err != nil {
return gInfo, nil, anteEvents, priority, err
return gInfo, nil, anteEvents, priority, nil, err
}

result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...)
Expand All @@ -757,7 +757,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
}
}

return gInfo, result, anteEvents, priority, err
return gInfo, result, anteEvents, priority, tx, err
}

// runMsgs iterates through a list of messages and executes them with the provided
Expand Down
6 changes: 3 additions & 3 deletions baseapp/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ 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.runTx(runTxModeCheck, bz)
return gasInfo, result, err
}

// Simulate executes a tx in simulate mode to get result and gas info.
func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) {
gasInfo, result, _, _, err := app.runTx(runTxModeSimulate, txBytes)
gasInfo, result, _, _, _, err := app.runTx(runTxModeSimulate, txBytes)
return gasInfo, result, err
}

Expand All @@ -32,7 +32,7 @@ func (app *BaseApp) SimDeliver(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(runTxModeDeliver, bz)
gasInfo, result, _, _, _, err := app.runTx(runTxModeDeliver, bz)
return gasInfo, result, err
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ replace (
// replace broken goleveldb.
github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
// use cometbft
github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.29
github.com/tendermint/tendermint => github.com/classic-terra/cometbft v0.34.29-terra.0
)

retract (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWs
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/classic-terra/cometbft v0.34.29-terra.0 h1:HnRGt7tijI2n5zSVrg/xh1mYYm4Gb4QFlknq+dRP8Jw=
github.com/classic-terra/cometbft v0.34.29-terra.0/go.mod h1:L9shMfbkZ8B+7JlwANEr+NZbBcn+hBpwdbeYvA5rLCw=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
Expand All @@ -200,8 +202,6 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE
github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI=
github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA=
github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M=
github.com/cometbft/cometbft v0.34.29 h1:Q4FqMevP9du2pOgryZJHpDV2eA6jg/kMYxBj9ZTY6VQ=
github.com/cometbft/cometbft v0.34.29/go.mod h1:L9shMfbkZ8B+7JlwANEr+NZbBcn+hBpwdbeYvA5rLCw=
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=
Expand Down
8 changes: 7 additions & 1 deletion server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (

clientflags "github.com/cosmos/cosmos-sdk/client/flags"
pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types"
"github.com/cosmos/cosmos-sdk/store/cache"
"github.com/cosmos/cosmos-sdk/store/iavl"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
Expand Down Expand Up @@ -81,6 +83,9 @@ type BaseConfig struct {
// InterBlockCache enables inter-block caching.
InterBlockCache bool `mapstructure:"inter-block-cache"`

// InterBlockCacheSize set the size of the inter-block cache.
InterBlockCacheSize uint `mapstructure:"inter-block-cache-size"`

// IndexEvents defines the set of events in the form {eventType}.{attributeKey},
// which informs Tendermint what to index. If empty, all events will be indexed.
IndexEvents []string `mapstructure:"index-events"`
Expand Down Expand Up @@ -281,12 +286,13 @@ func DefaultConfig() *Config {
BaseConfig: BaseConfig{
MinGasPrices: defaultMinGasPrices,
InterBlockCache: true,
InterBlockCacheSize: cache.DefaultCommitKVStoreCacheSize,
Pruning: pruningtypes.PruningOptionDefault,
PruningKeepRecent: "0",
PruningInterval: "0",
MinRetainBlocks: 0,
IndexEvents: make([]string, 0),
IAVLCacheSize: 781250, // 50 MB
IAVLCacheSize: iavl.DefaultIAVLCacheSize,
IAVLDisableFastNode: false,
IAVLLazyLoading: false,
AppDBBackend: "",
Expand Down
12 changes: 10 additions & 2 deletions server/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,23 @@ min-retain-blocks = {{ .BaseConfig.MinRetainBlocks }}
# InterBlockCache enables inter-block caching.
inter-block-cache = {{ .BaseConfig.InterBlockCache }}
# InterBlockCacheSize set the size (the number of cache items) of interblock cache item
# Each item consumes 128 bytes, so the value should be dividend by 128
# Default cache size is 10mb.
# Ex) 100mb = 10,000,000 / 128 = 78,125
inter-block-cache-size = {{ .BaseConfig.InterBlockCacheSize }}
# IndexEvents defines the set of events in the form {eventType}.{attributeKey},
# which informs Tendermint what to index. If empty, all events will be indexed.
#
# Example:
# ["message.sender", "message.recipient"]
index-events = [{{ range .BaseConfig.IndexEvents }}{{ printf "%q, " . }}{{end}}]
# IavlCacheSize set the size of the iavl tree cache.
# Default cache size is 50mb.
# IAVLCacheSize set the cache size (the number of cache items) of the iavl tree.
# Each item size consumes 128 bytes, so the value should be dividend by 128
# Default cache size is 100mb.
# Ex) 100mb = 100,000,000 / 128 = 781,250
iavl-cache-size = {{ .BaseConfig.IAVLCacheSize }}
# IavlDisableFastNode enables or disables the fast node feature of IAVL.
Expand Down
29 changes: 17 additions & 12 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,27 @@ import (
"github.com/cosmos/cosmos-sdk/server/rosetta"
crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
"github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/store/cache"
"github.com/cosmos/cosmos-sdk/store/iavl"
"github.com/cosmos/cosmos-sdk/telemetry"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)

const (
// Tendermint full-node start flags
flagWithTendermint = "with-tendermint"
flagAddress = "address"
flagTransport = "transport"
flagTraceStore = "trace-store"
flagCPUProfile = "cpu-profile"
FlagMinGasPrices = "minimum-gas-prices"
FlagHaltHeight = "halt-height"
FlagHaltTime = "halt-time"
FlagInterBlockCache = "inter-block-cache"
FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades"
FlagTrace = "trace"
FlagInvCheckPeriod = "inv-check-period"
flagWithTendermint = "with-tendermint"
flagAddress = "address"
flagTransport = "transport"
flagTraceStore = "trace-store"
flagCPUProfile = "cpu-profile"
FlagMinGasPrices = "minimum-gas-prices"
FlagHaltHeight = "halt-height"
FlagHaltTime = "halt-time"
FlagInterBlockCache = "inter-block-cache"
FlagInterBlockCacheSize = "inter-block-cache-size"
FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades"
FlagTrace = "trace"
FlagInvCheckPeriod = "inv-check-period"

FlagPruning = "pruning"
FlagPruningKeepRecent = "pruning-keep-recent"
Expand Down Expand Up @@ -166,13 +169,15 @@ is performed. Note, when enabled, gRPC will also be automatically enabled.
cmd.Flags().Uint64(FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node")
cmd.Flags().Uint64(FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node")
cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching")
cmd.Flags().Uint(FlagInterBlockCacheSize, cache.DefaultCommitKVStoreCacheSize, "The size of inter-block caching store")
cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file")
cmd.Flags().Bool(FlagTrace, false, "Provide full stack traces for errors in ABCI Log")
cmd.Flags().String(FlagPruning, pruningtypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)")
cmd.Flags().Uint64(FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')")
cmd.Flags().Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')")
cmd.Flags().Uint(FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks")
cmd.Flags().Uint64(FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks")
cmd.Flags().Uint64(FlagIAVLCacheSize, iavl.DefaultIAVLCacheSize, "The size of iavl caching store")

cmd.Flags().Bool(FlagAPIEnable, false, "Define if the API server should be enabled")
cmd.Flags().Bool(FlagAPISwagger, false, "Define if swagger documentation should automatically be registered (Note: the API must also be enabled)")
Expand Down
13 changes: 10 additions & 3 deletions store/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ var (
_ types.CommitKVStore = (*CommitKVStoreCache)(nil)
_ types.MultiStorePersistentCache = (*CommitKVStoreCacheManager)(nil)

// DefaultCommitKVStoreCacheSize defines the persistent ARC cache size for a
// CommitKVStoreCache.
DefaultCommitKVStoreCacheSize uint = 1000
// DefaultCommitKVStoreCacheSize defines the number of persistent ARC cache item for a
// CommitKVStoreCache, which is supposed to be 10MB size.
// Each cache item consumes 128 bytes, 64 bytes for the left sibling, and 64 bytes for the right sibling.
// The number of cache item is calculated as 10 MB = 10,000,000 / 128 = 78_125
DefaultCommitKVStoreCacheSize uint = 78_125
)

type (
Expand Down Expand Up @@ -59,6 +61,11 @@ func NewCommitKVStoreCacheManager(size uint) *CommitKVStoreCacheManager {
}
}

// SetCacheSize sets the cache size of the CommitKVStore.
func (cmgr *CommitKVStoreCacheManager) SetCacheSize(size uint) {
cmgr.cacheSize = size
}

// GetStoreCache returns a Cache from the CommitStoreCacheManager for a given
// StoreKey. If no Cache exists for the StoreKey, then one is created and set.
// The returned Cache is meant to be used in a persistent manner.
Expand Down
5 changes: 4 additions & 1 deletion store/iavl/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import (
)

const (
DefaultIAVLCacheSize = 500000
// DefaultIAVLCacheSize defines the number of iavl cache item, which is supposed to be 100MB size.
// Each cache item consumes 128 bytes, 64 bytes for the left sibling, and 64 bytes for the right sibling.
// The number of cache item is calculated as 100 MB = 10,000,000 / 128 = 781_250
DefaultIAVLCacheSize = 781_250
)

var (
Expand Down
3 changes: 3 additions & 0 deletions store/types/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ type MultiStorePersistentCache interface {
// cache.
GetStoreCache(key StoreKey, store CommitKVStore) CommitKVStore

// Sets the cache size of the provided CommitKVStore
SetCacheSize(size uint)

// Return the underlying CommitKVStore for a StoreKey.
Unwrap(key StoreKey) CommitKVStore

Expand Down
23 changes: 23 additions & 0 deletions x/staking/keeper/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,29 @@ func (k Keeper) Delegate(

delegatorAddress := sdk.MustAccAddressFromBech32(delegation.DelegatorAddress)

// If Delegations are allowed again, limit validator power to 20%
if ctx.ChainID() == ColumbusChainID {
// Get the last Total Power of the validator set
lastPower := k.GetLastTotalPower(ctx)

// Get the power of the current validator power
validatorLastPower := sdk.TokensToConsensusPower(validator.Tokens, k.PowerReduction(ctx))

// Get the new power of the validator if delegated the bond amount
validatorNewPower := validatorLastPower + sdk.TokensToConsensusPower(bondAmt, k.PowerReduction(ctx))

// Compute what the Total Consensus Power would be if this Delegation goes through
newTotalPower := lastPower.Int64() + sdk.TokensToConsensusPower(bondAmt, k.PowerReduction(ctx))

// Compute what the new Validator voting power would be in relation to the new total power
// validatorIncreasedDelegationPercent := float32(validatorNewPower) / float32(newTotalPower)
validatorIncreasedDelegationPercent := sdk.NewDec(validatorNewPower).QuoInt64(newTotalPower)

// If Delegations are allowed, and the Delegation would have increased the Validator to over 20% of the staking power, do not allow the Delegation to proceed
if validatorIncreasedDelegationPercent.GT(sdk.NewDecWithPrec(20, 2)) {
panic("validator power is over the allowed limit")
}
}
// if subtractAccount is true then we are
// performing a delegation and not a redelegation, thus the source tokens are
// all non bonded
Expand Down
2 changes: 2 additions & 0 deletions x/staking/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/staking/types"
)

const ColumbusChainID = "columbus-5"

type msgServer struct {
Keeper
}
Expand Down

0 comments on commit c4e15be

Please sign in to comment.