Skip to content

Commit

Permalink
module/txpool: added Content() and ContentFrom(...)
Browse files Browse the repository at this point in the history
  • Loading branch information
lmittmann committed Jul 19, 2023
1 parent 7e72eb2 commit a03e9c2
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 3 deletions.
100 changes: 100 additions & 0 deletions module/txpool/content.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package txpool

import (
"encoding/json"
"sort"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/lmittmann/w3/internal/module"
"github.com/lmittmann/w3/w3types"
)

// Content requests the pending and queued transactions in the transaction pool.
func Content() w3types.CallerFactory[ContentResponse] {
return module.NewFactory[ContentResponse](
"txpool_content",
nil,
)
}

// ContentFrom requests the pending and queued transactions in the transaction pool
// from the given address.
func ContentFrom(addr common.Address) w3types.CallerFactory[ContentFromResponse] {
return module.NewFactory[ContentFromResponse](
"txpool_contentFrom",
[]any{addr},
)
}

type ContentResponse struct {
Pending map[common.Address][]*types.Transaction
Queued map[common.Address][]*types.Transaction
}

func (c *ContentResponse) UnmarshalJSON(data []byte) error {
type contentResponse struct {
Pending map[common.Address]map[uint64]*types.Transaction `json:"pending"`
Queued map[common.Address]map[uint64]*types.Transaction `json:"queued"`
}

var dec contentResponse
if err := json.Unmarshal(data, &dec); err != nil {
return err
}

c.Pending = make(map[common.Address][]*types.Transaction, len(dec.Pending))
for addr, nonceTx := range dec.Pending {
txs := make(types.TxByNonce, 0, len(nonceTx))
for _, tx := range nonceTx {
txs = append(txs, tx)
}
sort.Sort(txs)
c.Pending[addr] = txs
}

c.Queued = make(map[common.Address][]*types.Transaction, len(dec.Queued))
for addr, nonceTx := range dec.Queued {
txs := make(types.TxByNonce, 0, len(nonceTx))
for _, tx := range nonceTx {
txs = append(txs, tx)
}
sort.Sort(txs)
c.Queued[addr] = txs
}

return nil
}

type ContentFromResponse struct {
Pending []*types.Transaction
Queued []*types.Transaction
}

func (cf *ContentFromResponse) UnmarshalJSON(data []byte) error {
type contentFromResponse struct {
Pending map[uint64]*types.Transaction `json:"pending"`
Queued map[uint64]*types.Transaction `json:"queued"`
}

var dec contentFromResponse
if err := json.Unmarshal(data, &dec); err != nil {
return err
}

txs := make(types.TxByNonce, 0, len(dec.Pending))
for _, tx := range dec.Pending {
txs = append(txs, tx)
}
sort.Sort(txs)
cf.Pending = txs

txs = make(types.TxByNonce, 0, len(dec.Queued))
for _, tx := range dec.Queued {
txs = append(txs, tx)
}
sort.Sort(txs)
cf.Queued = txs

return nil
}
85 changes: 85 additions & 0 deletions module/txpool/content_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package txpool_test

import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/lmittmann/w3/module/txpool"
"github.com/lmittmann/w3/rpctest"
)

func TestContent(t *testing.T) {
tests := []rpctest.TestCase[txpool.ContentResponse]{
{
Golden: "content",
Call: txpool.Content(),
WantRet: txpool.ContentResponse{
Pending: map[common.Address][]*types.Transaction{
common.HexToAddress("0x000454307bB96E303044046a6eB2736D2aD560B6"): {
types.NewTx(&types.DynamicFeeTx{
ChainID: big.NewInt(1),
Nonce: 4652,
GasTipCap: big.NewInt(31407912032),
GasFeeCap: big.NewInt(202871575924),
Gas: 1100000,
To: ptr(common.HexToAddress("0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B")),
Value: big.NewInt(81000000000000000),
Data: common.FromHex("0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000001896e196d5300000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000011fc51222ce800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000004657febe8d8000000000000000000000000000000000000000000000000000011fc51222ce800000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000008d538a82c84d7003aa0e7f1098bd9dc5ea1777be000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000"),
R: new(big.Int).SetBytes(common.FromHex("0xf91729846ac8bb780a7239b7f0157d53330bba310a0811f4eec2eae25172c252")),
S: new(big.Int).SetBytes(common.FromHex("0x1bb9a1b9aea8b128e0e8dc42b17664be50c7b4073973c730b6c4cf2a3b3503cb")),
}),
},
},
Queued: map[common.Address][]*types.Transaction{
common.HexToAddress("0x1BA4Ca9ac6ff4CF192C11E8C1624563f302cAA87"): {
types.NewTx(&types.DynamicFeeTx{
ChainID: big.NewInt(1),
Nonce: 183,
GasTipCap: big.NewInt(110000000),
GasFeeCap: big.NewInt(20027736270),
Gas: 99226,
To: ptr(common.HexToAddress("0x1BA4Ca9ac6ff4CF192C11E8C1624563f302cAA87")),
Value: big.NewInt(0),
Data: []byte{},
R: new(big.Int).SetBytes(common.FromHex("0xea35c7c0643b79664b0bbb7f42d64edd371508ae4c33c1f817a80a2655465935")),
S: new(big.Int).SetBytes(common.FromHex("0x76d39f794e9e1ee359d66b7d3b19b90aaf2051b2159c68f3bb8c954558989da8")),
}),
},
},
},
},
}

rpctest.RunTestCases(t, tests)
}

