Skip to content

Commit

Permalink
change DeliverTx to take typed tx (#360)
Browse files Browse the repository at this point in the history
- To avoid multiple deserialization, as well as adding cached values to
sdk.Tx
- Add new acl constants for evm subprefixes
- Add a new bank send method that doesn't automatically create accounts
unit tests & local sei integration
  • Loading branch information
codchen authored and udpatil committed Mar 4, 2024
1 parent 1615293 commit 496ea0f
Show file tree
Hide file tree
Showing 14 changed files with 428 additions and 335 deletions.
13 changes: 8 additions & 5 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,12 @@ func (app *BaseApp) CheckTx(ctx context.Context, req *abci.RequestCheckTx) (*abc
}

sdkCtx := app.getContextForTx(mode, req.Tx)
gInfo, result, _, priority, err := app.runTx(sdkCtx, mode, req.Tx)
tx, err := app.txDecoder(req.Tx)
if err != nil {
res := sdkerrors.ResponseCheckTx(err, 0, 0, app.trace)
return &res, err
}
gInfo, result, _, priority, err := app.runTx(sdkCtx, mode, tx, sha256.Sum256(req.Tx))
if err != nil {
res := sdkerrors.ResponseCheckTx(err, gInfo.GasWanted, gInfo.GasUsed, app.trace)
return &res, err
Expand Down Expand Up @@ -256,9 +261,7 @@ func (app *BaseApp) DeliverTxBatch(ctx sdk.Context, req sdk.DeliverTxBatchReques
// Otherwise, the ResponseDeliverTx will contain relevant error information.
// Regardless of tx execution outcome, the ResponseDeliverTx will contain relevant
// gas execution context.
// TODO: (occ) this is the function called from sei-chain to perform execution of a transaction.
// We'd likely replace this with an execution tasks that is scheduled by the OCC scheduler
func (app *BaseApp) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTx) (res abci.ResponseDeliverTx) {
func (app *BaseApp) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTx, tx sdk.Tx, checksum [32]byte) (res abci.ResponseDeliverTx) {
defer telemetry.MeasureSince(time.Now(), "abci", "deliver_tx")
defer func() {
for _, streamingListener := range app.abciListeners {
Expand All @@ -278,7 +281,7 @@ func (app *BaseApp) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTx) (res a
telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted")
}()

gInfo, result, anteEvents, _, err := app.runTx(ctx.WithTxBytes(req.Tx).WithVoteInfos(app.voteInfos), runTxModeDeliver, req.Tx)
gInfo, result, anteEvents, _, err := app.runTx(ctx.WithTxBytes(req.Tx).WithVoteInfos(app.voteInfos), runTxModeDeliver, tx, checksum)
if err != nil {
resultStr = "failed"
// if we have a result, use those events instead of just the anteEvents
Expand Down
22 changes: 9 additions & 13 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package baseapp

import (
"context"
"crypto/sha256"
"fmt"
"reflect"
"strings"
Expand Down Expand Up @@ -802,16 +801,15 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) sdk.Context

// cacheTxContext returns a new context based off of the provided context with
// a branched multi-store.
// TODO: (occ) This is an example of where we wrap the multistore with a cache multistore, and then return a modified context using that multistore
func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context, sdk.CacheMultiStore) {
func (app *BaseApp) cacheTxContext(ctx sdk.Context, checksum [32]byte) (sdk.Context, sdk.CacheMultiStore) {
ms := ctx.MultiStore()
// TODO: https://github.com/cosmos/cosmos-sdk/issues/2824
msCache := ms.CacheMultiStore()
if msCache.TracingEnabled() {
msCache = msCache.SetTracingContext(
sdk.TraceContext(
map[string]interface{}{
"txHash": fmt.Sprintf("%X", sha256.Sum256(txBytes)),
"txHash": fmt.Sprintf("%X", checksum),
},
),
).(sdk.CacheMultiStore)
Expand All @@ -827,8 +825,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(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, priority int64, err error) {

func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [32]byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, priority int64, err error) {
defer telemetry.MeasureThroughputSinceWithLabels(
telemetry.TxCount,
[]metrics.Label{
Expand All @@ -852,7 +849,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf
spanCtx, span := app.TracingInfo.StartWithContext("RunTx", ctx.TraceSpanContext())
defer span.End()
ctx = ctx.WithTraceSpanContext(spanCtx)
span.SetAttributes(attribute.String("txHash", fmt.Sprintf("%X", sha256.Sum256(txBytes))))
span.SetAttributes(attribute.String("txHash", fmt.Sprintf("%X", checksum)))
}

// NOTE: GasWanted should be returned by the AnteHandler. GasUsed is
Expand All @@ -874,9 +871,8 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf
gInfo = sdk.GasInfo{GasWanted: gasWanted, GasUsed: ctx.GasMeter().GasConsumed()}
}()

tx, err := app.txDecoder(txBytes)
if err != nil {
return sdk.GasInfo{}, nil, nil, 0, err
if tx == nil {
return sdk.GasInfo{}, nil, nil, 0, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx decode error")
}

msgs := tx.GetMsgs()
Expand All @@ -903,7 +899,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf
// NOTE: Alternatively, we could require that AnteHandler ensures that
// writes do not happen if aborted/failed. This may have some
// performance benefits, but it'll be more difficult to get right.
anteCtx, msCache = app.cacheTxContext(ctx, txBytes)
anteCtx, msCache = app.cacheTxContext(ctx, checksum)
anteCtx = anteCtx.WithEventManager(sdk.NewEventManager())
newCtx, err := app.anteHandler(anteCtx, tx, mode == runTxModeSimulate)

Expand Down Expand Up @@ -958,7 +954,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf
// Create a new Context based off of the existing Context with a MultiStore branch
// in case message processing fails. At this point, the MultiStore
// is a branch of a branch.
runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes)
runMsgCtx, msCache := app.cacheTxContext(ctx, checksum)

// Attempt to execute all messages and only update state if all messages pass
// and we're in DeliverTx. Note, runMsgs will never return a reference to a
Expand Down Expand Up @@ -1020,7 +1016,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s
err error
)

msgCtx, msgMsCache := app.cacheTxContext(ctx, []byte{})
msgCtx, msgMsCache := app.cacheTxContext(ctx, [32]byte{})
msgCtx = msgCtx.WithMessageIndex(i)

startTime := time.Now()
Expand Down
33 changes: 20 additions & 13 deletions baseapp/deliver_tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package baseapp
import (
"bytes"
"context"
"crypto/sha256"
"encoding/binary"
"fmt"
"math/rand"
Expand Down Expand Up @@ -228,7 +229,8 @@ func TestWithRouter(t *testing.T) {
txBytes, err := codec.Marshal(tx)
require.NoError(t, err)

res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
decoded, _ := app.txDecoder(txBytes)
res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes))
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
}

Expand Down Expand Up @@ -434,7 +436,8 @@ func TestMultiMsgDeliverTx(t *testing.T) {
tx := newTxCounter(0, 0, 1, 2)
txBytes, err := codec.Marshal(tx)
require.NoError(t, err)
res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
decoded, _ := app.txDecoder(txBytes)
res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes))
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))

store := app.deliverState.ctx.KVStore(capKey1)
Expand All @@ -454,7 +457,8 @@ func TestMultiMsgDeliverTx(t *testing.T) {
tx.Msgs = append(tx.Msgs, msgCounter2{1})
txBytes, err = codec.Marshal(tx)
require.NoError(t, err)
res = app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
decoded, _ = app.txDecoder(txBytes)
res = app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes))
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))

