Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: performance improvement #222

Merged
merged 15 commits into from
Jul 6, 2023
Merged
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()
forcodedancing marked this conversation as resolved.
Show resolved Hide resolved

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
}
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
2 changes: 1 addition & 1 deletion crypto/codec/tm.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import (
tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto"

"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/eth/ethsecp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/crypto/keys/eth/ethsecp256k1"
)

// FromTmProtoPublicKey converts a TM's tmprotocrypto.PublicKey into our own PubKey.
Expand Down
2 changes: 1 addition & 1 deletion crypto/keyring/keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) {
continue
}

if err := os.WriteFile(dir+"/keyhash", passwordHash, 0o555); err != nil {
if err := os.WriteFile(dir+"/keyhash", passwordHash, 0o555); err != nil { //nolint:gosec
return "", err
}

Expand Down
Loading