Skip to content

Commit 6621802

Browse files
author
Daisuke Kanda
committed
define txpool's function as method
Signed-off-by: Daisuke Kanda <daisuke.kanda@datachain.jp>
1 parent c5db28a commit 6621802

File tree

6 files changed

+108
-64
lines changed

6 files changed

+108
-64
lines changed

pkg/client/client.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import (
1414
"github.com/ethereum/go-ethereum/core/vm"
1515
"github.com/ethereum/go-ethereum/ethclient"
1616
"github.com/ethereum/go-ethereum/rpc"
17+
"github.com/datachainlab/ethereum-ibc-relay-chain/pkg/client/txpool"
1718
)
18-
19+
/*
1920
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
2021
type RPCTransaction struct {
2122
BlockHash *common.Hash `json:"blockHash"`
@@ -41,14 +42,14 @@ type RPCTransaction struct {
4142
S *hexutil.Big `json:"s"`
4243
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
4344
}
44-
45+
*/
4546
// wrapping interface of ethclient.Client struct
4647
type IETHClient interface {
4748
Inner() *ethclient.Client
4849
SuggestGasPrice(ctx context.Context) (*big.Int, error)
4950
HeaderByNumber(ctx context.Context, number *big.Int) (*gethtypes.Header, error);
5051
FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*ethereum.FeeHistory, error)
51-
ContentFrom(ctx context.Context, address common.Address) (map[string]map[string]*RPCTransaction, error);
52+
GetMinimumRequiredFee(ctx context.Context, address common.Address, nonce uint64, priceBump uint64) (*txpool.RPCTransaction, *big.Int, *big.Int, error);
5253
}
5354

5455
type ETHClient struct {
@@ -114,15 +115,6 @@ func (cl *ETHClient) FeeHistory(ctx context.Context, blockCount uint64, lastBloc
114115
return cl.Client.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles)
115116
}
116117

117-
// ContentFrom calls `txpool_contentFrom` of the Ethereum RPC
118-
func (cl *ETHClient) ContentFrom(ctx context.Context, address common.Address) (map[string]map[string]*RPCTransaction, error) {
119-
var res map[string]map[string]*RPCTransaction
120-
if err := cl.Client.Client().CallContext(ctx, &res, "txpool_contentFrom", address); err != nil {
121-
return nil, err
122-
}
123-
return res, nil
124-
}
125-
126118
func (cl *ETHClient) GetTransactionReceipt(ctx context.Context, txHash common.Hash) (rc *Receipt, err error) {
127119
var r *Receipt
128120

pkg/client/txpool.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"math/big"
6+
7+
"github.com/ethereum/go-ethereum/common"
8+
"github.com/datachainlab/ethereum-ibc-relay-chain/pkg/client/txpool"
9+
)
10+
11+
func (cl *ETHClient) GetMinimumRequiredFee(ctx context.Context, address common.Address, nonce uint64, priceBump uint64) (*txpool.RPCTransaction, *big.Int, *big.Int, error) {
12+
return txpool.GetMinimumRequiredFee(ctx, cl.Client, address, nonce, priceBump);
13+
}

pkg/client/txpool/txpool.go

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,50 @@ import (
55
"math/big"
66
"slices"
77

8-
"github.com/datachainlab/ethereum-ibc-relay-chain/pkg/client"
98
"github.com/ethereum/go-ethereum/common"
9+
"github.com/ethereum/go-ethereum/common/hexutil"
10+
"github.com/ethereum/go-ethereum/core/types"
11+
"github.com/ethereum/go-ethereum/ethclient"
1012
)
1113