store = app.deliverState.ctx.KVStore(capKey1)
Expand Down Expand Up @@ -651,9 +655,8 @@ func TestRunInvalidTransaction(t *testing.T) {
txBytes, err := newCdc.Marshal(tx)
require.NoError(t, err)

res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
require.EqualValues(t, sdkerrors.ErrTxDecode.ABCICode(), res.Code)
require.EqualValues(t, sdkerrors.ErrTxDecode.Codespace(), res.Codespace)
_, err = app.txDecoder(txBytes)
require.NotNil(t, err)
}
}

Expand Down Expand Up @@ -922,7 +925,8 @@ func TestBaseAppAnteHandler(t *testing.T) {
tx.setFailOnAnte(true)
txBytes, err := cdc.Marshal(tx)
require.NoError(t, err)
res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
decoded, _ := app.txDecoder(txBytes)
res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes))
require.Empty(t, res.Events)
require.False(t, res.IsOK(), fmt.Sprintf("%v", res))

Expand All @@ -938,7 +942,8 @@ func TestBaseAppAnteHandler(t *testing.T) {
txBytes, err = cdc.Marshal(tx)
require.NoError(t, err)

res = app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
decoded, _ = app.txDecoder(txBytes)
res = app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes))
// should emit ante event
require.NotEmpty(t, res.Events)
require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
Expand All @@ -955,7 +960,8 @@ func TestBaseAppAnteHandler(t *testing.T) {
txBytes, err = cdc.Marshal(tx)
require.NoError(t, err)

res = app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
decoded, _ = app.txDecoder(txBytes)
res = app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes))
require.NotEmpty(t, res.Events)
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))

