Skip to content

Commit

Permalink
feat: performance improvement (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonberg1997 authored Jul 6, 2023
1 parent 2881155 commit 8d58b45
Show file tree
Hide file tree
Showing 45 changed files with 1,560 additions and 227 deletions.
27 changes: 13 additions & 14 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ permissions:
# Optional: allow read access to pull request. Use with `only-new-issues` option.
# pull-requests: read
jobs:
# golangci:
# name: golangci-lint
# runs-on: ubuntu-latest
# steps:
# - uses: actions/setup-go@v3
# with:
# go-version: 1.19.8
# - uses: actions/checkout@v3
# - name: golangci-lint
# uses: golangci/golangci-lint-action@v3
# with:
# # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
# version: v1.50.1

golangci:
name: golangci-lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.20.5
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: v1.53.3
11 changes: 9 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ run:
linters:
disable-all: true
enable:
- depguard
- dogsled
- exportloopref
- goconst
Expand All @@ -18,7 +17,6 @@ linters:
- gosimple
- govet
- ineffassign
- nakedret
- nolintlint
- staticcheck
- stylecheck
Expand All @@ -39,6 +37,15 @@ issues:
- text: "ST1016:"
linters:
- stylecheck
- text: "SA1019: errors"
linters:
- staticcheck
- text: "SA1019: sdkerr"
linters:
- staticcheck
- text: "SA1019: sdkerrors"
linters:
- staticcheck
- path: "migrations"
text: "SA1019:"
linters:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ benchmark:
###############################################################################

golangci_lint_cmd=golangci-lint
golangci_version=v1.50.1
golangci_version=v1.53.3

lint:
@echo "--> Running linter"
Expand Down
65 changes: 61 additions & 4 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ import (
"syscall"
"time"

errorsmod "cosmossdk.io/errors"
abci "github.com/cometbft/cometbft/abci/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/grpc/codes"
grpcstatus "google.golang.org/grpc/status"

errorsmod "cosmossdk.io/errors"
storetypes "github.com/cosmos/cosmos-sdk/store/types"

cmtrpctypes "github.com/cometbft/cometbft/rpc/jsonrpc/types"
"github.com/cosmos/cosmos-sdk/codec"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
Expand Down Expand Up @@ -504,7 +503,65 @@ func (app *BaseApp) Commit() abci.ResponseCommit {
return res
}

// halt attempts to gracefully shutdown the node via SIGINT and SIGTERM falling
// PreBeginBlock implements the ABCI application interface.
func (app *BaseApp) PreBeginBlock(req abci.RequestPreBeginBlock) (res abci.ResponsePrefetch) {
defer func() {
if r := recover(); r != nil {
res = abci.ResponsePrefetch{Error: errorsmod.Wrapf(sdkerrors.ErrPanic, "%v", r).Error()}
}
}()

if req.Header.ChainID != app.chainID {
err := fmt.Sprintf("invalid request chain-id: %s, expected: %s", req.Header.ChainID, app.chainID)
return abci.ResponsePrefetch{Error: err}
}

if app.cms.TracingEnabled() {
app.cms.SetTracingContext(map[string]interface{}{"blockHeight": req.Header.Height})
}

// Initialize the preDeliverTx state.
app.setPreState(req.StateNumber, req.Header)

res = abci.ResponsePrefetch{Code: abci.CodeTypeOK}
return
}

func (app *BaseApp) PreDeliverTx(req abci.RequestPreDeliverTx) {
defer func() {
if r := recover(); r != nil {
return
}
}()

preState := app.preDeliverStates[req.StateIndex]
if preState == nil {
return
}

ctx := preState.ctx.
WithTxBytes(req.Tx).
WithVoteInfos(app.voteInfos)

ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx))

app.runTxOnContext(ctx, runTxModePreDeliver, req.Tx)
}

func (app *BaseApp) PreCommit(req abci.RequestPreCommit) (res abci.ResponsePrefetch) {
defer func() {
if r := recover(); r != nil {
res = abci.ResponsePrefetch{Error: errorsmod.Wrapf(sdkerrors.ErrPanic, "%v", r).Error()}
}
}()

app.preDeliverStates[req.StateIndex].ms.Write()

res = abci.ResponsePrefetch{Code: abci.CodeTypeOK}
return
}

