From b03859d5cf651247416334a9730ca53124431c8d Mon Sep 17 00:00:00 2001 From: Devon Bear Date: Fri, 6 Oct 2023 16:49:39 -0400 Subject: [PATCH] ree --- cosmos/miner/miner.go | 8 ++- cosmos/txpool/handler.go | 6 +- cosmos/txpool/mocks/tx_serializer.go | 82 ++++++++++----------- cosmos/x/evm/types/tx_serializer.go | 102 ++++++--------------------- e2e/testapp/app.go | 9 +-- 5 files changed, 75 insertions(+), 132 deletions(-) diff --git a/cosmos/miner/miner.go b/cosmos/miner/miner.go index 9326e25c0..a9df03a19 100644 --- a/cosmos/miner/miner.go +++ b/cosmos/miner/miner.go @@ -28,6 +28,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/miner" @@ -41,7 +42,7 @@ var emptyHash = common.Hash{} // Miner implements the baseapp.TxSelector interface. type Miner struct { *miner.Miner - serializer evmtypes.TxSerializer + serializer evmtypes.TxSerializer[*engine.ExecutionPayloadEnvelope] currentPayload *miner.Payload } @@ -53,7 +54,7 @@ func New(gm *miner.Miner) *Miner { } // Init sets the transaction serializer. -func (m *Miner) Init(serializer evmtypes.TxSerializer) { +func (m *Miner) Init(serializer evmtypes.TxSerializer[*engine.ExecutionPayloadEnvelope]) { m.serializer = serializer } @@ -113,7 +114,8 @@ func (m *Miner) resolveEnvelope() []byte { if m.currentPayload == nil { return nil } - bz, err := m.serializer.PayloadToSdkTxBytes(m.currentPayload.ResolveFull()) + envelope := m.currentPayload.ResolveFull() + bz, err := m.serializer.ToSdkTxBytes(envelope, envelope.ExecutionPayload.GasLimit) if err != nil { panic(err) } diff --git a/cosmos/txpool/handler.go b/cosmos/txpool/handler.go index 02b7f6ce8..8c1c25dd2 100644 --- a/cosmos/txpool/handler.go +++ b/cosmos/txpool/handler.go @@ -50,8 +50,8 @@ type TxSubProvider interface { // TxSerializer provides an interface to Serialize Geth Transactions to Bytes (via sdk.Tx). type TxSerializer interface { - TxToSdkTx(signedTx *coretypes.Transaction) (sdk.Tx, error) - TxToSdkTxBytes(signedTx *coretypes.Transaction) ([]byte, error) + ToSdkTx(signedTx *coretypes.Transaction, gasLimit uint64) (sdk.Tx, error) + ToSdkTxBytes(signedTx *coretypes.Transaction, gasLimit uint64) ([]byte, error) } // TxBroadcaster provides an interface to broadcast TxBytes to the comet p2p layer. @@ -163,7 +163,7 @@ func (h *handler) broadcastTransactions(txs coretypes.Transactions) { h.logger.Debug("broadcasting transactions", "num_txs", len(txs)) for _, signedEthTx := range txs { // Serialize the transaction to Bytes - txBytes, err := h.serializer.TxToSdkTxBytes(signedEthTx) + txBytes, err := h.serializer.ToSdkTxBytes(signedEthTx, signedEthTx.Gas()) if err != nil { h.logger.Error("failed to serialize transaction", "err", err) continue diff --git a/cosmos/txpool/mocks/tx_serializer.go b/cosmos/txpool/mocks/tx_serializer.go index 15d55b8a2..19d4e5142 100644 --- a/cosmos/txpool/mocks/tx_serializer.go +++ b/cosmos/txpool/mocks/tx_serializer.go @@ -22,25 +22,25 @@ func (_m *TxSerializer) EXPECT() *TxSerializer_Expecter { return &TxSerializer_Expecter{mock: &_m.Mock} } -// TxToSdkTxBytes provides a mock function with given fields: signedTx -func (_m *TxSerializer) TxToSdkTxBytes(signedTx *types.Transaction) ([]byte, error) { - ret := _m.Called(signedTx) +// ToSdkTx provides a mock function with given fields: signedTx, gasLimit +func (_m *TxSerializer) ToSdkTx(signedTx *types.Transaction, gasLimit uint64) (cosmos_sdktypes.Tx, error) { + ret := _m.Called(signedTx, gasLimit) - var r0 []byte + var r0 cosmos_sdktypes.Tx var r1 error - if rf, ok := ret.Get(0).(func(*types.Transaction) ([]byte, error)); ok { - return rf(signedTx) + if rf, ok := ret.Get(0).(func(*types.Transaction, uint64) (cosmos_sdktypes.Tx, error)); ok { + return rf(signedTx, gasLimit) } - if rf, ok := ret.Get(0).(func(*types.Transaction) []byte); ok { - r0 = rf(signedTx) + if rf, ok := ret.Get(0).(func(*types.Transaction, uint64) cosmos_sdktypes.Tx); ok { + r0 = rf(signedTx, gasLimit) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) + r0 = ret.Get(0).(cosmos_sdktypes.Tx) } } - if rf, ok := ret.Get(1).(func(*types.Transaction) error); ok { - r1 = rf(signedTx) + if rf, ok := ret.Get(1).(func(*types.Transaction, uint64) error); ok { + r1 = rf(signedTx, gasLimit) } else { r1 = ret.Error(1) } @@ -48,53 +48,54 @@ func (_m *TxSerializer) TxToSdkTxBytes(signedTx *types.Transaction) ([]byte, err return r0, r1 } -// TxSerializer_TxToSdkTxBytes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TxToSdkTxBytes' -type TxSerializer_TxToSdkTxBytes_Call struct { +// TxSerializer_ToSdkTx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ToSdkTx' +type TxSerializer_ToSdkTx_Call struct { *mock.Call } -// TxToSdkTxBytes is a helper method to define mock.On call +// ToSdkTx is a helper method to define mock.On call // - signedTx *types.Transaction -func (_e *TxSerializer_Expecter) TxToSdkTxBytes(signedTx interface{}) *TxSerializer_TxToSdkTxBytes_Call { - return &TxSerializer_TxToSdkTxBytes_Call{Call: _e.mock.On("TxToSdkTxBytes", signedTx)} +// - gasLimit uint64 +func (_e *TxSerializer_Expecter) ToSdkTx(signedTx interface{}, gasLimit interface{}) *TxSerializer_ToSdkTx_Call { + return &TxSerializer_ToSdkTx_Call{Call: _e.mock.On("ToSdkTx", signedTx, gasLimit)} } -func (_c *TxSerializer_TxToSdkTxBytes_Call) Run(run func(signedTx *types.Transaction)) *TxSerializer_TxToSdkTxBytes_Call { +func (_c *TxSerializer_ToSdkTx_Call) Run(run func(signedTx *types.Transaction, gasLimit uint64)) *TxSerializer_ToSdkTx_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*types.Transaction)) + run(args[0].(*types.Transaction), args[1].(uint64)) }) return _c } -func (_c *TxSerializer_TxToSdkTxBytes_Call) Return(_a0 []byte, _a1 error) *TxSerializer_TxToSdkTxBytes_Call { +func (_c *TxSerializer_ToSdkTx_Call) Return(_a0 cosmos_sdktypes.Tx, _a1 error) *TxSerializer_ToSdkTx_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *TxSerializer_TxToSdkTxBytes_Call) RunAndReturn(run func(*types.Transaction) ([]byte, error)) *TxSerializer_TxToSdkTxBytes_Call { +func (_c *TxSerializer_ToSdkTx_Call) RunAndReturn(run func(*types.Transaction, uint64) (cosmos_sdktypes.Tx, error)) *TxSerializer_ToSdkTx_Call { _c.Call.Return(run) return _c } -// TxToSdkTx provides a mock function with given fields: signedTx -func (_m *TxSerializer) TxToSdkTx(signedTx *types.Transaction) (cosmos_sdktypes.Tx, error) { - ret := _m.Called(signedTx) +// ToSdkTxBytes provides a mock function with given fields: signedTx, gasLimit +func (_m *TxSerializer) ToSdkTxBytes(signedTx *types.Transaction, gasLimit uint64) ([]byte, error) { + ret := _m.Called(signedTx, gasLimit) - var r0 cosmos_sdktypes.Tx + var r0 []byte var r1 error - if rf, ok := ret.Get(0).(func(*types.Transaction) (cosmos_sdktypes.Tx, error)); ok { - return rf(signedTx) + if rf, ok := ret.Get(0).(func(*types.Transaction, uint64) ([]byte, error)); ok { + return rf(signedTx, gasLimit) } - if rf, ok := ret.Get(0).(func(*types.Transaction) cosmos_sdktypes.Tx); ok { - r0 = rf(signedTx) + if rf, ok := ret.Get(0).(func(*types.Transaction, uint64) []byte); ok { + r0 = rf(signedTx, gasLimit) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(cosmos_sdktypes.Tx) + r0 = ret.Get(0).([]byte) } } - if rf, ok := ret.Get(1).(func(*types.Transaction) error); ok { - r1 = rf(signedTx) + if rf, ok := ret.Get(1).(func(*types.Transaction, uint64) error); ok { + r1 = rf(signedTx, gasLimit) } else { r1 = ret.Error(1) } @@ -102,30 +103,31 @@ func (_m *TxSerializer) TxToSdkTx(signedTx *types.Transaction) (cosmos_sdktypes. return r0, r1 } -// TxSerializer_TxToSdkTx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TxToSdkTx' -type TxSerializer_TxToSdkTx_Call struct { +// TxSerializer_ToSdkTxBytes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ToSdkTxBytes' +type TxSerializer_ToSdkTxBytes_Call struct { *mock.Call } -// TxToSdkTx is a helper method to define mock.On call +// ToSdkTxBytes is a helper method to define mock.On call // - signedTx *types.Transaction -func (_e *TxSerializer_Expecter) TxToSdkTx(signedTx interface{}) *TxSerializer_TxToSdkTx_Call { - return &TxSerializer_TxToSdkTx_Call{Call: _e.mock.On("TxToSdkTx", signedTx)} +// - gasLimit uint64 +func (_e *TxSerializer_Expecter) ToSdkTxBytes(signedTx interface{}, gasLimit interface{}) *TxSerializer_ToSdkTxBytes_Call { + return &TxSerializer_ToSdkTxBytes_Call{Call: _e.mock.On("ToSdkTxBytes", signedTx, gasLimit)} } -func (_c *TxSerializer_TxToSdkTx_Call) Run(run func(signedTx *types.Transaction)) *TxSerializer_TxToSdkTx_Call { +func (_c *TxSerializer_ToSdkTxBytes_Call) Run(run func(signedTx *types.Transaction, gasLimit uint64)) *TxSerializer_ToSdkTxBytes_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*types.Transaction)) + run(args[0].(*types.Transaction), args[1].(uint64)) }) return _c } -func (_c *TxSerializer_TxToSdkTx_Call) Return(_a0 cosmos_sdktypes.Tx, _a1 error) *TxSerializer_TxToSdkTx_Call { +func (_c *TxSerializer_ToSdkTxBytes_Call) Return(_a0 []byte, _a1 error) *TxSerializer_ToSdkTxBytes_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *TxSerializer_TxToSdkTx_Call) RunAndReturn(run func(*types.Transaction) (cosmos_sdktypes.Tx, error)) *TxSerializer_TxToSdkTx_Call { +func (_c *TxSerializer_ToSdkTxBytes_Call) RunAndReturn(run func(*types.Transaction, uint64) ([]byte, error)) *TxSerializer_ToSdkTxBytes_Call { _c.Call.Return(run) return _c } diff --git a/cosmos/x/evm/types/tx_serializer.go b/cosmos/x/evm/types/tx_serializer.go index 0b5030874..68489b499 100644 --- a/cosmos/x/evm/types/tx_serializer.go +++ b/cosmos/x/evm/types/tx_serializer.go @@ -25,67 +25,43 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" - - "github.com/ethereum/go-ethereum/beacon/engine" - - coretypes "pkg.berachain.dev/polaris/eth/core/types" ) // TxSerializer provides an interface to serialize ethereum transactions // to sdk.Tx's and bytes that can be used by CometBFT. -type TxSerializer interface { - TxToSdkTx(signedTx *coretypes.Transaction) (sdk.Tx, error) - TxToSdkTxBytes(signedTx *coretypes.Transaction) ([]byte, error) - PayloadToSdkTxBytes(payload *engine.ExecutionPayloadEnvelope) ([]byte, error) - PayloadToSdkTx(payload *engine.ExecutionPayloadEnvelope) (sdk.Tx, error) +type TxSerializer[I any] interface { + ToSdkTx(input I, gasLimit uint64) (sdk.Tx, error) + ToSdkTxBytes(input I, gasLimit uint64) ([]byte, error) } -// serializer implements TxSerializer. -type serializer struct { +type serializer[I any, O sdk.Msg] struct { txConfig client.TxConfig + wrapFn func(I) (O, error) } // NewSerializer returns a new instance of TxSerializer. -func NewSerializer(txConfig client.TxConfig) TxSerializer { - return &serializer{ +func NewSerializer[I any, O sdk.Msg]( + txConfig client.TxConfig, wrapFn func(I) (O, error), +) TxSerializer[I] { + return &serializer[I, O]{ txConfig: txConfig, + wrapFn: wrapFn, } } -// SerializeToBytes converts an Ethereum transaction to Cosmos formatted -// txBytes which allows for it to broadcast it to CometBFT. -func (s *serializer) PayloadToSdkTxBytes( - payload *engine.ExecutionPayloadEnvelope, -) ([]byte, error) { - // First, we convert the Ethereum transaction to a Cosmos transaction. - cosmosTx, err := s.PayloadToSdkTx(payload) - if err != nil { - return nil, err - } - - // Then we use the clientCtx.TxConfig.TxEncoder() to encode the Cosmos transaction into bytes. - return s.txConfig.TxEncoder()(cosmosTx) -} - -// PayloadToSdkTx converts an ExecutionPayloadEnvelope to an sdk.Tx. -func (s *serializer) PayloadToSdkTx(payload *engine.ExecutionPayloadEnvelope) (sdk.Tx, error) { +func (s *serializer[I, O]) ToSdkTx(input I, gasLimit uint64) (sdk.Tx, error) { var err error // TODO: do we really need to use extensions for anything? Since we // are using the standard ante handler stuff I don't think we actually need to. tx := s.txConfig.NewTxBuilder() // Set the tx gas limit to the block gas limit in the payload - tx.SetGasLimit(payload.ExecutionPayload.GasLimit) + tx.SetGasLimit(gasLimit) - bz, err := payload.MarshalJSON() + wrapped, err := s.wrapFn(input) if err != nil { return nil, err } - - wp := &WrappedPayloadEnvelope{ - Data: bz, - } - // Lastly, we set the signature. We can pull the sequence from the nonce of the ethereum tx. if err = tx.SetSignatures( signingtypes.SignatureV2{ @@ -104,45 +80,7 @@ func (s *serializer) PayloadToSdkTx(payload *engine.ExecutionPayloadEnvelope) (s } // Lastly, we inject the signed ethereum transaction as a message into the Cosmos Tx. - if err = tx.SetMsgs(wp); err != nil { - return nil, err - } - - // Finally, we return the Cosmos Tx. - return tx.GetTx(), nil -} - -// TxToSdkTx converts an ethereum transaction to a Cosmos native transaction. -func (s *serializer) TxToSdkTx(signedTx *coretypes.Transaction) (sdk.Tx, error) { - var err error - // are using the standard ante handler stuff I don't think we actually need to. - tx := s.txConfig.NewTxBuilder() - - // Create the WrappedEthereumTransaction message. - wrappedEthTx, err := WrapTx(signedTx) - if err != nil { - return nil, err - } - - // Lastly, we set the signature. We can pull the sequence from the nonce of the ethereum tx. - if err = tx.SetSignatures( - signingtypes.SignatureV2{ - Sequence: signedTx.Nonce(), - Data: &signingtypes.SingleSignatureData{ - // We retrieve the hash of the signed transaction from the ethereum transaction - // objects, as this was the bytes that were signed. We pass these into the - // SingleSignatureData as the SignModeHandler needs to know what data was signed - // over so that it can verify the signature in the ante handler. - Signature: []byte{0x0}, - }, - PubKey: &secp256k1.PubKey{Key: []byte{0x0}}, - }, - ); err != nil { - return nil, err - } - - // Lastly, we inject the signed ethereum transaction as a message into the Cosmos Tx. - if err = tx.SetMsgs(wrappedEthTx); err != nil { + if err = tx.SetMsgs(wrapped); err != nil { return nil, err } @@ -150,13 +88,13 @@ func (s *serializer) TxToSdkTx(signedTx *coretypes.Transaction) (sdk.Tx, error) return tx.GetTx(), nil } -// SerializeToBytes converts an Ethereum transaction to Cosmos formatted txBytes which allows for -// it to broadcast it to CometBFT. -// func -func (s *serializer) TxToSdkTxBytes(signedTx *coretypes.Transaction) ([]byte, error) { +// SerializeToBytes converts an Ethereum transaction to Cosmos formatted +// txBytes which allows for it to broadcast it to CometBFT. +func (s *serializer[I, O]) ToSdkTxBytes( + input I, gasLimit uint64, +) ([]byte, error) { // First, we convert the Ethereum transaction to a Cosmos transaction. - // func(I any) sdk.Tx, error) - cosmosTx, err := s.TxToSdkTx(signedTx) /// + cosmosTx, err := s.ToSdkTx(input, gasLimit) if err != nil { return nil, err } diff --git a/e2e/testapp/app.go b/e2e/testapp/app.go index ace4011b3..0ace8ee9f 100644 --- a/e2e/testapp/app.go +++ b/e2e/testapp/app.go @@ -282,12 +282,13 @@ func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APICon panic(err) } - // Create a TxSerializer. - serializer := evmtypes.NewSerializer(apiSvr.ClientCtx.TxConfig) + // Create the Serializers. + txSerializer := evmtypes.NewSerializer(apiSvr.ClientCtx.TxConfig, evmtypes.WrapTx) + payloadSerializer := evmtypes.NewSerializer(apiSvr.ClientCtx.TxConfig, evmtypes.WrapPayload) // Initialize services. - app.mm.Init(serializer) - app.mp.Init(app.Logger(), apiSvr.ClientCtx, serializer) + app.mm.Init(payloadSerializer) + app.mp.Init(app.Logger(), apiSvr.ClientCtx, txSerializer) // Register services with Polaris. app.EVMKeeper.RegisterServices(apiSvr.ClientCtx, []node.Lifecycle{