Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
cool-develope committed Sep 30, 2024
1 parent 4197471 commit 5a9091f
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 29 deletions.
4 changes: 4 additions & 0 deletions server/v2/stf/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ require (
cosmossdk.io/core v1.0.0-alpha.3
cosmossdk.io/schema v0.3.0
github.com/cosmos/gogoproto v1.7.0
github.com/stretchr/testify v1.8.4
github.com/tidwall/btree v1.7.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 10 additions & 0 deletions server/v2/stf/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@ cosmossdk.io/schema v0.3.0 h1:01lcaM4trhzZ1HQTfTV8z6Ma1GziOZ/YmdzBN3F720c=
cosmossdk.io/schema v0.3.0/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro=
github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
79 changes: 53 additions & 26 deletions server/v2/stf/stf.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ func (s STF[T]) DeliverBlock(

// reset events
exCtx.events = make([]event.Event, 0)
exCtx.txIndex = 0
// pre block is called separate from begin block in order to prepopulate state
preBlockEvents, err := s.preBlock(exCtx, block.Txs)
if err != nil {
Expand All @@ -124,7 +123,6 @@ func (s STF[T]) DeliverBlock(

// reset events
exCtx.events = make([]event.Event, 0)
exCtx.txIndex = 0
// begin block
var beginBlockEvents []event.Event
if !block.IsGenesis {
Expand All @@ -142,14 +140,13 @@ func (s STF[T]) DeliverBlock(

// execute txs
txResults := make([]server.TxResult, len(block.Txs))
exCtx.txIndex = 0
// 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)
txResults[i] = s.deliverTx(exCtx, newState, txBytes, transaction.ExecModeFinalize, hi, int32(i+1))
}
// reset events
exCtx.events = make([]event.Event, 0)
Expand All @@ -175,6 +172,7 @@ func (s STF[T]) deliverTx(
tx T,
execMode transaction.ExecMode,
hi header.Info,
txIndex int32,
) server.TxResult {
// recover in the case of a panic
var recoveryError error
Expand All @@ -197,18 +195,32 @@ func (s STF[T]) deliverTx(
Error: recoveryError,
}
}
// TODO: how to handle msgIndex and eventIndex ???
validateGas, validationEvents, err := s.validateTx(ctx, state, gasLimit, tx, execMode)
if err != nil {
return server.TxResult{
Error: err,
}
}
events := make([]event.Event, 0)
// set the event indexes, set MsgIndex to 0 in validation events
for i, e := range validationEvents {
e.BlockStage = appdata.TxProcessingStage
e.TxIndex = txIndex
e.MsgIndex = 0
e.EventIndex = int32(i + 1)
events = append(events, e)
}

execResp, execGas, execEvents, err := s.execTx(ctx, state, gasLimit-validateGas, tx, execMode, hi)
// TODO: should handle execCtx.txIndex with events
// set the TxIndex in the exec events
for _, e := range execEvents {
e.BlockStage = appdata.TxProcessingStage
e.TxIndex = txIndex
events = append(events, e)
}

return server.TxResult{
Events: append(validationEvents, execEvents...),
Events: events,
GasUsed: execGas + validateGas,
GasWanted: gasLimit,
Resp: execResp,
Expand Down Expand Up @@ -274,14 +286,19 @@ func (s STF[T]) execTx(
if applyErr != nil {
return nil, 0, nil, applyErr
}
// set the event indexes, set MsgIndex to -1 in post tx events
for i := range postTxCtx.events {
postTxCtx.events[i].EventIndex = int32(i + 1)
postTxCtx.events[i].MsgIndex = -1
}

return nil, gasUsed, postTxCtx.events, txErr
}
// tx execution went fine, now we use the same state to run the post tx exec handler,
// in case the execution of the post tx fails, then no state change is applied and the
// whole execution step is rolled back.
postTxCtx := s.makeContext(ctx, RuntimeIdentity, execState, execMode) // NO gas limit.
postTxCtx.setHeaderInfo(hi)
// TODO: how to handle msgIndex and eventIndex ???
postTxErr := s.postTxExec(postTxCtx, tx, true)
if postTxErr != nil {
// if post tx fails, then we do not apply any state change, we return the post tx error,
Expand All @@ -294,6 +311,11 @@ func (s STF[T]) execTx(
if applyErr != nil {
return nil, 0, nil, applyErr
}
// set the event indexes, set MsgIndex to -1 in post tx events
for i := range postTxCtx.events {
postTxCtx.events[i].EventIndex = int32(i + 1)
postTxCtx.events[i].MsgIndex = -1
}

return msgsResp, gasUsed, append(runTxMsgsEvents, postTxCtx.events...), nil
}
Expand All @@ -320,17 +342,24 @@ func (s STF[T]) runTxMsgs(
execCtx := s.makeContext(ctx, RuntimeIdentity, state, execMode)
execCtx.setHeaderInfo(hi)
execCtx.setGasLimit(gasLimit)
events := make([]event.Event, 0)
for i, msg := range msgs {
execCtx.sender = txSenders[i]
resp, err := s.msgRouter.Invoke(execCtx, msg) // TODO: should handle execCtx.msgIndex with events
execCtx.events = make([]event.Event, 0) // reset events
resp, err := s.msgRouter.Invoke(execCtx, msg)
if err != nil {
return nil, 0, nil, err // do not wrap the error or we lose the original error type
}
msgResps[i] = resp
for j, e := range execCtx.events {
e.MsgIndex = int32(i + 1)
e.EventIndex = int32(j + 1)
events = append(events, e)
}
}

consumed := execCtx.meter.Limit() - execCtx.meter.Remaining()
return msgResps, consumed, execCtx.events, nil
return msgResps, consumed, events, nil
}

// preBlock executes the pre block logic.
Expand All @@ -345,6 +374,7 @@ func (s STF[T]) preBlock(

for i := range ctx.events {
ctx.events[i].BlockStage = appdata.PreBlockStage
ctx.events[i].EventIndex = int32(i + 1)
}

return ctx.events, nil
Expand All @@ -361,6 +391,7 @@ func (s STF[T]) beginBlock(

for i := range ctx.events {
ctx.events[i].BlockStage = appdata.BeginBlockStage
ctx.events[i].EventIndex = int32(i + 1)
}

return ctx.events, nil
Expand All @@ -374,30 +405,30 @@ func (s STF[T]) endBlock(
if err != nil {
return nil, nil, err
}

events, valsetUpdates, err := s.validatorUpdates(ctx)
events := ctx.events
ctx.events = make([]event.Event, 0) // reset events
valsetUpdates, err := s.validatorUpdates(ctx)
if err != nil {
return nil, nil, err
}

ctx.events = append(ctx.events, events...)

for i := range ctx.events {
ctx.events[i].BlockStage = appdata.EndBlockStage
events = append(events, ctx.events...)
for i := range events {
events[i].BlockStage = appdata.EndBlockStage
events[i].EventIndex = int32(i + 1)
}

return ctx.events, valsetUpdates, nil
return events, valsetUpdates, nil
}

// validatorUpdates returns the validator updates for the current block. It is called by endBlock after the endblock execution has concluded
func (s STF[T]) validatorUpdates(
ctx *executionContext,
) ([]event.Event, []appmodulev2.ValidatorUpdate, error) {
) ([]appmodulev2.ValidatorUpdate, error) {
valSetUpdates, err := s.doValidatorUpdate(ctx)
if err != nil {
return nil, nil, err
return nil, err
}
return ctx.events, valSetUpdates, nil
return valSetUpdates, nil
}

// Simulate simulates the execution of a tx on the provided state.
Expand All @@ -412,7 +443,7 @@ func (s STF[T]) Simulate(
if err != nil {
return server.TxResult{}, nil
}
txr := s.deliverTx(ctx, simulationState, tx, internal.ExecModeSimulate, hi)
txr := s.deliverTx(ctx, simulationState, tx, internal.ExecModeSimulate, hi, 0)

return txr, simulationState
}
Expand Down Expand Up @@ -496,10 +527,6 @@ type executionContext struct {

msgRouter router.Service
queryRouter router.Service

txIndex int32
msgIndex int32
eventIndex int32 // TODO: how to pass it to the handlers?
}

// setHeaderInfo sets the header info in the state to be used by queries in the future.
Expand Down
1 change: 0 additions & 1 deletion server/v2/stf/stf_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,5 @@ func (r coreRouterImpl) Invoke(ctx context.Context, req transaction.Msg) (res tr
if !exists {
return nil, fmt.Errorf("%w: %s", ErrNoHandler, typeName)
}
// TODO: should handle ctx.eventIndex, eventIndex should be embedded as a value in the context???
return handler(ctx, req)
}
93 changes: 91 additions & 2 deletions server/v2/stf/stf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import (
"time"

gogotypes "github.com/cosmos/gogoproto/types"
"github.com/stretchr/testify/require"

appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/event"
coregas "cosmossdk.io/core/gas"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/schema/appdata"
"cosmossdk.io/server/v2/stf/branch"
"cosmossdk.io/server/v2/stf/gas"
"cosmossdk.io/server/v2/stf/mock"
Expand Down Expand Up @@ -68,22 +71,48 @@ func TestSTF(t *testing.T) {
sum := sha256.Sum256([]byte("test-hash"))

s := &STF[mock.Tx]{
doPreBlock: func(ctx context.Context, txs []mock.Tx) error { return nil },
doPreBlock: func(ctx context.Context, txs []mock.Tx) error {
ctx.(*executionContext).events = append(ctx.(*executionContext).events, event.NewEvent("pre-block"))
return nil
},
doBeginBlock: func(ctx context.Context) error {
kvSet(t, ctx, "begin-block")
ctx.(*executionContext).events = append(ctx.(*executionContext).events, event.NewEvent("begin-block"))
return nil
},
doEndBlock: func(ctx context.Context) error {
kvSet(t, ctx, "end-block")
ctx.(*executionContext).events = append(ctx.(*executionContext).events, event.NewEvent("end-block"))
return nil
},
doValidatorUpdate: func(ctx context.Context) ([]appmodulev2.ValidatorUpdate, error) { return nil, nil },
doValidatorUpdate: func(ctx context.Context) ([]appmodulev2.ValidatorUpdate, error) {
ctx.(*executionContext).events = append(ctx.(*executionContext).events, event.NewEvent("validator-update"))
return nil, nil
},
doTxValidation: func(ctx context.Context, tx mock.Tx) error {
kvSet(t, ctx, "validate")
ctx.(*executionContext).events = append(
ctx.(*executionContext).events,
event.NewEvent("validate-tx", event.NewAttribute("sender", string(tx.Sender))),
event.NewEvent(
"validate-tx",
event.NewAttribute("sender", string(tx.Sender)),
event.NewAttribute("index", "2"),
),
)
return nil
},
postTxExec: func(ctx context.Context, tx mock.Tx, success bool) error {
kvSet(t, ctx, "post-tx-exec")
ctx.(*executionContext).events = append(
ctx.(*executionContext).events,
event.NewEvent("post-tx-exec", event.NewAttribute("sender", string(tx.Sender))),
event.NewEvent(
"post-tx-exec",
event.NewAttribute("sender", string(tx.Sender)),
event.NewAttribute("index", "2"),
),
)
return nil
},
branchFn: branch.DefaultNewWriterMap,
Expand All @@ -93,6 +122,15 @@ func TestSTF(t *testing.T) {

addMsgHandlerToSTF(t, s, func(ctx context.Context, msg *gogotypes.BoolValue) (*gogotypes.BoolValue, error) {
kvSet(t, ctx, "exec")
ctx.(*executionContext).events = append(
ctx.(*executionContext).events,
event.NewEvent("handle-msg", event.NewAttribute("msg", msg.String())),
event.NewEvent(
"handle-msg",
event.NewAttribute("msg", msg.String()),
event.NewAttribute("index", "2"),
),
)
return nil, nil
})

Expand Down Expand Up @@ -135,6 +173,57 @@ func TestSTF(t *testing.T) {
if txResult.GasWanted != mockTx.GasLimit {
t.Errorf("Expected GasWanted to be %d, got %d", mockTx.GasLimit, txResult.GasWanted)
}

// check PreBlockEvents
require.Len(t, result.PreBlockEvents, 1)
require.Equal(t, "pre-block", result.PreBlockEvents[0].Type)
require.Equal(t, appdata.PreBlockStage, result.PreBlockEvents[0].BlockStage)
require.Equal(t, int32(1), result.PreBlockEvents[0].EventIndex)
// check BeginBlockEvents
require.Len(t, result.BeginBlockEvents, 1)
require.Equal(t, "begin-block", result.BeginBlockEvents[0].Type)
require.Equal(t, appdata.BeginBlockStage, result.BeginBlockEvents[0].BlockStage)
require.Equal(t, int32(1), result.BeginBlockEvents[0].EventIndex)
// check EndBlockEvents
require.Len(t, result.EndBlockEvents, 2)
require.Equal(t, "end-block", result.EndBlockEvents[0].Type)
require.Equal(t, "validator-update", result.EndBlockEvents[1].Type)
require.Equal(t, appdata.EndBlockStage, result.EndBlockEvents[1].BlockStage)
require.Equal(t, int32(1), result.EndBlockEvents[0].EventIndex)
require.Equal(t, int32(2), result.EndBlockEvents[1].EventIndex)
// check TxEvents
require.Len(t, txResult.Events, 6)
for i, event := range txResult.Events {
require.Equal(t, appdata.TxProcessingStage, event.BlockStage)
require.Equal(t, int32(1), event.TxIndex)
require.Equal(t, int32(i%2+1), event.EventIndex)
attrs, err := event.Attributes()
require.NoError(t, err)
require.Less(t, len(attrs), 3)
require.Greater(t, len(attrs), 0)
if len(attrs) == 2 {
require.Equal(t, "index", attrs[1].Key)
require.Equal(t, "2", attrs[1].Value)
}
switch i {
case 0, 1:
require.Equal(t, "validate-tx", event.Type)
require.Equal(t, int32(0), event.MsgIndex)
require.Equal(t, "sender", attrs[0].Key)
require.Equal(t, "sender", attrs[0].Value)
case 2, 3:
require.Equal(t, "handle-msg", event.Type)
require.Equal(t, int32(1), event.MsgIndex)
require.Equal(t, "msg", attrs[0].Key)
require.Equal(t, "&BoolValue{Value:true,XXX_unrecognized:[],}", attrs[0].Value)

case 4, 5:
require.Equal(t, "post-tx-exec", event.Type)
require.Equal(t, int32(-1), event.MsgIndex)
require.Equal(t, "sender", attrs[0].Key)
require.Equal(t, "sender", attrs[0].Value)
}
}
})

t.Run("exec tx out of gas", func(t *testing.T) {
Expand Down

0 comments on commit 5a9091f

Please sign in to comment.