func TestContentFrom(t *testing.T) {
tests := []rpctest.TestCase[txpool.ContentFromResponse]{
{
Golden: "contentFrom",
Call: txpool.ContentFrom(common.HexToAddress("0x1BA4Ca9ac6ff4CF192C11E8C1624563f302cAA87")),
WantRet: txpool.ContentFromResponse{
Queued: []*types.Transaction{
types.NewTx(&types.DynamicFeeTx{
ChainID: big.NewInt(1),
Nonce: 183,
GasTipCap: big.NewInt(110000000),
GasFeeCap: big.NewInt(20027736270),
Gas: 99226,
To: ptr(common.HexToAddress("0x1BA4Ca9ac6ff4CF192C11E8C1624563f302cAA87")),
Value: big.NewInt(0),
Data: []byte{},
R: new(big.Int).SetBytes(common.FromHex("0xea35c7c0643b79664b0bbb7f42d64edd371508ae4c33c1f817a80a2655465935")),
S: new(big.Int).SetBytes(common.FromHex("0x76d39f794e9e1ee359d66b7d3b19b90aaf2051b2159c68f3bb8c954558989da8")),
}),
},
},
},
}

rpctest.RunTestCases(t, tests)
}

func ptr[T any](x T) *T { return &x }
6 changes: 3 additions & 3 deletions module/txpool/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/lmittmann/w3/w3types"
)

// Status requests the txpool status.
// Status requests the number of pending and queued transactions in the transaction pool.
func Status() w3types.CallerFactory[StatusResponse] {
return module.NewFactory[StatusResponse](
"txpool_status",
Expand All @@ -21,14 +21,14 @@ type StatusResponse struct {
Queued uint
}

func (s *StatusResponse) UnmarshalJSON(input []byte) error {
func (s *StatusResponse) UnmarshalJSON(data []byte) error {
type statusResponse struct {
Pending hexutil.Uint `json:"pending"`
Queued hexutil.Uint `json:"queued"`
}

var dec statusResponse
if err := json.Unmarshal(input, &dec); err != nil {
if err := json.Unmarshal(data, &dec); err != nil {
return err
}
s.Pending = uint(dec.Pending)
Expand Down
2 changes: 2 additions & 0 deletions module/txpool/testdata/content.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
> {"jsonrpc":"2.0","id":1,"method":"txpool_content"}
< {"jsonrpc":"2.0","id":1,"result":{"pending":{"0x000454307bB96E303044046a6eB2736D2aD560B6":{"4652":{"blockHash":null,"blockNumber":null,"from":"0x000454307bb96e303044046a6eb2736d2ad560b6","gas":"0x10c8e0","gasPrice":"0x2f3c169574","maxFeePerGas":"0x2f3c169574","maxPriorityFeePerGas":"0x7500eb460","hash":"0xb4f36425ff7007c1fc6d29148f062f5ed3232ad99bc185f5ad26f071851409c7","input":"0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000001896e196d5300000000000000000000000000000000000000000000000000000000000000030b090c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000011fc51222ce800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000004657febe8d8000000000000000000000000000000000000000000000000000011fc51222ce800000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000008d538a82c84d7003aa0e7f1098bd9dc5ea1777be000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000","nonce":"0x122c","to":"0xef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","transactionIndex":null,"value":"0x11fc51222ce8000","type":"0x2","accessList":[],"chainId":"0x1","v":"0x0","r":"0xf91729846ac8bb780a7239b7f0157d53330bba310a0811f4eec2eae25172c252","s":"0x1bb9a1b9aea8b128e0e8dc42b17664be50c7b4073973c730b6c4cf2a3b3503cb"}}},"queued":{"0x1BA4Ca9ac6ff4CF192C11E8C1624563f302cAA87":{"183":{"blockHash":null,"blockNumber":null,"from":"0x1ba4ca9ac6ff4cf192c11e8c1624563f302caa87","gas":"0x1839a","gasPrice":"0x4a9bf00ce","maxFeePerGas":"0x4a9bf00ce","maxPriorityFeePerGas":"0x68e7780","hash":"0x222c11451c3bf3607a4ef18fa87f26575a0dca97e10ceb81b8ebebdd45d5bbfb","input":"0x","nonce":"0xb7","to":"0x1ba4ca9ac6ff4cf192c11e8c1624563f302caa87","transactionIndex":null,"value":"0x0","type":"0x2","accessList":[],"chainId":"0x1","v":"0x0","r":"0xea35c7c0643b79664b0bbb7f42d64edd371508ae4c33c1f817a80a2655465935","s":"0x76d39f794e9e1ee359d66b7d3b19b90aaf2051b2159c68f3bb8c954558989da8"}}}}}
2 changes: 2 additions & 0 deletions module/txpool/testdata/contentFrom.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
> {"jsonrpc":"2.0","id":1,"method":"txpool_contentFrom","params":["0x1ba4ca9ac6ff4cf192c11e8c1624563f302caa87"]}
< {"jsonrpc":"2.0","id":1,"result":{"queued":{"183":{"blockHash":null,"blockNumber":null,"from":"0x1ba4ca9ac6ff4cf192c11e8c1624563f302caa87","gas":"0x1839a","gasPrice":"0x4a9bf00ce","maxFeePerGas":"0x4a9bf00ce","maxPriorityFeePerGas":"0x68e7780","hash":"0x222c11451c3bf3607a4ef18fa87f26575a0dca97e10ceb81b8ebebdd45d5bbfb","input":"0x","nonce":"0xb7","to":"0x1ba4ca9ac6ff4cf192c11e8c1624563f302caa87","transactionIndex":null,"value":"0x0","type":"0x2","accessList":[],"chainId":"0x1","v":"0x0","r":"0xea35c7c0643b79664b0bbb7f42d64edd371508ae4c33c1f817a80a2655465935","s":"0x76d39f794e9e1ee359d66b7d3b19b90aaf2051b2159c68f3bb8c954558989da8"}}}}

0 comments on commit a03e9c2

Please sign in to comment.