Expand Down Expand Up @@ -1032,7 +1038,7 @@ func TestGasConsumptionBadTx(t *testing.T) {
txBytes, err := cdc.Marshal(tx)
require.NoError(t, err)

res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, tx, sha256.Sum256(txBytes))
require.False(t, res.IsOK(), fmt.Sprintf("%v", res))

// removed the block gas exceeded because of removal of block gas meter, gasWanted < max block gas is still fulfilled by various other checks
Expand Down Expand Up @@ -1498,7 +1504,8 @@ func TestDeliverTx(t *testing.T) {
txBytes, err := codec.Marshal(tx)
require.NoError(t, err)

res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
decoded, _ := app.txDecoder(txBytes)
res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes))
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
events := res.GetEvents()
require.Len(t, events, 3, "should contain ante handler, message type and counter events respectively")
Expand Down Expand Up @@ -1700,12 +1707,12 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options
value := make([]byte, 10000)
_, err := r.Read(value)
require.NoError(t, err)
tx.Msgs = append(tx.Msgs, msgKeyValue{Key: key, Value: value})
tx.Msgs = append(tx.Msgs, &msgKeyValue{Key: key, Value: value})
keyCounter++
}
txBytes, err := codec.Marshal(tx)
require.NoError(t, err)
resp := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes})
resp := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, tx, sha256.Sum256(txBytes))
require.True(t, resp.IsOK(), "%v", resp.String())
}
app.EndBlock(app.deliverState.ctx, abci.RequestEndBlock{Height: height})
Expand Down
15 changes: 11 additions & 4 deletions baseapp/msg_service_router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package baseapp_test