// halt attempts to gracefully shut down the node via SIGINT and SIGTERM falling
// back on os.Exit if both fail.
func (app *BaseApp) halt() {
app.logger.Info("halting node per configuration", "height", app.haltHeight, "time", app.haltTime)
Expand Down
76 changes: 65 additions & 11 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import (
"github.com/cometbft/cometbft/libs/log"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/cosmos/gogoproto/proto"
lru "github.com/hashicorp/golang-lru"
"golang.org/x/exp/maps"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/snapshots"
"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/store/rootmulti"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
Expand All @@ -41,12 +43,15 @@ const (
runTxModeDeliver // Deliver a transaction
runTxPrepareProposal // Prepare a TM block proposal
runTxProcessProposal // Process a TM block proposal
runTxModePreDeliver // Pre-deliver a transaction

inMemorySignatures = 4096 // Number of recent block signatures to keep in memory
)

var _ abci.Application = (*BaseApp)(nil)

// BaseApp reflects the ABCI application implementation.
type BaseApp struct { // nolint: maligned
type BaseApp struct { //nolint: maligned
// initialized on creation
logger log.Logger
name string // application name from abci.Info
Expand Down Expand Up @@ -85,6 +90,8 @@ type BaseApp struct { // nolint: maligned
processProposalState *state // for ProcessProposal
prepareProposalState *state // for PrepareProposal

preDeliverStates []*state // for PreDeliverTx

// an inter-block write-through cache provided to the context during deliverState
interBlockCache sdk.MultiStorePersistentCache

Expand Down Expand Up @@ -148,6 +155,9 @@ type BaseApp struct { // nolint: maligned

// upgradeChecker is a hook function from the upgrade module to check upgrade is executed or not.
upgradeChecker func(ctx sdk.Context, name string) bool

// Signatures of recent blocks to speed up
sigCache *lru.ARCCache
}

// NewBaseApp returns a reference to an initialized BaseApp. It accepts a
Expand All @@ -169,6 +179,7 @@ func NewBaseApp(
msgServiceRouter: NewMsgServiceRouter(),
txDecoder: txDecoder,
fauxMerkleMode: false,
preDeliverStates: make([]*state, 0),
}

for _, option := range options {
Expand All @@ -189,6 +200,14 @@ func NewBaseApp(
app.SetProcessProposal(abciProposalHandler.ProcessProposalHandler())
}

if app.sigCache == nil {
sigCache, err := lru.NewARC(inMemorySignatures)
if err != nil {
panic(err)
}
app.sigCache = sigCache
}

if app.interBlockCache != nil {
app.cms.SetInterBlockCache(app.interBlockCache)
}
Expand Down Expand Up @@ -430,7 +449,7 @@ func (app *BaseApp) Seal() { app.sealed = true }
func (app *BaseApp) IsSealed() bool { return app.sealed }

// setState sets the BaseApp's state for the corresponding mode with a branched
// multi-store (i.e. a CacheMultiStore) and a new Context with the same
// multi-store (i.e., a CacheMultiStore) and a new Context with the same
// multi-store branch, and provided header.
func (app *BaseApp) setState(mode runTxMode, header tmproto.Header) {
ms := app.cms.CacheMultiStore()
Expand Down Expand Up @@ -458,6 +477,23 @@ func (app *BaseApp) setState(mode runTxMode, header tmproto.Header) {
}
}

func (app *BaseApp) setPreState(number int64, header tmproto.Header) {
app.preDeliverStates = app.preDeliverStates[:0] // reset, keep allocated memory

for i := int64(0); i < number; i++ {
var ms sdk.CacheMultiStore
if _, ok := app.cms.(*rootmulti.Store); ok {
ms = app.cms.(*rootmulti.Store).DeepCopyMultiStore()
}

baseState := &state{
ms: ms,
ctx: sdk.NewContext(ms, header, false, app.upgradeChecker, app.logger),
}
app.preDeliverStates = append(app.preDeliverStates, baseState)
}
}

// GetConsensusParams returns the current consensus parameters from the BaseApp's
// ParamStore. If the BaseApp has no ParamStore defined, nil is returned.
func (app *BaseApp) GetConsensusParams(ctx sdk.Context) *tmproto.ConsensusParams {
Expand Down Expand Up @@ -598,7 +634,8 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) sdk.Context
}
ctx := modeState.ctx.
WithTxBytes(txBytes).
WithVoteInfos(app.voteInfos)
WithVoteInfos(app.voteInfos).
WithSigCache(app.sigCache)

ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx))

Expand Down Expand Up @@ -640,12 +677,16 @@ 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) {
ctx := app.getContextForTx(mode, txBytes)
return app.runTxOnContext(ctx, mode, txBytes)
}

func (app *BaseApp) runTxOnContext(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, priority int64, 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.
var gasWanted uint64

ctx := app.getContextForTx(mode, txBytes)
ms := ctx.MultiStore()
gInfo.MinGasPrice = app.minGasPrices.String()

Expand All @@ -667,7 +708,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re

// consumeBlockGas makes sure block gas is consumed at most once. It must
// happen after tx processing, and must be executed even if tx processing
// fails. Hence, it's execution is deferred.
// fails. Hence, its execution is deferred.
consumeBlockGas := func() {
if !blockGasConsumed {
blockGasConsumed = true
Expand All @@ -678,18 +719,27 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
}

// If BlockGasMeter() panics it will be caught by the above recover and will
// return an error - in any case BlockGasMeter will consume gas past the limit.
// return an error - in any case, BlockGasMeter will consume gas past the limit.
//
// NOTE: consumeBlockGas must exist in a separate defer function from the
// general deferred recovery function to recover from consumeBlockGas as it'll
// general deferred recovery function to recover from consumeBlockGas, as it'll
// be executed first (deferred statements are executed as stack).
if mode == runTxModeDeliver {
defer consumeBlockGas()
}

tx, err := app.txDecoder(txBytes)
if err != nil {
return sdk.GasInfo{}, nil, nil, 0, err
var tx sdk.Tx
if ctx.SigCache() != nil && ctx.TxBytes() != nil {
if txCache, known := ctx.SigCache().Get(string(ctx.TxBytes())); known {
tx = txCache.(sdk.Tx)
}
}

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

msgs := tx.GetMsgs()
Expand Down Expand Up @@ -785,6 +835,10 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
msCache.Write()
}

if mode == runTxModePreDeliver {
msCache.Write()
}

if len(anteEvents) > 0 && (mode == runTxModeDeliver || mode == runTxModeSimulate) {
// append the events in the order of occurrence
result.Events = append(anteEvents, result.Events...)
Expand All @@ -806,7 +860,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s

// NOTE: GasWanted is determined by the AnteHandler and GasUsed by the GasMeter.
for i, msg := range msgs {
if mode != runTxModeDeliver && mode != runTxModeSimulate {
if mode != runTxModeDeliver && mode != runTxModeSimulate && mode != runTxModePreDeliver {
break
}

Expand Down
6 changes: 6 additions & 0 deletions baseapp/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"

dbm "github.com/cometbft/cometbft-db"
lru "github.com/hashicorp/golang-lru"

"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/snapshots"
Expand Down Expand Up @@ -298,3 +299,8 @@ func (app *BaseApp) SetPrepareProposal(handler sdk.PrepareProposalHandler) {
func (app *BaseApp) SetUpgradeChecker(checker func(sdk.Context, string) bool) {
app.upgradeChecker = checker
}

// SetSigCache is used to set a signature cache
func (app *BaseApp) SetSigCache(cache *lru.ARCCache) {
app.sigCache = cache
}
4 changes: 4 additions & 0 deletions baseapp/params_legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ func ValidateBlockParams(i interface{}) error {
return fmt.Errorf("block maximum gas must be greater than or equal to -1: %d", v.MaxGas)
}

if v.MaxTxs <= 0 {
return fmt.Errorf("block maximum tx nums must be positive: %d", v.MaxTxs)
}

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion bsc/rlp/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ func writeBigIntNoPtr(val reflect.Value, w *encbuf) error {
}

func writeBigInt(i *big.Int, w *encbuf) error {
if cmp := i.Cmp(big0); cmp == -1 { //nolint:all
if cmp := i.Cmp(big0); cmp == -1 {
return fmt.Errorf("rlp: cannot encode negative *big.Int")
} else if cmp == 0 {
w.str = append(w.str, 0x80)
Expand Down
Loading

0 comments on commit 8d58b45

Please sign in to comment.