Skip to content

Commit eb74395

Browse files
authored
Extend Geth Confirm Func (#570)
1 parent 33ed37f commit eb74395

File tree

3 files changed

+99
-30
lines changed

3 files changed

+99
-30
lines changed

.changeset/fresh-bushes-hear.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
"chainlink-deployments-framework": patch
3+
---
4+
5+
Adds a new EVM Confirm Functor which allows the user to specify a custom wait interval for checking confirmation.
6+
Example
7+
8+
```golang
9+
p, err := cldf_evm_provider.NewRPCChainProvider(
10+
d.ChainSelector,
11+
cldf_evm_provider.RPCChainProviderConfig{
12+
DeployerTransactorGen: cldf_evm_provider.TransactorFromRaw(
13+
getNetworkPrivateKey(),
14+
),
15+
RPCs: []rpcclient.RPC{
16+
{
17+
Name: "default",
18+
WSURL: rpcWSURL,
19+
HTTPURL: rpcHTTPURL,
20+
PreferredURLScheme: rpcclient.URLSchemePreferenceHTTP,
21+
},
22+
},
23+
ConfirmFunctor: cldf_evm_provider.ConfirmFuncGeth(
24+
30*time.Second,
25+
// set custom confirm ticker time because Anvil's blocks are instant
26+
cldf_evm_provider.WithTickInterval(5*time.Millisecond),
27+
),
28+
},
29+
).Initialize(context.Background())
30+
```

chain/evm/provider/confirm_functor.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,29 @@ type ConfirmFunctor interface {
2626
}
2727

2828
// ConfirmFuncGeth returns a ConfirmFunctor that uses the Geth client to confirm transactions.
29-
func ConfirmFuncGeth(waitMinedTimeout time.Duration) ConfirmFunctor {
30-
return &confirmFuncGeth{
29+
func ConfirmFuncGeth(waitMinedTimeout time.Duration, opts ...func(*confirmFuncGeth)) ConfirmFunctor {
30+
cf := &confirmFuncGeth{
31+
tickInterval: 1 * time.Second, // the same value we have in bind.WaitMined hardcoded in "go-ethereum"
3132
waitMinedTimeout: waitMinedTimeout,
3233
}
34+
for _, o := range opts {
35+
o(cf)
36+
}
37+
38+
return cf
39+
}
40+
41+
// WithTickInterval specifies tick interval to confirm transaction is mined
42+
func WithTickInterval(interval time.Duration) func(*confirmFuncGeth) {
43+
return func(o *confirmFuncGeth) {
44+
o.tickInterval = interval
45+
}
3346
}
3447

3548
// confirmFuncGeth implements the ConfirmFunctor interface which generates a confirmation function
3649
// for transactions using the Geth client.
3750
type confirmFuncGeth struct {
51+
tickInterval time.Duration
3852
waitMinedTimeout time.Duration
3953
}
4054

@@ -51,7 +65,7 @@ func (g *confirmFuncGeth) Generate(
5165
ctxTimeout, cancel := context.WithTimeout(ctx, g.waitMinedTimeout)
5266
defer cancel()
5367

54-
receipt, err := bind.WaitMined(ctxTimeout, client, tx)
68+
receipt, err := waitMinedWithInterval(ctxTimeout, g.tickInterval, client, tx.Hash())
5569
if err != nil {
5670
return 0, fmt.Errorf("tx %s failed to confirm for selector %d: %w",
5771
tx.Hash().Hex(), selector, err,
@@ -157,3 +171,20 @@ func (g *confirmFuncSeth) Generate(
157171
return decoded.Receipt.BlockNumber.Uint64(), nil
158172
}, nil
159173
}
174+
175+
// waitMinedWithInterval is a custom function that allows to get receipts faster for networks with instant blocks
176+
func waitMinedWithInterval(ctx context.Context, tick time.Duration, b bind.DeployBackend, txHash common.Hash) (*types.Receipt, error) {
177+
queryTicker := time.NewTicker(tick)
178+
defer queryTicker.Stop()
179+
for {
180+
receipt, err := b.TransactionReceipt(ctx, txHash)
181+
if err == nil {
182+
return receipt, nil
183+
}
184+
select {
185+
case <-ctx.Done():
186+
return nil, ctx.Err()
187+
case <-queryTicker.C:
188+
}
189+
}
190+
}

chain/evm/provider/confirm_functor_test.go

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,39 +39,47 @@ func Test_ConfirmFuncGeth_ConfirmFunc(t *testing.T) {
3939
adminTransactor.From: {Balance: prefundAmountWei},
4040
}
4141

42-
tests := []struct {
43-
name string
44-
giveTx func(*testing.T, *SimClient) *types.Transaction
45-
wantErr string
46-
}{
47-
{
48-
name: "successful confirmation",
49-
giveTx: func(t *testing.T, client *SimClient) *types.Transaction {
50-
t.Helper()
42+
defaultGiveTxFunc := func(t *testing.T, client *SimClient) *types.Transaction {
43+
t.Helper()
5144

52-
// Get the nonce
53-
nonce, err := client.PendingNonceAt(t.Context(), adminTransactor.From)
54-
require.NoError(t, err)
45+
// Get the nonce
46+
nonce, err := client.PendingNonceAt(t.Context(), adminTransactor.From)
47+
require.NoError(t, err)
5548

56-
gasPrice, err := client.SuggestGasPrice(t.Context())
57-
require.NoError(t, err)
49+
gasPrice, err := client.SuggestGasPrice(t.Context())
50+
require.NoError(t, err)
5851

59-
// Create a transaction to send tokens. This will be used to test the confirmation function.
60-
tx := types.NewTransaction(
61-
nonce, userTransactor.From, big.NewInt(10000000000000000), 21000, gasPrice, nil,
62-
)
52+
// Create a transaction to send tokens. This will be used to test the confirmation function.
53+
tx := types.NewTransaction(
54+
nonce, userTransactor.From, big.NewInt(10000000000000000), 21000, gasPrice, nil,
55+
)
6356

64-
signedTx, err := types.SignTx(tx, types.NewCancunSigner(simChainID), adminKey)
65-
require.NoError(t, err, "failed to sign transaction")
57+
signedTx, err := types.SignTx(tx, types.NewCancunSigner(simChainID), adminKey)
58+
require.NoError(t, err, "failed to sign transaction")
6659

67-
// Send the transaction
68-
err = client.SendTransaction(t.Context(), signedTx)
69-
require.NoError(t, err)
60+
// Send the transaction
61+
err = client.SendTransaction(t.Context(), signedTx)
62+
require.NoError(t, err)
7063

71-
client.Commit() // Commit the transaction to the simulated backend
64+
client.Commit() // Commit the transaction to the simulated backend
7265

73-
return signedTx
74-
},
66+
return signedTx
67+
}
68+
69+
tests := []struct {
70+
name string
71+
giveTx func(*testing.T, *SimClient) *types.Transaction
72+
confirmerOpts []func(*confirmFuncGeth)
73+
wantErr string
74+
}{
75+
{
76+
name: "successful confirmation",
77+
giveTx: defaultGiveTxFunc,
78+
},
79+
{
80+
name: "successful confirmation with custom WaitMined ticker",
81+
confirmerOpts: []func(*confirmFuncGeth){WithTickInterval(10 * time.Millisecond)},
82+
giveTx: defaultGiveTxFunc,
7583
},
7684
{
7785
name: "failed with nil tx",
@@ -121,7 +129,7 @@ func Test_ConfirmFuncGeth_ConfirmFunc(t *testing.T) {
121129
tx := tt.giveTx(t, client)
122130

123131
// Generate the confirm function
124-
functor := ConfirmFuncGeth(1 * time.Second)
132+
functor := ConfirmFuncGeth(1*time.Second, tt.confirmerOpts...)
125133
confirmFunc, err := functor.Generate(
126134
t.Context(), chainsel.TEST_1000.Selector, client, adminTransactor.From,
127135
)

0 commit comments

Comments
 (0)