github.com/cgcardona/r-subnet-evm@v0.1.5/cmd/simulator/load/worker.go (about)

     1  // Copyright (C) 2023, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package load
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"time"
    10  
    11  	"github.com/cgcardona/r-subnet-evm/core/types"
    12  	"github.com/cgcardona/r-subnet-evm/ethclient"
    13  	"github.com/cgcardona/r-subnet-evm/interfaces"
    14  	"github.com/ethereum/go-ethereum/common"
    15  	"github.com/ethereum/go-ethereum/log"
    16  )
    17  
    18  type singleAddressTxWorker struct {
    19  	client ethclient.Client
    20  
    21  	acceptedNonce uint64
    22  	address       common.Address
    23  
    24  	sub      interfaces.Subscription
    25  	newHeads chan *types.Header
    26  }
    27  
    28  // NewSingleAddressTxWorker creates and returns a singleAddressTxWorker
    29  func NewSingleAddressTxWorker(ctx context.Context, client ethclient.Client, address common.Address) *singleAddressTxWorker {
    30  	newHeads := make(chan *types.Header)
    31  	tw := &singleAddressTxWorker{
    32  		client:   client,
    33  		address:  address,
    34  		newHeads: newHeads,
    35  	}
    36  
    37  	sub, err := client.SubscribeNewHead(ctx, newHeads)
    38  	if err != nil {
    39  		log.Debug("failed to subscribe new heads, falling back to polling", "err", err)
    40  	} else {
    41  		tw.sub = sub
    42  	}
    43  
    44  	return tw
    45  }
    46  
    47  func (tw *singleAddressTxWorker) IssueTx(ctx context.Context, tx *types.Transaction) error {
    48  	return tw.client.SendTransaction(ctx, tx)
    49  }
    50  
    51  func (tw *singleAddressTxWorker) ConfirmTx(ctx context.Context, tx *types.Transaction) error {
    52  	txNonce := tx.Nonce()
    53  
    54  	for {
    55  		// If the is less than what has already been accepted, the transaction is confirmed
    56  		if txNonce < tw.acceptedNonce {
    57  			return nil
    58  		}
    59  
    60  		select {
    61  		case <-tw.newHeads:
    62  		case <-time.After(time.Second):
    63  		case <-ctx.Done():
    64  			return fmt.Errorf("failed to await tx %s nonce %d: %w", tx.Hash(), txNonce, ctx.Err())
    65  		}
    66  
    67  		// Update the worker's accepted nonce, so we can check on the next iteration
    68  		// if the transaction has been accepted.
    69  		acceptedNonce, err := tw.client.NonceAt(ctx, tw.address, nil)
    70  		if err != nil {
    71  			return fmt.Errorf("failed to await tx %s nonce %d: %w", tx.Hash(), txNonce, err)
    72  		}
    73  		tw.acceptedNonce = acceptedNonce
    74  	}
    75  }
    76  
    77  func (tw *singleAddressTxWorker) Close(ctx context.Context) error {
    78  	if tw.sub != nil {
    79  		tw.sub.Unsubscribe()
    80  	}
    81  	close(tw.newHeads)
    82  	return nil
    83  }