diff --git a/jsonrpc/txpool_endpoint.go b/jsonrpc/txpool_endpoint.go index 0d91a06ec7..b2578b88fa 100644 --- a/jsonrpc/txpool_endpoint.go +++ b/jsonrpc/txpool_endpoint.go @@ -14,6 +14,9 @@ type txPoolStore interface { // GetCapacity returns the current and max capacity of the pool in slots GetCapacity() (uint64, uint64) + + // GetBaseFee returns current base fee + GetBaseFee() uint64 } // TxPool is the txpool jsonrpc endpoint @@ -22,8 +25,8 @@ type TxPool struct { } type ContentResponse struct { - Pending map[types.Address]map[uint64]*txpoolTransaction `json:"pending"` - Queued map[types.Address]map[uint64]*txpoolTransaction `json:"queued"` + Pending map[types.Address]map[uint64]*transaction `json:"pending"` + Queued map[types.Address]map[uint64]*transaction `json:"queued"` } type InspectResponse struct { @@ -38,86 +41,27 @@ type StatusResponse struct { Queued uint64 `json:"queued"` } -type txpoolTransaction struct { - Nonce argUint64 `json:"nonce"` - GasPrice argBig `json:"gasPrice"` - GasFeeCap *argBig `json:"gasFeeCap,omitempty"` - GasTipCap *argBig `json:"gasTipCap,omitempty"` - Gas argUint64 `json:"gas"` - To *types.Address `json:"to"` - Value argBig `json:"value"` - Input argBytes `json:"input"` - Hash types.Hash `json:"hash"` - From types.Address `json:"from"` - BlockHash types.Hash `json:"blockHash"` - BlockNumber interface{} `json:"blockNumber"` - TxIndex interface{} `json:"transactionIndex"` -} - -func toTxPoolTransaction(t *types.Transaction) *txpoolTransaction { - var gasTipCap, gasFeeCap *argBig - - if t.GasTipCap != nil { - gasTipCapVal := argBig(*t.GasTipCap) - gasTipCap = &gasTipCapVal - } - - if t.GasFeeCap != nil { - gasFeeCapVal := argBig(*t.GasFeeCap) - gasFeeCap = &gasFeeCapVal - } - - return &txpoolTransaction{ - Nonce: argUint64(t.Nonce), - GasPrice: argBig(*t.GasPrice), - GasFeeCap: gasFeeCap, - GasTipCap: gasTipCap, - Gas: argUint64(t.Gas), - To: t.To, - Value: argBig(*t.Value), - Input: t.Input, - Hash: t.Hash, - From: t.From, - BlockHash: types.ZeroHash, - BlockNumber: nil, - TxIndex: nil, - } -} - // Create response for txpool_content request. // See https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content. func (t *TxPool) Content() (interface{}, error) { - pendingTxs, queuedTxs := t.store.GetTxs(true) - - // collect pending - pendingRPCTxs := make(map[types.Address]map[uint64]*txpoolTransaction) - for addr, txs := range pendingTxs { - pendingRPCTxs[addr] = make(map[uint64]*txpoolTransaction, len(txs)) + convertTxMap := func(txMap map[types.Address][]*types.Transaction) map[types.Address]map[uint64]*transaction { + result := make(map[types.Address]map[uint64]*transaction, len(txMap)) - for _, tx := range txs { - nonce := tx.Nonce - rpcTx := toTxPoolTransaction(tx) + for addr, txs := range txMap { + result[addr] = make(map[uint64]*transaction, len(txs)) - pendingRPCTxs[addr][nonce] = rpcTx + for _, tx := range txs { + result[addr][tx.Nonce] = toTransaction(tx, nil, &types.ZeroHash, nil) + } } - } - - // collect enqueued - queuedRPCTxs := make(map[types.Address]map[uint64]*txpoolTransaction) - for addr, txs := range queuedTxs { - queuedRPCTxs[addr] = make(map[uint64]*txpoolTransaction, len(txs)) - for _, tx := range txs { - nonce := tx.Nonce - rpcTx := toTxPoolTransaction(tx) - - queuedRPCTxs[addr][nonce] = rpcTx - } + return result } + pendingTxs, queuedTxs := t.store.GetTxs(true) resp := ContentResponse{ - Pending: pendingRPCTxs, - Queued: queuedRPCTxs, + Pending: convertTxMap(pendingTxs), + Queued: convertTxMap(queuedTxs), } return resp, nil @@ -126,40 +70,30 @@ func (t *TxPool) Content() (interface{}, error) { // Create response for txpool_inspect request. // See https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect. func (t *TxPool) Inspect() (interface{}, error) { - pendingTxs, queuedTxs := t.store.GetTxs(true) - - // collect pending - pendingRPCTxs := make(map[string]map[string]string) - for addr, txs := range pendingTxs { - pendingRPCTxs[addr.String()] = make(map[string]string, len(txs)) - - for _, tx := range txs { - nonceStr := strconv.FormatUint(tx.Nonce, 10) - pendingRPCTxs[addr.String()][nonceStr] = fmt.Sprintf( - "%d wei + %d gas x %d wei", tx.Value, tx.Gas, tx.GasPrice, - ) + baseFee := t.store.GetBaseFee() + convertTxMap := func(txMap map[types.Address][]*types.Transaction) map[string]map[string]string { + result := make(map[string]map[string]string, len(txMap)) + + for addr, txs := range txMap { + result[addr.String()] = make(map[string]string, len(txs)) + + for _, tx := range txs { + nonceStr := strconv.FormatUint(tx.Nonce, 10) + result[addr.String()][nonceStr] = fmt.Sprintf( + "%d wei + %d gas x %d wei", tx.Value, tx.Gas, tx.GetGasPrice(baseFee), + ) + } } - } - - // collect enqueued - queuedRPCTxs := make(map[string]map[string]string) - for addr, txs := range queuedTxs { - queuedRPCTxs[addr.String()] = make(map[string]string, len(txs)) - for _, tx := range txs { - nonceStr := strconv.FormatUint(tx.Nonce, 10) - queuedRPCTxs[addr.String()][nonceStr] = fmt.Sprintf( - "%d wei + %d gas x %d wei", tx.Value, tx.Gas, tx.GasPrice, - ) - } + return result } // get capacity of the TxPool current, max := t.store.GetCapacity() - + pendingTxs, queuedTxs := t.store.GetTxs(true) resp := InspectResponse{ - Pending: pendingRPCTxs, - Queued: queuedRPCTxs, + Pending: convertTxMap(pendingTxs), + Queued: convertTxMap(queuedTxs), CurrentCapacity: current, MaxCapacity: max, } diff --git a/jsonrpc/txpool_endpoint_test.go b/jsonrpc/txpool_endpoint_test.go index 5d2b8b4958..a52f7dc2de 100644 --- a/jsonrpc/txpool_endpoint_test.go +++ b/jsonrpc/txpool_endpoint_test.go @@ -28,14 +28,14 @@ func TestContentEndpoint(t *testing.T) { assert.Equal(t, 0, len(response.Queued)) }) - //nolint:dupl t.Run("returns correct data for pending transaction", func(t *testing.T) { t.Parallel() mockStore := newMockTxPoolStore() address1 := types.Address{0x1} - testTx := newTestTransaction(2, address1) - mockStore.pending[address1] = []*types.Transaction{testTx} + testTx1 := newTestTransaction(2, address1) + testTx2 := newTestDynamicFeeTransaction(3, address1) + mockStore.pending[address1] = []*types.Transaction{testTx1, testTx2} txPoolEndpoint := &TxPool{mockStore} result, _ := txPoolEndpoint.Content() @@ -44,28 +44,46 @@ func TestContentEndpoint(t *testing.T) { assert.Equal(t, 1, len(response.Pending)) assert.Equal(t, 0, len(response.Queued)) - assert.Equal(t, 1, len(response.Pending[address1])) + assert.Equal(t, 2, len(response.Pending[address1])) - txData := response.Pending[address1][testTx.Nonce] + txData := response.Pending[address1][testTx1.Nonce] + assert.NotNil(t, txData) + assert.Equal(t, testTx1.Gas, uint64(txData.Gas)) + assert.Equal(t, *testTx1.GasPrice, big.Int(*txData.GasPrice)) + assert.Equal(t, (*argBig)(nil), txData.GasFeeCap) + assert.Equal(t, (*argBig)(nil), txData.GasTipCap) + assert.Equal(t, testTx1.To, txData.To) + assert.Equal(t, testTx1.From, txData.From) + assert.Equal(t, *testTx1.Value, big.Int(txData.Value)) + assert.Equal(t, testTx1.Input, []byte(txData.Input)) + assert.Equal(t, (*argUint64)(nil), txData.BlockNumber) + assert.Equal(t, (*argUint64)(nil), txData.TxIndex) + + txData = response.Pending[address1][testTx2.Nonce] assert.NotNil(t, txData) - assert.Equal(t, testTx.Gas, uint64(txData.Gas)) - assert.Equal(t, *testTx.GasPrice, big.Int(txData.GasPrice)) - assert.Equal(t, testTx.To, txData.To) - assert.Equal(t, testTx.From, txData.From) - assert.Equal(t, *testTx.Value, big.Int(txData.Value)) - assert.Equal(t, testTx.Input, []byte(txData.Input)) - assert.Equal(t, nil, txData.BlockNumber) - assert.Equal(t, nil, txData.TxIndex) + assert.Equal(t, (argUint64)(types.DynamicFeeTx), txData.Type) + assert.Equal(t, testTx2.Gas, uint64(txData.Gas)) + assert.Equal(t, (*argBig)(nil), txData.GasPrice) + assert.Equal(t, *testTx2.GasFeeCap, big.Int(*txData.GasFeeCap)) + assert.Equal(t, *testTx2.GasTipCap, big.Int(*txData.GasTipCap)) + assert.Equal(t, testTx2.To, txData.To) + assert.Equal(t, testTx2.From, txData.From) + assert.Equal(t, *testTx2.ChainID, big.Int(*txData.ChainID)) + assert.Equal(t, *testTx2.Value, big.Int(txData.Value)) + assert.Equal(t, testTx2.Input, []byte(txData.Input)) + assert.Equal(t, (*argUint64)(nil), txData.BlockNumber) + assert.Equal(t, (*argUint64)(nil), txData.TxIndex) }) - //nolint:dupl t.Run("returns correct data for queued transaction", func(t *testing.T) { t.Parallel() mockStore := newMockTxPoolStore() - address1 := types.Address{0x1} - testTx := newTestTransaction(2, address1) - mockStore.queued[address1] = []*types.Transaction{testTx} + address1, address2 := types.Address{0x1}, types.Address{0x2} + testTx1 := newTestTransaction(2, address1) + testTx2 := newTestDynamicFeeTransaction(1, address2) + mockStore.queued[address1] = []*types.Transaction{testTx1} + mockStore.queued[address2] = []*types.Transaction{testTx2} txPoolEndpoint := &TxPool{mockStore} result, _ := txPoolEndpoint.Content() @@ -73,19 +91,37 @@ func TestContentEndpoint(t *testing.T) { response := result.(ContentResponse) assert.Equal(t, 0, len(response.Pending)) - assert.Equal(t, 1, len(response.Queued)) + assert.Equal(t, 2, len(response.Queued)) assert.Equal(t, 1, len(response.Queued[address1])) + assert.Equal(t, 1, len(response.Queued[address2])) - txData := response.Queued[address1][testTx.Nonce] + txData := response.Queued[address1][testTx1.Nonce] assert.NotNil(t, txData) - assert.Equal(t, testTx.Gas, uint64(txData.Gas)) - assert.Equal(t, *testTx.GasPrice, big.Int(txData.GasPrice)) - assert.Equal(t, testTx.To, txData.To) - assert.Equal(t, testTx.From, txData.From) - assert.Equal(t, *testTx.Value, big.Int(txData.Value)) - assert.Equal(t, testTx.Input, []byte(txData.Input)) - assert.Equal(t, nil, txData.BlockNumber) - assert.Equal(t, nil, txData.TxIndex) + assert.Equal(t, testTx1.Gas, uint64(txData.Gas)) + assert.Equal(t, *testTx1.GasPrice, big.Int(*txData.GasPrice)) + assert.Equal(t, (*argBig)(nil), txData.GasFeeCap) + assert.Equal(t, (*argBig)(nil), txData.GasTipCap) + assert.Equal(t, testTx1.To, txData.To) + assert.Equal(t, testTx1.From, txData.From) + assert.Equal(t, *testTx1.Value, big.Int(txData.Value)) + assert.Equal(t, testTx1.Input, []byte(txData.Input)) + assert.Equal(t, (*argUint64)(nil), txData.BlockNumber) + assert.Equal(t, (*argUint64)(nil), txData.TxIndex) + + txData = response.Queued[address2][testTx2.Nonce] + assert.NotNil(t, txData) + assert.Equal(t, (argUint64)(types.DynamicFeeTx), txData.Type) + assert.Equal(t, testTx2.Gas, uint64(txData.Gas)) + assert.Equal(t, (*argBig)(nil), txData.GasPrice) + assert.Equal(t, *testTx2.GasFeeCap, big.Int(*txData.GasFeeCap)) + assert.Equal(t, *testTx2.GasTipCap, big.Int(*txData.GasTipCap)) + assert.Equal(t, testTx2.To, txData.To) + assert.Equal(t, testTx2.From, txData.From) + assert.Equal(t, *testTx2.ChainID, big.Int(*txData.ChainID)) + assert.Equal(t, *testTx2.Value, big.Int(txData.Value)) + assert.Equal(t, testTx2.Input, []byte(txData.Input)) + assert.Equal(t, (*argUint64)(nil), txData.BlockNumber) + assert.Equal(t, (*argUint64)(nil), txData.TxIndex) }) t.Run("returns correct ContentResponse data for multiple transactions", func(t *testing.T) { @@ -233,6 +269,7 @@ type mockTxPoolStore struct { queued map[types.Address][]*types.Transaction capacity uint64 maxSlots uint64 + baseFee uint64 includeQueued bool } @@ -253,6 +290,10 @@ func (s *mockTxPoolStore) GetCapacity() (uint64, uint64) { return s.capacity, s.maxSlots } +func (s *mockTxPoolStore) GetBaseFee() uint64 { + return s.baseFee +} + func newTestTransaction(nonce uint64, from types.Address) *types.Transaction { txn := &types.Transaction{ Nonce: nonce, @@ -271,3 +312,25 @@ func newTestTransaction(nonce uint64, from types.Address) *types.Transaction { return txn } + +func newTestDynamicFeeTransaction(nonce uint64, from types.Address) *types.Transaction { + txn := &types.Transaction{ + Type: types.DynamicFeeTx, + Nonce: nonce, + GasTipCap: big.NewInt(2), + GasFeeCap: big.NewInt(4), + ChainID: big.NewInt(100), + Gas: nonce * 100, + Value: big.NewInt(200), + Input: []byte{0xff}, + From: from, + To: &addr1, + V: big.NewInt(1), + R: big.NewInt(1), + S: big.NewInt(1), + } + + txn.ComputeHash(1) + + return txn +} diff --git a/txpool/txpool.go b/txpool/txpool.go index 01075f2cda..58c31acb1a 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -755,7 +755,10 @@ func (p *TxPool) addTx(origin txOrigin, tx *types.Transaction) error { return err } - tx.ChainID = p.chainID // add chainID to the tx + // add chainID to the tx - only dynamic fee tx + if tx.Type == types.DynamicFeeTx { + tx.ChainID = p.chainID + } // calculate tx hash tx.ComputeHash(p.store.Header().Number)