Skip to content

Commit

Permalink
feat(sims): Integration with app v2 (#23013)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex | Interchain Labs <[email protected]>
  • Loading branch information
alpe and Alex | Interchain Labs authored Jan 9, 2025
1 parent 39a55ed commit cf721a6
Show file tree
Hide file tree
Showing 27 changed files with 1,217 additions and 48 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
Every module contains its own CHANGELOG.md. Please refer to the module you are interested in.

### Features

* (sims) [#23013](https://github.com/cosmos/cosmos-sdk/pull/23013) Integration with app v2
* (baseapp) [#20291](https://github.com/cosmos/cosmos-sdk/pull/20291) Simulate nested messages.
* (client/keys) [#21829](https://github.com/cosmos/cosmos-sdk/pull/21829) Add support for importing hex key using standard input.
* (x/auth/ante) [#23128](https://github.com/cosmos/cosmos-sdk/pull/23128) Allow custom verifyIsOnCurve when validate tx for public key like ethsecp256k1.
Expand Down
5 changes: 5 additions & 0 deletions runtime/v2/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,8 @@ func (a *App[T]) SchemaDecoderResolver() decoding.DecoderResolver {
func (a *App[T]) Close() error {
return nil
}

// GetApp return self
func (a *App[T]) GetApp() *App[T] {
return a
}
10 changes: 8 additions & 2 deletions scripts/build/simulations.mk
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,16 @@ test-sim-multi-seed-long:
# @cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout=2h -tags='sims' -run TestFullAppSimulation \
# -NumBlocks=150 -Period=50

test-sim-multi-seed-short:
test-sim-multi-seed-short: test-v2-sim
# @echo "Running short multi-seed application simulation. This may take awhile!"
# @cd ${CURRENT_DIR}/simapp && go test -failfast -mod=readonly -timeout 30m -tags='sims' -run TestFullAppSimulation \
# -NumBlocks=50 -Period=10 -FauxMerkle=true
# -NumBlocks=50 -Period=10 -FauxMerkle=true

.Phony: test-v2-sim
test-v2-sim:
@echo "Running short multi-seed application simulation. This may take awhile!"
@cd ${CURRENT_DIR}/simapp/v2 && go test -failfast -mod=readonly -timeout 30m -tags='sims' -run TestSimsAppV2 \
# -NumBlocks=50 -Period=10 -FauxMerkle=true

test-sim-benchmark-invariants:
# @echo "Running simulation invariant benchmarks..."
Expand Down
37 changes: 37 additions & 0 deletions server/v2/appmanager/appmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"iter"

"cosmossdk.io/core/server"
corestore "cosmossdk.io/core/store"
Expand All @@ -16,6 +17,8 @@ import (
// It is responsible for interacting with stf and store.
// Runtime/v2 is an extension of this interface.
type AppManager[T transaction.Tx] interface {
TransactionFuzzer[T]

// InitGenesis initializes the genesis state of the application.
InitGenesis(
ctx context.Context,
Expand Down Expand Up @@ -55,6 +58,17 @@ type AppManager[T transaction.Tx] interface {
QueryWithState(ctx context.Context, state corestore.ReaderMap, request transaction.Msg) (transaction.Msg, error)
}

// TransactionFuzzer defines an interface for processing simulated transactions and generating responses with state changes.
type TransactionFuzzer[T transaction.Tx] interface {
// DeliverSims processes simulated transactions for a block and generates a response with potential state changes.
// The simsBuilder generates simulated transactions.
DeliverSims(
ctx context.Context,
block *server.BlockRequest[T],
simsBuilder func(ctx context.Context) iter.Seq[T],
) (*server.BlockResponse, corestore.WriterMap, error)
}

// Store defines the underlying storage behavior needed by AppManager.
type Store interface {
// StateLatest returns a readonly view over the latest
Expand Down Expand Up @@ -187,6 +201,29 @@ func (a appManager[T]) DeliverBlock(
return blockResponse, newState, nil
}

// DeliverSims same as DeliverBlock for sims only.
func (a appManager[T]) DeliverSims(
ctx context.Context,
block *server.BlockRequest[T],
simsBuilder func(ctx context.Context) iter.Seq[T],
) (*server.BlockResponse, corestore.WriterMap, error) {
latestVersion, currentState, err := a.db.StateLatest()
if err != nil {
return nil, nil, fmt.Errorf("unable to create new state for height %d: %w", block.Height, err)
}

if latestVersion+1 != block.Height {
return nil, nil, fmt.Errorf("invalid DeliverSims height wanted %d, got %d", latestVersion+1, block.Height)
}

blockResponse, newState, err := a.stf.DeliverSims(ctx, block, currentState, simsBuilder)
if err != nil {
return nil, nil, fmt.Errorf("sims delivery failed: %w", err)
}

return blockResponse, newState, nil
}

// ValidateTx will validate the tx against the latest storage state. This means that
// only the stateful validation will be run, not the execution portion of the tx.
// If full execution is needed, Simulate must be used.
Expand Down
9 changes: 9 additions & 0 deletions server/v2/appmanager/stf.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package appmanager

import (
"context"
"iter"

"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
Expand Down Expand Up @@ -40,4 +41,12 @@ type StateTransitionFunction[T transaction.Tx] interface {
gasLimit uint64,
req transaction.Msg,
) (transaction.Msg, error)

// DeliverSims provides an interface for state transitions by sims.
DeliverSims(
ctx context.Context,
block *server.BlockRequest[T],
state store.ReaderMap,
simsBuilder func(ctx context.Context) iter.Seq[T],
) (blockResult *server.BlockResponse, newState store.WriterMap, err error)
}
34 changes: 34 additions & 0 deletions server/v2/stf/sims_entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package stf

import (
"context"
"iter"

"cosmossdk.io/core/header"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
)

// doSimsTXs constructs a function to simulate transactions in a block execution context using the provided simsBuilder.
func (s STF[T]) doSimsTXs(simsBuilder func(ctx context.Context) iter.Seq[T]) doInBlockDeliveryFn[T] {
return func(
exCtx context.Context,
_ []T,
newState store.WriterMap,
headerInfo header.Info,
) ([]server.TxResult, error) {
const key = "sims.header.time"
simsCtx := context.WithValue(exCtx, key, headerInfo.Time) //nolint: staticcheck // using string key to decouple
var results []server.TxResult
var i int32
for tx := range simsBuilder(simsCtx) {
if err := isCtxCancelled(simsCtx); err != nil {
return nil, err
}
results = append(results, s.deliverTx(simsCtx, newState, tx, transaction.ExecModeFinalize, headerInfo, i+1))
i++
}
return results, nil
}
}
58 changes: 50 additions & 8 deletions server/v2/stf/stf.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"iter"
"strings"

appmodulev2 "cosmossdk.io/core/appmodule/v2"
Expand Down Expand Up @@ -84,13 +85,40 @@ func New[T transaction.Tx](
}, nil
}

// DeliverSims entrypoint to processes sims transactions similar to DeliverBlock.
func (s STF[T]) DeliverSims(
ctx context.Context,
block *server.BlockRequest[T],
state store.ReaderMap,
simsBuilder func(ctx context.Context) iter.Seq[T],
) (blockResult *server.BlockResponse, newState store.WriterMap, err error) {
return s.deliverBlock(ctx, block, state, s.doSimsTXs(simsBuilder))
}

// DeliverBlock is our state transition function.
// It takes a read only view of the state to apply the block to,
// executes the block and returns the block results and the new state.
func (s STF[T]) DeliverBlock(
ctx context.Context,
block *server.BlockRequest[T],
state store.ReaderMap,
) (blockResult *server.BlockResponse, newState store.WriterMap, err error) {
return s.deliverBlock(ctx, block, state, s.doDeliverTXs)
}

// common code path for DeliverSims and DeliverBlock
type doInBlockDeliveryFn[T transaction.Tx] func(
ctx context.Context,
txs []T,
newState store.WriterMap,
hi header.Info,
) ([]server.TxResult, error)

func (s STF[T]) deliverBlock(
ctx context.Context,
block *server.BlockRequest[T],
state store.ReaderMap,
doInBlockDelivery doInBlockDeliveryFn[T],
) (blockResult *server.BlockResponse, newState store.WriterMap, err error) {
// creates a new branchFn state, from the readonly view of the state
// that can be written to.
Expand Down Expand Up @@ -141,14 +169,9 @@ func (s STF[T]) DeliverBlock(
}

// execute txs
txResults := make([]server.TxResult, len(block.Txs))
// TODO: skip first tx if vote extensions are enabled (marko)
for i, txBytes := range block.Txs {
// check if we need to return early or continue delivering txs
if err = isCtxCancelled(ctx); err != nil {
return nil, nil, err
}
txResults[i] = s.deliverTx(exCtx, newState, txBytes, transaction.ExecModeFinalize, hi, int32(i+1))
txResults, err := doInBlockDelivery(exCtx, block.Txs, newState, hi)
if err != nil {
return nil, nil, err
}
// reset events
exCtx.events = make([]event.Event, 0)
Expand All @@ -167,6 +190,25 @@ func (s STF[T]) DeliverBlock(
}, newState, nil
}

func (s STF[T]) doDeliverTXs(
exCtx context.Context,
txs []T,
newState store.WriterMap,
hi header.Info,
) ([]server.TxResult, error) {
// execute txs
txResults := make([]server.TxResult, len(txs))
// TODO: skip first tx if vote extensions are enabled (marko)
for i, txBytes := range txs {
// check if we need to return early or continue delivering txs
if err := isCtxCancelled(exCtx); err != nil {
return nil, err
}
txResults[i] = s.deliverTx(exCtx, newState, txBytes, transaction.ExecModeFinalize, hi, int32(i+1))
}
return txResults, nil
}

// deliverTx executes a TX and returns the result.
func (s STF[T]) deliverTx(
ctx context.Context,
Expand Down
3 changes: 2 additions & 1 deletion server/v2/streaming/examples/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"os"
"path/filepath"

"cosmossdk.io/server/v2/streaming"
"github.com/hashicorp/go-plugin"

"cosmossdk.io/server/v2/streaming"
)

// FilePlugin is the implementation of the baseapp.ABCIListener interface
Expand Down
7 changes: 5 additions & 2 deletions simapp/v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ require (

require github.com/cosmos/iavl/v2 v2.0.0-alpha.4 // indirect

require (
cosmossdk.io/server/v2/appmanager v1.0.0-beta.1
github.com/cometbft/cometbft/api v1.0.0
)

require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.1-20241120201313-68e42a58b301.1 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.1-20240130113600-88ef6483f90f.1 // indirect
Expand All @@ -64,7 +69,6 @@ require (
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/errors/v2 v2.0.0 // indirect
cosmossdk.io/schema v1.0.0 // indirect
cosmossdk.io/server/v2/appmanager v1.0.0-beta.1 // indirect
cosmossdk.io/server/v2/stf v1.0.0-beta.1 // indirect
cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43 // indirect
cosmossdk.io/x/tx v1.0.0 // indirect
Expand Down Expand Up @@ -96,7 +100,6 @@ require (
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/cometbft/cometbft-db v1.0.1 // indirect
github.com/cometbft/cometbft/api v1.0.0 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-db v1.1.1 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
Expand Down
Loading

0 comments on commit cf721a6

Please sign in to comment.