github.com/smartcontractkit/chainlink-testing-framework/libs@v0.0.0-20240227141906-ec710b4eb1a3/blockchain/gas_stats.go (about)

     1  package blockchain
     2  
     3  import (
     4  	"sort"
     5  	"sync"
     6  
     7  	"github.com/rs/zerolog/log"
     8  )
     9  
    10  const (
    11  	// GWei one giga-wei used for gas calculations
    12  	GWei = 1e9
    13  	// ETH one eth in wei
    14  	ETH = 1e18
    15  )
    16  
    17  // GasStats helper struct to determine gas metrics across all txs of a test
    18  type GasStats struct {
    19  	NodeID       int
    20  	TotalGasUsed int64
    21  	SeenHashes   map[string]bool
    22  	ClientTXs    []TXGasData
    23  	addMu        sync.Mutex
    24  }
    25  
    26  // TXGasData transaction gas data
    27  type TXGasData struct {
    28  	TXHash            string
    29  	Value             uint64
    30  	GasLimit          uint64
    31  	GasUsed           uint64
    32  	GasPrice          uint64
    33  	CumulativeGasUsed uint64
    34  }
    35  
    36  // NewGasStats creates new gas stats collector
    37  func NewGasStats(nodeID int) *GasStats {
    38  	return &GasStats{
    39  		NodeID:     nodeID,
    40  		SeenHashes: make(map[string]bool),
    41  		ClientTXs:  make([]TXGasData, 0),
    42  	}
    43  }
    44  
    45  // AddClientTXData adds client TX data
    46  func (g *GasStats) AddClientTXData(data TXGasData) {
    47  	g.addMu.Lock()
    48  	defer g.addMu.Unlock()
    49  	if _, ok := g.SeenHashes[data.TXHash]; !ok {
    50  		g.ClientTXs = append(g.ClientTXs, data)
    51  	}
    52  }
    53  
    54  func (g *GasStats) txCost(data TXGasData) float64 {
    55  	fee := float64(data.GasPrice * data.GasUsed)
    56  	val := float64(data.Value)
    57  	return (fee + val) / ETH
    58  }
    59  
    60  func (g *GasStats) maxGasUsage() uint64 {
    61  	if len(g.ClientTXs) == 0 {
    62  		return 0
    63  	}
    64  	sort.Slice(g.ClientTXs, func(i, j int) bool {
    65  		return g.ClientTXs[i].GasUsed > g.ClientTXs[j].GasUsed
    66  	})
    67  	return g.ClientTXs[0].GasUsed
    68  }
    69  
    70  func (g *GasStats) totalCost() float64 {
    71  	var total float64
    72  	for _, tx := range g.ClientTXs {
    73  		total += g.txCost(tx)
    74  	}
    75  	return total
    76  }
    77  
    78  // PrintStats prints gas stats and total TXs cost
    79  func (g *GasStats) PrintStats() {
    80  	log.Info().Msg("---------- Start Gas Stats ----------")
    81  	log.Info().Int("Node", g.NodeID).Uint64("Gas (GWei)", g.maxGasUsage()).Msg("Max gas used")
    82  	for _, tx := range g.ClientTXs {
    83  		log.Info().
    84  			Int("Node", g.NodeID).
    85  			Float64("Value (ETH)", float64(tx.Value)/ETH).
    86  			Uint64("Gas used", tx.GasUsed).
    87  			Float64("Suggested gas price (GWei)", float64(tx.GasPrice)/GWei).
    88  			Uint64("Gas Limit", tx.GasLimit).
    89  			Float64("Cost (ETH)", g.txCost(tx)).
    90  			Msg("TX Cost")
    91  	}
    92  	log.Info().
    93  		Float64("ETH", g.totalCost()).
    94  		Msg("Total TXs cost")
    95  	log.Info().Msg("---------------- End ---------------")
    96  }