Skip to content

Commit dd6cb15

Browse files
committed
refactoring FundAccounts to work concurrently
1 parent 8542edb commit dd6cb15

File tree

2 files changed

+104
-37
lines changed

2 files changed

+104
-37
lines changed

cmd/loadtest/account.go

Lines changed: 103 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"github.com/ethereum/go-ethereum/accounts/abi/bind"
1313
"github.com/ethereum/go-ethereum/common"
1414
"github.com/ethereum/go-ethereum/core/types"
15-
ethtypes "github.com/ethereum/go-ethereum/core/types"
1615
"github.com/ethereum/go-ethereum/crypto"
1716
"github.com/ethereum/go-ethereum/ethclient"
1817
"github.com/rs/zerolog/log"
@@ -161,20 +160,76 @@ func (ap *AccountPool) AddReusableNonce(address common.Address, nonce uint64) er
161160
return nil
162161
}
163162

164-
func (ap *AccountPool) FundAccounts() error {
163+
func (ap *AccountPool) FundAccounts(ctx context.Context) error {
165164
ap.mu.Lock()
166165
defer ap.mu.Unlock()
167166

167+
wg := sync.WaitGroup{}
168+
wg.Add(len(ap.accounts))
169+
170+
txCh := make(chan *types.Transaction, len(ap.accounts))
171+
errCh := make(chan error, len(ap.accounts))
172+
173+
tops, err := bind.NewKeyedTransactorWithChainID(ap.fundingPrivateKey, ap.chainID)
174+
if err != nil {
175+
log.Error().Err(err).Msg("Unable create transaction signer")
176+
return err
177+
}
178+
179+
nonce, err := ap.client.PendingNonceAt(ctx, tops.From)
180+
if err != nil {
181+
log.Error().Err(err).Msg("Unable to get nonce")
182+
}
183+
168184
for i := range ap.accounts {
169-
account := ap.accounts[i]
170-
if !account.funded {
171-
err := ap.fundAccountIfNeeded(context.Background(), account)
185+
accountToFund := ap.accounts[i]
186+
go func(forcedNonce uint64, account Account) {
187+
defer wg.Done()
188+
if !account.funded {
189+
tx, err := ap.fundAccountIfNeeded(ctx, account, &forcedNonce, false)
190+
if err != nil {
191+
errCh <- fmt.Errorf("failed to fund account: %w", err)
192+
}
193+
if tx != nil {
194+
txCh <- tx
195+
}
196+
}
197+
}(nonce, accountToFund)
198+
nonce++
199+
}
200+
201+
wg.Wait()
202+
203+
close(errCh)
204+
close(txCh)
205+
206+
for err := range errCh {
207+
if err != nil {
208+
return err
209+
}
210+
}
211+
212+
for tx := range txCh {
213+
if tx != nil {
214+
log.Debug().
215+
Str("address", tx.To().Hex()).
216+
Str("txHash", tx.Hash().Hex()).
217+
Msg("transaction to fund account sent")
218+
219+
_, err := ap.waitMined(ctx, tx)
172220
if err != nil {
173-
return fmt.Errorf("failed to fund account: %w", err)
221+
log.Error().
222+
Str("address", tx.To().Hex()).
223+
Str("txHash", tx.Hash().Hex()).
224+
Msgf("transaction to fund account failed")
225+
return err
174226
}
175227
}
176228
}
177229

230+
log.Debug().
231+
Msg("All accounts funded")
232+
178233
return nil
179234
}
180235

@@ -209,7 +264,7 @@ func (ap *AccountPool) next(ctx context.Context) (Account, error) {
209264
}
210265
account := ap.accounts[ap.currentAccountIndex]
211266

212-
err := ap.fundAccountIfNeeded(ctx, account)
267+
_, err := ap.fundAccountIfNeeded(ctx, account, nil, true)
213268
if err != nil {
214269
return Account{}, err
215270
}
@@ -232,45 +287,46 @@ func (ap *AccountPool) next(ctx context.Context) (Account, error) {
232287
return account, nil
233288
}
234289

235-
func (ap *AccountPool) fundAccountIfNeeded(ctx context.Context, account Account) error {
290+
func (ap *AccountPool) fundAccountIfNeeded(ctx context.Context, account Account, forcedNonce *uint64, waitToFund bool) (*types.Transaction, error) {
236291
// if account is funded, return it
237292
if account.funded {
238-
return nil
293+
return nil, nil
239294
}
240295

241296
// Check if the account must be funded
242-
balance, err := ap.client.BalanceAt(context.Background(), account.address, nil)
297+
balance, err := ap.client.BalanceAt(ctx, account.address, nil)
243298
if err != nil {
244-
return fmt.Errorf("failed to check account balance: %w", err)
299+
return nil, fmt.Errorf("failed to check account balance: %w", err)
245300
}
246301
// if account has enough balance
247302
if balance.Cmp(ap.fundingAmount) >= 0 {
248-
return nil
303+
return nil, nil
249304
}
250305

251306
// Fund the account
252307
log.Debug().
253308
Str("address", account.address.Hex()).
254309
Str("balance", balance.String()).
255310
Msg("account needs to be funded")
256-
_, err = ap.fund(ctx, account, true)
311+
tx, err := ap.fund(ctx, account, forcedNonce, waitToFund)
257312
if err != nil {
258-
return fmt.Errorf("failed to fund account: %w", err)
313+
return nil, fmt.Errorf("failed to fund account: %w", err)
259314
}
260315

261-
balance, err = ap.client.BalanceAt(context.Background(), account.address, nil)
262-
if err != nil {
263-
return fmt.Errorf("failed to check account balance: %w", err)
316+
if waitToFund {
317+
balance, err = ap.client.BalanceAt(ctx, account.address, nil)
318+
if err != nil {
319+
return tx, fmt.Errorf("failed to check account balance: %w", err)
320+
}
321+
log.Debug().
322+
Str("address", account.address.Hex()).
323+
Str("balance", balance.String()).
324+
Msg("account funded")
264325
}
265-
log.Debug().
266-
Str("address", account.address.Hex()).
267-
Str("balance", balance.String()).
268-
Msg("account funded")
269-
270-
return nil
326+
return tx, nil
271327
}
272328

273-
func (ap *AccountPool) fund(ctx context.Context, acc Account, waitToFund bool) (*types.Transaction, error) {
329+
func (ap *AccountPool) fund(ctx context.Context, acc Account, forcedNonce *uint64, waitToFund bool) (*types.Transaction, error) {
274330
// Fund the account
275331
ltp := inputLoadTestParams
276332

@@ -282,14 +338,20 @@ func (ap *AccountPool) fund(ctx context.Context, acc Account, waitToFund bool) (
282338
tops.GasLimit = uint64(21000)
283339
tops = configureTransactOpts(ctx, ap.client, tops)
284340

285-
nonce, err := ap.client.PendingNonceAt(ctx, tops.From)
286-
if err != nil {
287-
log.Error().Err(err).Msg("Unable to get nonce")
341+
var nonce uint64
342+
343+
if forcedNonce != nil {
344+
nonce = *forcedNonce
345+
} else {
346+
nonce, err = ap.client.PendingNonceAt(ctx, tops.From)
347+
if err != nil {
348+
log.Error().Err(err).Msg("Unable to get nonce")
349+
}
288350
}
289351

290-
var tx *ethtypes.Transaction
352+
var tx *types.Transaction
291353
if *ltp.LegacyTransactionMode {
292-
tx = ethtypes.NewTx(&ethtypes.LegacyTx{
354+
tx = types.NewTx(&types.LegacyTx{
293355
Nonce: nonce,
294356
To: &acc.address,
295357
Value: ap.fundingAmount,
@@ -298,7 +360,7 @@ func (ap *AccountPool) fund(ctx context.Context, acc Account, waitToFund bool) (
298360
Data: nil,
299361
})
300362
} else {
301-
dynamicFeeTx := &ethtypes.DynamicFeeTx{
363+
dynamicFeeTx := &types.DynamicFeeTx{
302364
ChainID: ap.chainID,
303365
Nonce: nonce,
304366
To: &acc.address,
@@ -308,7 +370,7 @@ func (ap *AccountPool) fund(ctx context.Context, acc Account, waitToFund bool) (
308370
Data: nil,
309371
Value: ap.fundingAmount,
310372
}
311-
tx = ethtypes.NewTx(dynamicFeeTx)
373+
tx = types.NewTx(dynamicFeeTx)
312374
}
313375

314376
signedTx, err := tops.Signer(*ltp.FromETHAddress, tx)
@@ -333,10 +395,18 @@ func (ap *AccountPool) fund(ctx context.Context, acc Account, waitToFund bool) (
333395
if err != nil {
334396
log.Error().
335397
Str("address", acc.address.Hex()).
336-
Str("txHash", receipt.TxHash.Hex()).
337-
Msgf("transaction to fund account failed")
398+
Str("txHash", signedTx.Hash().Hex()).
399+
Msgf("failed to wait for transaction to be mined")
338400
return nil, err
339401
}
402+
403+
if receipt.Status != types.ReceiptStatusSuccessful {
404+
log.Error().
405+
Str("address", acc.address.Hex()).
406+
Str("txHash", receipt.TxHash.Hex()).
407+
Msgf("failed to wait for transaction to be mined")
408+
return nil, fmt.Errorf("transaction failed")
409+
}
340410
}
341411

342412
return signedTx, nil
@@ -353,9 +423,6 @@ func (ap *AccountPool) waitMined(ctx context.Context, tx *types.Transaction) (*t
353423
Msg("Unable to wait for transaction to be mined")
354424
return nil, err
355425
}
356-
if receipt.Status != ethtypes.ReceiptStatusSuccessful {
357-
return nil, fmt.Errorf("transaction failed")
358-
}
359426
return receipt, nil
360427
}
361428

cmd/loadtest/loadtest.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ func initializeLoadTestParams(ctx context.Context, c *ethclient.Client) error {
339339

340340
preFundSendingAddresses := *inputLoadTestParams.PreFundSendingAddresses
341341
if preFundSendingAddresses {
342-
err := accountPool.FundAccounts()
342+
err := accountPool.FundAccounts(ctx)
343343
if err != nil {
344344
log.Error().Err(err).Msg("Unable to fund sending addresses")
345345
return fmt.Errorf("unable to fund sending addresses. %w", err)

0 commit comments

Comments
 (0)