Skip to content

Commit

Permalink
Add test for antehandler
Browse files Browse the repository at this point in the history
  • Loading branch information
joshklop committed Dec 10, 2024
1 parent 5b6dee5 commit 4f1322f
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 102 deletions.
109 changes: 12 additions & 97 deletions e2e/stack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,10 @@ import (
"time"

authv1beta1 "cosmossdk.io/api/cosmos/auth/v1beta1"
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
"cosmossdk.io/math"
abcitypes "github.com/cometbft/cometbft/abci/types"
cometcore "github.com/cometbft/cometbft/rpc/core/types"
bfttypes "github.com/cometbft/cometbft/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cosmossecp256k1 "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
opbindings "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/receipts"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
Expand All @@ -34,9 +27,9 @@ import (
protov1 "github.com/golang/protobuf/proto" //nolint:staticcheck
"github.com/polymerdao/monomer"
"github.com/polymerdao/monomer/e2e"
"github.com/polymerdao/monomer/testutils"
rolluptypes "github.com/polymerdao/monomer/x/rollup/types"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)

func checkForRollbacks(t *testing.T, stack *e2e.StackConfig) {
Expand Down Expand Up @@ -262,18 +255,17 @@ func ethRollupFlow(t *testing.T, stack *e2e.StackConfig) {
l2ChainID, err := stack.MonomerClient.ChainID(stack.Ctx)
require.NoError(t, err)

withdrawalTxResult, err := stack.L2Client.BroadcastTxAsync(
stack.Ctx,
buildTx(t, l2ChainID.String(), baseAccount.Sequence, baseAccount.AccountNumber, userPrivKey, []protov1.Message{
&rolluptypes.MsgInitiateWithdrawal{
Sender: userCosmosAddr,
Target: withdrawalTx.Target.String(),
Value: math.NewIntFromBigInt(withdrawalTx.Value),
GasLimit: withdrawalTx.GasLimit.Bytes(),
Data: []byte{},
},
}),
)
l2WithdrawalTxBytes, err := testutils.BuildSDKTx(t, l2ChainID.String(), baseAccount.Sequence, baseAccount.AccountNumber, userPrivKey, []protov1.Message{
&rolluptypes.MsgInitiateWithdrawal{
Sender: userCosmosAddr,
Target: withdrawalTx.Target.String(),
Value: math.NewIntFromBigInt(withdrawalTx.Value),
GasLimit: withdrawalTx.GasLimit.Bytes(),
Data: []byte{},
},
}).Marshal()
require.NoError(t, err)
withdrawalTxResult, err := stack.L2Client.BroadcastTxAsync(stack.Ctx, l2WithdrawalTxBytes)
require.NoError(t, err)
require.Equalf(t, abcitypes.CodeTypeOK, withdrawalTxResult.Code, "log: "+withdrawalTxResult.Log)

Expand Down Expand Up @@ -380,83 +372,6 @@ func ethRollupFlow(t *testing.T, stack *e2e.StackConfig) {
t.Log("Monomer can initiate withdrawals on L2 and can generate proofs for verifying the withdrawal on L1")
}

func convertPrivKey(ecdsaPrivKey *ecdsa.PrivateKey) *secp256k1.PrivateKey {
privKeyBytes := ecdsaPrivKey.D.Bytes()
var key secp256k1.ModNScalar
if len(privKeyBytes) > 32 || key.SetByteSlice(privKeyBytes) {
panic("overflow")
}
if key.IsZero() {
panic("private keys must not be 0")
}
return secp256k1.NewPrivateKey(&key)
}

func buildTx(t *testing.T, chainID string, seqNum, accNum uint64, ethPrivKey *ecdsa.PrivateKey, msgs []protov1.Message) bfttypes.Tx {
cosmosPrivKey := &cosmossecp256k1.PrivKey{
Key: convertPrivKey(ethPrivKey).Serialize(),
}

var msgAnys []*codectypes.Any
for _, msg := range msgs {
msgAny, err := codectypes.NewAnyWithValue(msg)
require.NoError(t, err)
msgAnys = append(msgAnys, msgAny)
}

pubKeyAny, err := codectypes.NewAnyWithValue(cosmosPrivKey.PubKey())
require.NoError(t, err)

tx := &sdktx.Tx{
Body: &sdktx.TxBody{
Messages: msgAnys,
},
AuthInfo: &sdktx.AuthInfo{
SignerInfos: []*sdktx.SignerInfo{
{
PublicKey: pubKeyAny,
ModeInfo: &sdktx.ModeInfo{
Sum: &sdktx.ModeInfo_Single_{
Single: &sdktx.ModeInfo_Single{
Mode: signing.SignMode_SIGN_MODE_DIRECT,
},
},
},
Sequence: seqNum,
},
},
Fee: &sdktx.Fee{
Amount: sdk.NewCoins(sdk.NewCoin(rolluptypes.WEI, math.NewInt(100000000))),
GasLimit: 1000000,
},
},
}

bodyBytes, err := protov1.Marshal(tx.Body)
require.NoError(t, err)
authInfoBytes, err := protov1.Marshal(tx.AuthInfo)
require.NoError(t, err)

signBytes, err := (proto.MarshalOptions{Deterministic: true}).Marshal(&txv1beta1.SignDoc{
BodyBytes: bodyBytes,
AuthInfoBytes: authInfoBytes,
ChainId: chainID,
AccountNumber: accNum,
})
require.NoError(t, err)

signature, err := cosmosPrivKey.Sign(signBytes)
require.NoError(t, err)

require.True(t, cosmosPrivKey.PubKey().VerifySignature(signBytes, signature))

tx.Signatures = [][]byte{signature}

txBytes, err := tx.Marshal()
require.NoError(t, err)
return txBytes
}

func erc20RollupFlow(t *testing.T, stack *e2e.StackConfig) {
l1Client := stack.L1Client

Expand Down
85 changes: 85 additions & 0 deletions testutils/utils.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package testutils

import (
"crypto/ecdsa"
"math/big"
"math/rand"
"strings"
"testing"

txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
"cosmossdk.io/math"
"github.com/cockroachdb/pebble"
"github.com/cockroachdb/pebble/vfs"
cometdb "github.com/cometbft/cometbft-db"
bfttypes "github.com/cometbft/cometbft/types"
dbm "github.com/cosmos/cosmos-db"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cosmossecp256k1 "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdktypes "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
opbindings "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum-optimism/optimism/op-node/rollup"
Expand All @@ -24,9 +33,12 @@ import (
"github.com/ethereum/go-ethereum/core/state"
gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/trie"
protov1 "github.com/golang/protobuf/proto" //nolint:staticcheck
"github.com/polymerdao/monomer"
"github.com/polymerdao/monomer/monomerdb/localdb"
rolluptypes "github.com/polymerdao/monomer/x/rollup/types"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)

func NewCometMemDB(t *testing.T) cometdb.DB {
Expand Down Expand Up @@ -209,3 +221,76 @@ func GenerateL1Block() *gethtypes.Block {
Time: uint64(0),
}, nil, nil, nil, trie.NewStackTrie(nil))
}

func convertPrivKey(ecdsaPrivKey *ecdsa.PrivateKey) *secp256k1.PrivateKey {
privKeyBytes := ecdsaPrivKey.D.Bytes()
var key secp256k1.ModNScalar
if len(privKeyBytes) > 32 || key.SetByteSlice(privKeyBytes) {
panic("overflow")
}
if key.IsZero() {
panic("private keys must not be 0")
}
return secp256k1.NewPrivateKey(&key)
}

func BuildSDKTx(t *testing.T, chainID string, seqNum, accNum uint64, ethPrivKey *ecdsa.PrivateKey, msgs []protov1.Message) *sdktx.Tx {
cosmosPrivKey := &cosmossecp256k1.PrivKey{
Key: convertPrivKey(ethPrivKey).Serialize(),
}

var msgAnys []*codectypes.Any
for _, msg := range msgs {
msgAny, err := codectypes.NewAnyWithValue(msg)
require.NoError(t, err)
msgAnys = append(msgAnys, msgAny)
}

pubKeyAny, err := codectypes.NewAnyWithValue(cosmosPrivKey.PubKey())
require.NoError(t, err)

tx := &sdktx.Tx{
Body: &sdktx.TxBody{
Messages: msgAnys,
},
AuthInfo: &sdktx.AuthInfo{
SignerInfos: []*sdktx.SignerInfo{
{
PublicKey: pubKeyAny,
ModeInfo: &sdktx.ModeInfo{
Sum: &sdktx.ModeInfo_Single_{
Single: &sdktx.ModeInfo_Single{
Mode: signing.SignMode_SIGN_MODE_DIRECT,
},
},
},
Sequence: seqNum,
},
},
Fee: &sdktx.Fee{
Amount: sdktypes.NewCoins(sdktypes.NewCoin(rolluptypes.WEI, math.NewInt(100000000))),
GasLimit: 1000000,
},
},
}

bodyBytes, err := protov1.Marshal(tx.Body)
require.NoError(t, err)
authInfoBytes, err := protov1.Marshal(tx.AuthInfo)
require.NoError(t, err)

signBytes, err := (proto.MarshalOptions{Deterministic: true}).Marshal(&txv1beta1.SignDoc{
BodyBytes: bodyBytes,
AuthInfoBytes: authInfoBytes,
ChainId: chainID,
AccountNumber: accNum,
})
require.NoError(t, err)

signature, err := cosmosPrivKey.Sign(signBytes)
require.NoError(t, err)

tx.Signatures = [][]byte{signature}

return tx
}
5 changes: 2 additions & 3 deletions x/rollup/tx/helpers/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@ import (

sdktypes "github.com/cosmos/cosmos-sdk/types"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
rollupkeeper "github.com/polymerdao/monomer/x/rollup/keeper"
rolluptx "github.com/polymerdao/monomer/x/rollup/tx"
rolluptypes "github.com/polymerdao/monomer/x/rollup/types"
)

type AnteHandler struct {
authAnteHandler sdktypes.AnteHandler
rollupKeeper *rollupkeeper.Keeper
rollupKeeper rolluptx.RollupKeeper
}

func NewAnteHandler(
options authante.HandlerOptions, //nolint:gocritic // hugeParam
rollupKeeper *rollupkeeper.Keeper,
rollupKeeper rolluptx.RollupKeeper,
) (*AnteHandler, error) {
authAnteHandler, err := authante.NewAnteHandler(options)
if err != nil {
Expand Down
71 changes: 71 additions & 0 deletions x/rollup/tx/helpers/ante_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package helpers_test

import (
"testing"

storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/tx/signing"
"cosmossdk.io/x/tx/signing/direct"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
authantetestutil "github.com/cosmos/cosmos-sdk/x/auth/ante/testutil"
authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/golang/mock/gomock"
protov1 "github.com/golang/protobuf/proto" //nolint:staticcheck
"github.com/polymerdao/monomer/testutils"
"github.com/polymerdao/monomer/x/rollup/tx/helpers"
rolluptypes "github.com/polymerdao/monomer/x/rollup/types"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/reflect/protoreflect"
)

type mockRollupKeeper struct{}

func (mockRollupKeeper) GetL1BlockInfo(_ sdk.Context) (*rolluptypes.L1BlockInfo, error) { //nolint:gocritic // hugeParam
return &rolluptypes.L1BlockInfo{}, nil
}

type mockTx struct {
tx *sdktx.Tx
}

var _ sdk.Tx = (*mockTx)(nil)

func (tx *mockTx) GetMsgs() []sdk.Msg {
return tx.tx.GetMsgs()
}

func (tx *mockTx) GetMsgsV2() ([]protoreflect.ProtoMessage, error) {
msgsV1 := tx.GetMsgs()
msgs := make([]protoreflect.ProtoMessage, 0, len(msgsV1))
for _, msgV1 := range msgsV1 {
msgs = append(msgs, protov1.MessageV2(msgV1))
}
return msgs, nil
}

func TestUserTransactionCannotContainDepositMesssage(t *testing.T) {
sdkCtx := testutil.DefaultContextWithDB(
t,
storetypes.NewKVStoreKey(rolluptypes.StoreKey),
storetypes.NewTransientStoreKey("transient_test"),
).Ctx
anteHandler, err := helpers.NewAnteHandler(authante.HandlerOptions{
AccountKeeper: authantetestutil.NewMockAccountKeeper(gomock.NewController(t)),
BankKeeper: authtestutil.NewMockBankKeeper(gomock.NewController(t)),
SignModeHandler: signing.NewHandlerMap(direct.SignModeHandler{}),
}, mockRollupKeeper{})
require.NoError(t, err)

privKey, err := crypto.GenerateKey()
require.NoError(t, err)
for _, depositMsg := range []protov1.Message{&rolluptypes.MsgSetL1Attributes{}, &rolluptypes.MsgApplyUserDeposit{}} {
_, err := anteHandler.AnteHandle(sdkCtx, &mockTx{
tx: testutils.BuildSDKTx(t, "chainID", 0, 0, privKey, []protov1.Message{depositMsg}),
}, false)
require.ErrorContains(t, err, "transaction contains deposit message")
}
}
8 changes: 6 additions & 2 deletions x/rollup/tx/l1_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/rlp"
rollupkeeper "github.com/polymerdao/monomer/x/rollup/keeper"
rolluptypes "github.com/polymerdao/monomer/x/rollup/types"
)

type RollupKeeper interface {
GetL1BlockInfo(ctx sdk.Context) (*rolluptypes.L1BlockInfo, error)
}

// L1DataAnteHandler will consume gas to compensate the sequencer for posting
// the transaction to Ethereum. The gas cost is calculated based on the Ecotone
// upgrade and the sequencer is expected to post the transaction using blobs.
func L1DataAnteHandler(ctx sdk.Context, tx sdk.Tx, rollupKeeper *rollupkeeper.Keeper) (sdk.Context, error) { //nolint:gocritic // hugeparam
func L1DataAnteHandler(ctx sdk.Context, tx sdk.Tx, rollupKeeper RollupKeeper) (sdk.Context, error) { //nolint:gocritic // hugeparam
if rollupKeeper == nil {
return ctx, errorsmod.Wrap(sdkerrors.ErrLogic, "rollup keeper is required for l1 data ante handler")
}
Expand Down

0 comments on commit 4f1322f

Please sign in to comment.