14+
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
15+
type RPCTransaction struct {
16+
BlockHash *common.Hash `json:"blockHash"`
17+
BlockNumber *hexutil.Big `json:"blockNumber"`
18+
From common.Address `json:"from"`
19+
Gas hexutil.Uint64 `json:"gas"`
20+
GasPrice *hexutil.Big `json:"gasPrice"`
21+
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
22+
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
23+
MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"`
24+
Hash common.Hash `json:"hash"`
25+
Input hexutil.Bytes `json:"input"`
26+
Nonce hexutil.Uint64 `json:"nonce"`
27+
To *common.Address `json:"to"`
28+
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
29+
Value *hexutil.Big `json:"value"`
30+
Type hexutil.Uint64 `json:"type"`
31+
Accesses *types.AccessList `json:"accessList,omitempty"`
32+
ChainID *hexutil.Big `json:"chainId,omitempty"`
33+
BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
34+
V *hexutil.Big `json:"v"`
35+
R *hexutil.Big `json:"r"`
36+
S *hexutil.Big `json:"s"`
37+
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
38+
}
39+
40+
// ContentFrom calls `txpool_contentFrom` of the Ethereum RPC
41+
func ContentFrom(ctx context.Context, client *ethclient.Client, address common.Address) (map[string]map[string]*RPCTransaction, error) {
42+
var res map[string]map[string]*RPCTransaction
43+
if err := client.Client().CallContext(ctx, &res, "txpool_contentFrom", address); err != nil {
44+
return nil, err
45+
}
46+
return res, nil
47+
}
48+
1249
// PendingTransactions returns pending txs sent from `address` sorted by nonce.
13-
func PendingTransactions(ctx context.Context, cl client.IETHClient, address common.Address) ([]*client.RPCTransaction, error) {
14-
txs, err := cl.ContentFrom(ctx, address)
50+
func PendingTransactions(ctx context.Context, client *ethclient.Client, address common.Address) ([]*RPCTransaction, error) {
51+
txs, err := ContentFrom(ctx, client, address)
1552
if err != nil {
1653
return nil, err
1754
}
@@ -21,12 +58,12 @@ func PendingTransactions(ctx context.Context, cl client.IETHClient, address comm
2158
return nil, nil
2259
}
2360

24-
var pendingTxs []*client.RPCTransaction
61+
var pendingTxs []*RPCTransaction
2562
for _, pendingTx := range pendingTxMap {
2663
pendingTxs = append(pendingTxs, pendingTx)
2764
}
2865

29-
slices.SortFunc(pendingTxs, func(a, b *client.RPCTransaction) int {
66+
slices.SortFunc(pendingTxs, func(a, b *RPCTransaction) int {
3067
if a.Nonce < b.Nonce {
3168
return -1
3269
} else if a.Nonce > b.Nonce {
@@ -45,15 +82,15 @@ func inclByPercent(n *big.Int, percent uint64) {
4582
}
4683

4784
// GetMinimumRequiredFee returns the minimum fee required to successfully send a transaction
48-
func GetMinimumRequiredFee(ctx context.Context, cl client.IETHClient, address common.Address, nonce uint64, priceBump uint64) (*client.RPCTransaction, *big.Int, *big.Int, error) {
49-
pendingTxs, err := PendingTransactions(ctx, cl, address)
85+
func GetMinimumRequiredFee(ctx context.Context, client *ethclient.Client, address common.Address, nonce uint64, priceBump uint64) (*RPCTransaction, *big.Int, *big.Int, error) {
86+
pendingTxs, err := PendingTransactions(ctx, client, address)
5087
if err != nil {
5188
return nil, nil, nil, err
5289
} else if len(pendingTxs) == 0 {
5390
return nil, common.Big0, common.Big0, nil
5491
}
5592

56-
var targetTx *client.RPCTransaction
93+
var targetTx *RPCTransaction
5794
for _, pendingTx := range pendingTxs {
5895
if uint64(pendingTx.Nonce) == nonce {
5996
targetTx = pendingTx
@@ -63,6 +100,7 @@ func GetMinimumRequiredFee(ctx context.Context, cl client.IETHClient, address co
63100
if targetTx == nil {
64101
return nil, common.Big0, common.Big0, nil
65102
}
103+
66104
gasFeeCap := new(big.Int).Set(targetTx.GasFeeCap.ToInt())
67105
gasTipCap := new(big.Int).Set(targetTx.GasTipCap.ToInt())
68106

pkg/client/txpool/txpool_test.go

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"testing"
88
"unsafe"
99

10-
"github.com/datachainlab/ethereum-ibc-relay-chain/pkg/client"
1110
"github.com/ethereum/go-ethereum/common"
1211
"github.com/ethereum/go-ethereum/core/types"
1312
"github.com/ethereum/go-ethereum/crypto"
@@ -45,20 +44,16 @@ func getPrivateKey(t *testing.T, account types.Account) *ecdsa.PrivateKey {
4544
return key
4645
}
4746

48-
func getEthClient(t *testing.T, sim *simulated.Backend) client.IETHClient {
47+
func getEthClient(sim *simulated.Backend) *ethclient.Client {
4948
type simClient struct {
5049
*ethclient.Client
5150
}
5251
ifceCli := sim.Client()
5352
ptrCli := unsafe.Add(unsafe.Pointer(&ifceCli), unsafe.Sizeof(uintptr(0)))
54-
cli, err := client.NewETHClientWith((*simClient)(ptrCli).Client)
55-
if err != nil {
56-
t.Fatalf("failed to create client: err=%v", err)
57-
}
58-
return cli
53+
return (*simClient)(ptrCli).Client
5954
}
6055

61-
func transfer(t *testing.T, ctx context.Context, cl client.IETHClient, signer types.Signer, key *ecdsa.PrivateKey, nonce uint64, gasTipCap, gasFeeCap *big.Int, to common.Address, amount *big.Int) {
56+
func transfer(t *testing.T, ctx context.Context, client *ethclient.Client, signer types.Signer, key *ecdsa.PrivateKey, nonce uint64, gasTipCap, gasFeeCap *big.Int, to common.Address, amount *big.Int) {
6257
tx := types.NewTx(&types.DynamicFeeTx{
6358
Nonce: nonce,
6459
GasTipCap: gasTipCap,
@@ -73,15 +68,15 @@ func transfer(t *testing.T, ctx context.Context, cl client.IETHClient, signer ty
7368
t.Fatalf("failed to sign tx: err=%v", err)
7469
}
7570

76-
if err := cl.Inner().SendTransaction(ctx, tx); err != nil {
71+
if err := client.SendTransaction(ctx, tx); err != nil {
7772
t.Fatalf("failed to send tx: err=%v", err)
7873
}
7974
}
8075

81-
func replace(t *testing.T, ctx context.Context, cl client.IETHClient, signer types.Signer, key *ecdsa.PrivateKey, priceBump uint64, nonce uint64, gasTipCap, gasFeeCap *big.Int, to common.Address, amount *big.Int) {
76+
func replace(t *testing.T, ctx context.Context, client *ethclient.Client, signer types.Signer, key *ecdsa.PrivateKey, priceBump uint64, nonce uint64, gasTipCap, gasFeeCap *big.Int, to common.Address, amount *big.Int) {
8277
addr := crypto.PubkeyToAddress(key.PublicKey)
8378

84-
if _, minFeeCap, minTipCap, err := GetMinimumRequiredFee(ctx, cl, addr, nonce, priceBump); err != nil {
79+
if _, minFeeCap, minTipCap, err := GetMinimumRequiredFee(ctx, client, addr, nonce, priceBump); err != nil {
8580
t.Fatalf("failed to get the minimum fee required to replace tx: err=%v", err)
8681
} else if minFeeCap.Cmp(common.Big0) == 0 {
8782
t.Fatalf("tx to replace not found")
@@ -97,7 +92,7 @@ func replace(t *testing.T, ctx context.Context, cl client.IETHClient, signer typ
9792
}
9893
}
9994

100-
transfer(t, ctx, cl, signer, key, nonce, gasTipCap, gasFeeCap, to, amount)
95+
transfer(t, ctx, client, signer, key, nonce, gasTipCap, gasFeeCap, to, amount)
10196
}
10297

10398
func TestContentFrom(t *testing.T) {
@@ -114,10 +109,10 @@ func TestContentFrom(t *testing.T) {
114109
})
115110
defer sim.Close()
116111

117-
cli := getEthClient(t, sim)
112+
cli := getEthClient(sim)
118113

119114
// make signer
120-
chainID, err := cli.Inner().ChainID(ctx)
115+
chainID, err := cli.ChainID(ctx)
121116
if err != nil {
122117
t.Fatalf("failed to get chain ID: err=%v", err)
123118
}
@@ -134,7 +129,7 @@ func TestContentFrom(t *testing.T) {
134129
}
135130

136131
// check block info
137-
block, err := cli.Inner().BlockByNumber(ctx, nil)
132+
block, err := cli.BlockByNumber(ctx, nil)
138133
if err != nil {
139134
t.Fatalf("failed to get block by number: err=%v", err)
140135
} else {
@@ -145,7 +140,7 @@ func TestContentFrom(t *testing.T) {
145140
sim.Commit()
146141

147142
// check block info
148-
block, err = cli.Inner().BlockByNumber(ctx, nil)
143+
block, err = cli.BlockByNumber(ctx, nil)
149144
if err != nil {
150145
t.Fatalf("failed to get block by number: err=%v", err)
151146
} else {
@@ -168,7 +163,7 @@ func TestContentFrom(t *testing.T) {
168163
sim.Commit()
169164

170165
// check block info
171-
block, err = cli.Inner().BlockByNumber(ctx, nil)
166+
block, err = cli.BlockByNumber(ctx, nil)
172167
if err != nil {
173168
t.Fatalf("failed to get block by number: err=%v", err)
174169
} else {

pkg/relay/ethereum/gas.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ func NewGasFeeCalculator(client client.IETHClient, config *ChainConfig) *GasFeeC
2727
func (m *GasFeeCalculator) Apply(ctx context.Context, txOpts *bind.TransactOpts) error {
2828
minFeeCap := common.Big0
2929
minTipCap := common.Big0
30-
var oldTx *client.RPCTransaction
30+
var oldTx *txpool.RPCTransaction
3131
if m.config.PriceBump > 0 && txOpts.Nonce != nil {
3232
var err error
33-
if oldTx, minFeeCap, minTipCap, err = txpool.GetMinimumRequiredFee(ctx, m.client, txOpts.From, txOpts.Nonce.Uint64(), m.config.PriceBump); err != nil {
33+
if oldTx, minFeeCap, minTipCap, err = m.client.GetMinimumRequiredFee(ctx, txOpts.From, txOpts.Nonce.Uint64(), m.config.PriceBump); err != nil {
3434
return err
3535
}
3636
}

pkg/relay/ethereum/gas_test.go

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ package ethereum
22

33
import (
44
"context"
5+
"math/big"
6+
"testing"
57

68
"github.com/datachainlab/ethereum-ibc-relay-chain/pkg/client"
9+
"github.com/datachainlab/ethereum-ibc-relay-chain/pkg/client/txpool"
710
"github.com/ethereum/go-ethereum"
811
gethtypes "github.com/ethereum/go-ethereum/core/types"
912
"github.com/ethereum/go-ethereum/common"
1013
"github.com/ethereum/go-ethereum/common/hexutil"
1114
"github.com/ethereum/go-ethereum/accounts/abi/bind"
12-
"math/big"
13-
"testing"
1415
)
1516

1617
func Test_TxOpts_LegacyTx(t *testing.T) {
@@ -137,17 +138,30 @@ func Test_getFeeInfo(t *testing.T) {
137138
type MockETHClient struct {
138139
client.IETHClient
139140
MockSuggestGasPrice big.Int
140-
MockContentFrom map[string]map[string]*client.RPCTransaction
141+
MockPendingTransaction *txpool.RPCTransaction
141142
MockLatestHeaderNumber big.Int
142143
MockHistoryGasTipCap big.Int
143144
MockHistoryGasFeeCap big.Int
144145
}
145146
func (cl *MockETHClient) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
146147
return &cl.MockSuggestGasPrice, nil
147148
}
148-
func (cl *MockETHClient) ContentFrom(ctx context.Context, address common.Address) (map[string]map[string]*client.RPCTransaction, error) {
149-
return cl.MockContentFrom, nil
149+
150+
func inclByPercent(n *big.Int, percent uint64) {
151+
n.Mul(n, big.NewInt(int64(100+percent)))
152+
n.Div(n, big.NewInt(100))
153+
}
154+
155+
func (cl *MockETHClient) GetMinimumRequiredFee(ctx context.Context, address common.Address, nonce uint64, priceBump uint64) (*txpool.RPCTransaction, *big.Int, *big.Int, error) {
156+
gasFeeCap := new(big.Int).Set(cl.MockPendingTransaction.GasFeeCap.ToInt())
157+
gasTipCap := new(big.Int).Set(cl.MockPendingTransaction.GasTipCap.ToInt())
158+
159+
inclByPercent(gasFeeCap, priceBump)
160+
inclByPercent(gasTipCap, priceBump)
161+
162+
return cl.MockPendingTransaction, gasFeeCap, gasTipCap, nil
150163
}
164+
151165
func (cl *MockETHClient) HeaderByNumber(ctx context.Context, number *big.Int) (*gethtypes.Header, error) {
152166
if number != nil {
153167
return &gethtypes.Header{
@@ -180,15 +194,11 @@ func TestPriceBumpLegacy(t *testing.T) {
180194
txOpts := &bind.TransactOpts{}
181195
txOpts.Nonce = big.NewInt(1)
182196

183-
cli.MockContentFrom = map[string]map[string]*client.RPCTransaction{
184-
"pending": {
185-
"dummyaddr": &client.RPCTransaction{
186-
GasPrice: (*hexutil.Big)(big.NewInt(100)),
187-
GasTipCap: (*hexutil.Big)(big.NewInt(200)),
188-
GasFeeCap: (*hexutil.Big)(big.NewInt(300)),
189-
Nonce: (hexutil.Uint64)(txOpts.Nonce.Uint64()),
190-
},
191-
},
197+
cli.MockPendingTransaction = &txpool.RPCTransaction{
198+
GasPrice: (*hexutil.Big)(big.NewInt(100)),
199+
GasTipCap: (*hexutil.Big)(big.NewInt(200)),
200+
GasFeeCap: (*hexutil.Big)(big.NewInt(300)),
201+
Nonce: (hexutil.Uint64)(txOpts.Nonce.Uint64()),
192202
}
193203

194204
// test that gasPrice is bumped from old tx's gasFeeCap
@@ -234,15 +244,11 @@ func TestPriceBumpDynamic(t *testing.T) {
234244
txOpts.Nonce = big.NewInt(1)
235245

236246
cli.MockLatestHeaderNumber.SetUint64(1000)
237-
cli.MockContentFrom = map[string]map[string]*client.RPCTransaction{
238-
"pending": {
239-
"dummyaddr": &client.RPCTransaction{
240-
GasPrice: (*hexutil.Big)(big.NewInt(100)),
241-
GasTipCap: (*hexutil.Big)(big.NewInt(200)),
242-
GasFeeCap: (*hexutil.Big)(big.NewInt(300)),
243-
Nonce: (hexutil.Uint64)(txOpts.Nonce.Uint64()),
244-
},
245-
},
247+
cli.MockPendingTransaction = &txpool.RPCTransaction{
248+
GasPrice: (*hexutil.Big)(big.NewInt(100)),
249+
GasTipCap: (*hexutil.Big)(big.NewInt(200)),
250+
GasFeeCap: (*hexutil.Big)(big.NewInt(300)),
251+
Nonce: (hexutil.Uint64)(txOpts.Nonce.Uint64()),
246252
}
247253

248254
// test that gasTipCap and gasFeeCap are bumped from old tx's one
@@ -274,8 +280,8 @@ func TestPriceBumpDynamic(t *testing.T) {
274280
{
275281
// Because gasTipCap suggestion is added to gasFeeCap suggenstion,
276282
// gasTipCap suggestion should be lower than old tx's gasFeeCap
277-
cli.MockContentFrom["pending"]["dummyaddr"].GasTipCap = (*hexutil.Big)(big.NewInt(100))
278-
cli.MockContentFrom["pending"]["dummyaddr"].GasFeeCap = (*hexutil.Big)(big.NewInt(300))
283+
cli.MockPendingTransaction.GasTipCap = (*hexutil.Big)(big.NewInt(100))
284+
cli.MockPendingTransaction.GasFeeCap = (*hexutil.Big)(big.NewInt(300))
279285
cli.MockHistoryGasTipCap.SetUint64(199)
280286
cli.MockHistoryGasFeeCap.SetUint64(299 - 200)
281287
err := calculator.Apply(context.Background(), txOpts)

0 commit comments

Comments
 (0)