import (
"context"
"crypto/sha256"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -73,18 +74,24 @@ func TestMsgService(t *testing.T) {
encCfg := simapp.MakeTestEncodingConfig()
testdata.RegisterInterfaces(encCfg.InterfaceRegistry)
db := dbm.NewMemDB()
app := baseapp.NewBaseApp("test", log.NewTestingLogger(t), db, encCfg.TxConfig.TxDecoder(), nil, &testutil.TestAppOpts{})
decoder := encCfg.TxConfig.TxDecoder()
app := baseapp.NewBaseApp("test", log.NewTestingLogger(t), db, decoder, nil, &testutil.TestAppOpts{})
app.SetInterfaceRegistry(encCfg.InterfaceRegistry)
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
app.SetFinalizeBlocker(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) {
txResults := []*abci.ExecTxResult{}
for _, tx := range req.Txs {
for _, txbz := range req.Txs {
tx, err := decoder(txbz)
if err != nil {
txResults = append(txResults, &abci.ExecTxResult{})
continue
}
deliverTxResp := app.DeliverTx(ctx, abci.RequestDeliverTx{
Tx: tx,
})
Tx: txbz,
}, tx, sha256.Sum256(txbz))
txResults = append(txResults, &abci.ExecTxResult{
Code: deliverTxResp.Code,
Data: deliverTxResp.Data,
Expand Down
16 changes: 13 additions & 3 deletions baseapp/test_helpers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package baseapp

import (
"crypto/sha256"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
Expand All @@ -15,7 +17,7 @@ func (app *BaseApp) Check(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk
return sdk.GasInfo{}, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err)
}
ctx := app.checkState.ctx.WithTxBytes(bz).WithVoteInfos(app.voteInfos).WithConsensusParams(app.GetConsensusParams(app.checkState.ctx))
gasInfo, result, _, _, err := app.runTx(ctx, runTxModeCheck, bz)
gasInfo, result, _, _, err := app.runTx(ctx, runTxModeCheck, tx, sha256.Sum256(bz))
if len(ctx.MultiStore().GetEvents()) > 0 {
panic("Expected checkTx events to be empty")
}
Expand All @@ -25,7 +27,11 @@ func (app *BaseApp) Check(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk
func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) {
ctx := app.checkState.ctx.WithTxBytes(txBytes).WithVoteInfos(app.voteInfos).WithConsensusParams(app.GetConsensusParams(app.checkState.ctx))
ctx, _ = ctx.CacheContext()
gasInfo, result, _, _, err := app.runTx(ctx, runTxModeSimulate, txBytes)
tx, err := app.txDecoder(txBytes)
if err != nil {
return sdk.GasInfo{}, nil, err
}
gasInfo, result, _, _, err := app.runTx(ctx, runTxModeSimulate, tx, sha256.Sum256(txBytes))
if len(ctx.MultiStore().GetEvents()) > 0 {
panic("Expected simulate events to be empty")
}
Expand All @@ -39,7 +45,11 @@ func (app *BaseApp) Deliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *s
return sdk.GasInfo{}, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err)
}
ctx := app.deliverState.ctx.WithTxBytes(bz).WithVoteInfos(app.voteInfos).WithConsensusParams(app.GetConsensusParams(app.deliverState.ctx))
gasInfo, result, _, _, err := app.runTx(ctx, runTxModeDeliver, bz)
decoded, err := app.txDecoder(bz)
if err != nil {
return sdk.GasInfo{}, &sdk.Result{}, err
}
gasInfo, result, _, _, err := app.runTx(ctx, runTxModeDeliver, decoded, sha256.Sum256(bz))
return gasInfo, result, err
}

Expand Down
17 changes: 15 additions & 2 deletions proto/cosmos/accesscontrol/constants.proto
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,21 @@ enum ResourceType {
reserved 94;
KV_BANK_DEFERRED_MODULE_TX_INDEX = 95; // child of KV_BANK_DEFERRED

KV_DEX_MEM_CONTRACTS_TO_PROCESS = 96; // child of KV_DEX_MEM
KV_DEX_MEM_DOWNSTREAM_CONTRACTS = 97; // child of KV_DEX_MEM
KV_EVM = 96; // child of KV
KV_EVM_BALANCE = 97; // child of KV_EVM; deprecated
KV_EVM_TRANSIENT = 98; // child of KV_EVM
KV_EVM_ACCOUNT_TRANSIENT = 99; // child of KV_EVM
KV_EVM_MODULE_TRANSIENT = 100; // child of KV_EVM
KV_EVM_NONCE = 101; // child of KV_EVM
KV_EVM_RECEIPT = 102; // child of KV_EVM
KV_EVM_S2E = 103; // child of KV_EVM
KV_EVM_E2S = 104; // child of KV_EVM
KV_EVM_CODE_HASH = 105; // child of KV_EVM
KV_EVM_CODE = 106; // child of KV_EVM
KV_EVM_CODE_SIZE = 107; // child of KV_EVM

KV_DEX_MEM_CONTRACTS_TO_PROCESS = 108; // child of KV_DEX_MEM
KV_DEX_MEM_DOWNSTREAM_CONTRACTS = 109; // child of KV_DEX_MEM
}

enum WasmMessageSubtype {
Expand Down
12 changes: 9 additions & 3 deletions server/mock/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mock

import (
"context"
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -39,10 +40,15 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
baseApp.SetInitChainer(InitChainer(capKeyMainStore))
baseApp.SetFinalizeBlocker(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) {
txResults := []*abci.ExecTxResult{}
for _, tx := range req.Txs {
for _, txbz := range req.Txs {
tx, err := decodeTx(txbz)
if err != nil {
txResults = append(txResults, &abci.ExecTxResult{})
continue
}
deliverTxResp := baseApp.DeliverTx(ctx, abci.RequestDeliverTx{
Tx: tx,
})
Tx: txbz,
}, tx, sha256.Sum256(txbz))
txResults = append(txResults, &abci.ExecTxResult{
Code: deliverTxResp.Code,
Data: deliverTxResp.Data,
Expand Down
7 changes: 6 additions & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package simapp

import (
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -515,9 +516,13 @@ func (app *SimApp) FinalizeBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlo
txResults := []*abci.ExecTxResult{}
for i, tx := range req.Txs {
ctx = ctx.WithContext(context.WithValue(ctx.Context(), ante.ContextKeyTxIndexKey, i))
if typedTxs[i] == nil {
txResults = append(txResults, &abci.ExecTxResult{}) // empty result
continue
}
deliverTxResp := app.DeliverTx(ctx, abci.RequestDeliverTx{
Tx: tx,
})
}, typedTxs[i], sha256.Sum256(tx))
txResults = append(txResults, &abci.ExecTxResult{
Code: deliverTxResp.Code,
Data: deliverTxResp.Data,
Expand Down
Loading

0 comments on commit 496ea0f

Please sign in to comment.