From 7e1a11b01a2cd5570ca1e88908b9d02b3f4e9311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Negovanovi=C4=87?= Date: Tue, 26 Dec 2023 11:16:50 +0100 Subject: [PATCH] Initial approach to implement eth_sendTransaction --- jsonrpc/debug_endpoint.go | 2 +- jsonrpc/dispatcher.go | 3 +++ jsonrpc/eth_endpoint.go | 34 ++++++++++++++++++++++++++++------ jsonrpc/eth_endpoint_test.go | 18 ++++++++++++++---- jsonrpc/helper.go | 2 +- jsonrpc/helper_test.go | 2 +- jsonrpc/jsonrpc.go | 3 +++ server/server.go | 13 +++++++------ 8 files changed, 58 insertions(+), 19 deletions(-) diff --git a/jsonrpc/debug_endpoint.go b/jsonrpc/debug_endpoint.go index 59f44fd142..bc6694d989 100644 --- a/jsonrpc/debug_endpoint.go +++ b/jsonrpc/debug_endpoint.go @@ -191,7 +191,7 @@ func (d *Debug) TraceCall( return nil, ErrHeaderNotFound } - tx, err := DecodeTxn(arg, header.Number, d.store, true) + tx, err := DecodeTxn(arg, d.store, true) if err != nil { return nil, err } diff --git a/jsonrpc/dispatcher.go b/jsonrpc/dispatcher.go index 10c502f974..2a87aa77b7 100644 --- a/jsonrpc/dispatcher.go +++ b/jsonrpc/dispatcher.go @@ -11,6 +11,7 @@ import ( "time" "unicode" + "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/secrets" "github.com/armon/go-metrics" "github.com/hashicorp/go-hclog" @@ -68,6 +69,7 @@ type dispatcherParams struct { concurrentRequestsDebug uint64 secretsManager secrets.SecretsManager + txSigner crypto.TxSigner } func (dp dispatcherParams) isExceedingBatchLengthLimit(value uint64) bool { @@ -106,6 +108,7 @@ func (d *Dispatcher) registerEndpoints(store JSONRPCStore) error { d.params.secretsManager, d.params.chainID, d.params.priceLimit, + d.params.txSigner, ) if err != nil { return err diff --git a/jsonrpc/eth_endpoint.go b/jsonrpc/eth_endpoint.go index 1859123f77..8d558ee6c1 100644 --- a/jsonrpc/eth_endpoint.go +++ b/jsonrpc/eth_endpoint.go @@ -10,6 +10,7 @@ import ( "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/gasprice" "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/helper/progress" @@ -101,6 +102,7 @@ type Eth struct { filterManager *FilterManager priceLimit uint64 account *wallet.Account + txSigner crypto.TxSigner } func NewEth( @@ -109,7 +111,8 @@ func NewEth( filterManager *FilterManager, secretsManager secrets.SecretsManager, chainID uint64, - priceLimit uint64) (*Eth, error) { + priceLimit uint64, + txSigner crypto.TxSigner) (*Eth, error) { account, err := wallet.NewAccountFromSecret(secretsManager) if err != nil { return nil, fmt.Errorf("failed to read account data: %w", err) @@ -122,6 +125,7 @@ func NewEth( account: account, priceLimit: priceLimit, filterManager: filterManager, + txSigner: txSigner, }, nil } @@ -246,9 +250,27 @@ func (e *Eth) SendRawTransaction(buf argBytes) (interface{}, error) { } // SendTransaction rejects eth_sendTransaction json-rpc call as we don't support wallet management -func (e *Eth) SendTransaction(_ *txnArgs) (interface{}, error) { - return nil, fmt.Errorf("request calls to eth_sendTransaction method are not supported," + - " use eth_sendRawTransaction instead") +func (e *Eth) SendTransaction(args *txnArgs) (interface{}, error) { + tx, err := DecodeTxn(args, e.store, true) + if err != nil { + return nil, err + } + + ecdsaPrivKey, err := e.account.GetEcdsaPrivateKey() + if err != nil { + return nil, err + } + + signedTx, err := e.txSigner.SignTx(tx, ecdsaPrivKey) + if err != nil { + return nil, err + } + + if err := e.store.AddTx(signedTx); err != nil { + return nil, err + } + + return signedTx.Hash.String(), nil } // GetTransactionByHash returns a transaction by its hash. @@ -490,7 +512,7 @@ func (e *Eth) Call(arg *txnArgs, filter BlockNumberOrHash, apiOverride *stateOve return nil, err } - transaction, err := DecodeTxn(arg, header.Number, e.store, true) + transaction, err := DecodeTxn(arg, e.store, true) if err != nil { return nil, err } @@ -545,7 +567,7 @@ func (e *Eth) EstimateGas(arg *txnArgs, rawNum *BlockNumber) (interface{}, error } // testTransaction should execute tx with nonce always set to the current expected nonce for the account - transaction, err := DecodeTxn(arg, header.Number, e.store, true) + transaction, err := DecodeTxn(arg, e.store, true) if err != nil { return nil, err } diff --git a/jsonrpc/eth_endpoint_test.go b/jsonrpc/eth_endpoint_test.go index 7c9e845ba0..419ac9ce1b 100644 --- a/jsonrpc/eth_endpoint_test.go +++ b/jsonrpc/eth_endpoint_test.go @@ -170,7 +170,7 @@ func TestEth_DecodeTxn(t *testing.T) { store.SetAccount(addr, acc) } - res, err := DecodeTxn(tt.arg, 1, store, false) + res, err := DecodeTxn(tt.arg, store, false) assert.Equal(t, tt.res, res) assert.Equal(t, tt.err, err) }) @@ -290,7 +290,7 @@ func TestEth_TxnType(t *testing.T) { Nonce: 0, Type: types.DynamicFeeTx, } - res, err := DecodeTxn(args, 1, store, false) + res, err := DecodeTxn(args, store, false) expectedRes.ComputeHash() assert.NoError(t, err) @@ -299,13 +299,23 @@ func TestEth_TxnType(t *testing.T) { func newTestEthEndpoint(store testStore) *Eth { return &Eth{ - hclog.NewNullLogger(), store, 100, nil, 0, nil, + logger: hclog.NewNullLogger(), + store: store, + chainID: 100, + filterManager: nil, + priceLimit: 0, + account: nil, } } func newTestEthEndpointWithPriceLimit(store testStore, priceLimit uint64) *Eth { return &Eth{ - hclog.NewNullLogger(), store, 100, nil, priceLimit, nil, + logger: hclog.NewNullLogger(), + store: store, + chainID: 100, + filterManager: nil, + priceLimit: priceLimit, + account: nil, } } diff --git a/jsonrpc/helper.go b/jsonrpc/helper.go index 48a894686a..eabfbbdcfb 100644 --- a/jsonrpc/helper.go +++ b/jsonrpc/helper.go @@ -162,7 +162,7 @@ func GetNextNonce(address types.Address, number BlockNumber, store nonceGetter) return acc.Nonce, nil } -func DecodeTxn(arg *txnArgs, blockNumber uint64, store nonceGetter, forceSetNonce bool) (*types.Transaction, error) { +func DecodeTxn(arg *txnArgs, store nonceGetter, forceSetNonce bool) (*types.Transaction, error) { if arg == nil { return nil, errors.New("missing value for required argument 0") } diff --git a/jsonrpc/helper_test.go b/jsonrpc/helper_test.go index dca4866a85..a9084bc9f1 100644 --- a/jsonrpc/helper_test.go +++ b/jsonrpc/helper_test.go @@ -870,7 +870,7 @@ func TestDecodeTxn(t *testing.T) { t.Run(test.name, func(t *testing.T) { t.Parallel() - tx, err := DecodeTxn(test.arg, 1, test.store, false) + tx, err := DecodeTxn(test.arg, test.store, false) // DecodeTxn computes hash of tx if !test.err { diff --git a/jsonrpc/jsonrpc.go b/jsonrpc/jsonrpc.go index 3de16f4bdf..f45bddd1ef 100644 --- a/jsonrpc/jsonrpc.go +++ b/jsonrpc/jsonrpc.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/versioning" "github.com/gorilla/websocket" @@ -74,6 +75,7 @@ type Config struct { WebSocketReadLimit uint64 SecretsManager secrets.SecretsManager + TxSigner crypto.TxSigner } // NewJSONRPC returns the JSONRPC http server @@ -89,6 +91,7 @@ func NewJSONRPC(logger hclog.Logger, config *Config) (*JSONRPC, error) { blockRangeLimit: config.BlockRangeLimit, concurrentRequestsDebug: config.ConcurrentRequestsDebug, secretsManager: config.SecretsManager, + txSigner: config.TxSigner, }, ) diff --git a/server/server.go b/server/server.go index 42c1d2c8af..457301e3e4 100644 --- a/server/server.go +++ b/server/server.go @@ -282,8 +282,8 @@ func NewServer(config *Config) (*Server, error) { // compute the genesis root state config.Chain.Genesis.StateRoot = genesisRoot - // Use the london signer with eip-155 as a fallback one - var signer crypto.TxSigner = crypto.NewLondonSigner( + // Use the london txSigner with eip-155 as a fallback one + var txSigner crypto.TxSigner = crypto.NewLondonSigner( uint64(m.config.Chain.Params.ChainID), config.Chain.Params.Forks.IsActive(chain.Homestead, 0), crypto.NewEIP155Signer( @@ -318,7 +318,7 @@ func NewServer(config *Config) (*Server, error) { config.Chain, nil, m.executor, - signer, + txSigner, ) if err != nil { return nil, err @@ -356,7 +356,7 @@ func NewServer(config *Config) (*Server, error) { return nil, err } - m.txpool.SetSigner(signer) + m.txpool.SetSigner(txSigner) } { @@ -389,7 +389,7 @@ func NewServer(config *Config) (*Server, error) { } // setup and start jsonrpc server - if err := m.setupJSONRPC(); err != nil { + if err := m.setupJSONRPC(txSigner); err != nil { return nil, err } @@ -850,7 +850,7 @@ func (j *jsonRPCHub) GetSyncProgression() *progress.Progression { // SETUP // // setupJSONRCP sets up the JSONRPC server, using the set configuration -func (s *Server) setupJSONRPC() error { +func (s *Server) setupJSONRPC(txSigner crypto.TxSigner) error { hub := &jsonRPCHub{ state: s.state, restoreProgression: s.restoreProgression, @@ -875,6 +875,7 @@ func (s *Server) setupJSONRPC() error { ConcurrentRequestsDebug: s.config.JSONRPC.ConcurrentRequestsDebug, WebSocketReadLimit: s.config.JSONRPC.WebSocketReadLimit, SecretsManager: s.secretsManager, + TxSigner: txSigner, } srv, err := jsonrpc.NewJSONRPC(s.logger, conf)