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

     1  // Package blockchain handles connections to various blockchains
     2  package blockchain
     3  
     4  import (
     5  	"context"
     6  	"crypto/ecdsa"
     7  	"encoding/json"
     8  	"math/big"
     9  	"time"
    10  
    11  	"github.com/ethereum/go-ethereum"
    12  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    13  	"github.com/ethereum/go-ethereum/common"
    14  	"github.com/ethereum/go-ethereum/common/hexutil"
    15  	"github.com/ethereum/go-ethereum/core/types"
    16  )
    17  
    18  // EVMClient is the interface that wraps a given client implementation for a blockchain, to allow for switching
    19  // of network types within the test suite
    20  // EVMClient can be connected to a single or multiple nodes,
    21  type EVMClient interface {
    22  	// Getters
    23  	Get() interface{}
    24  	GetNetworkName() string
    25  	NetworkSimulated() bool
    26  	GetChainID() *big.Int
    27  	GetClients() []EVMClient
    28  	GetDefaultWallet() *EthereumWallet
    29  	GetWallets() []*EthereumWallet
    30  	GetNetworkConfig() *EVMNetwork
    31  	GetNonceSetting() NonceSettings
    32  
    33  	GetHeaderSubscriptions() map[string]HeaderEventSubscription
    34  
    35  	// Setters
    36  	SetID(id int)
    37  	SetDefaultWallet(num int) error
    38  	SetWallets([]*EthereumWallet)
    39  	LoadWallets(ns EVMNetwork) error
    40  	SwitchNode(node int) error
    41  	SyncNonce(c EVMClient)
    42  
    43  	// On-chain Operations
    44  	BalanceAt(ctx context.Context, address common.Address) (*big.Int, error)
    45  	HeaderHashByNumber(ctx context.Context, bn *big.Int) (string, error)
    46  	HeaderTimestampByNumber(ctx context.Context, bn *big.Int) (uint64, error)
    47  	LatestBlockNumber(ctx context.Context) (uint64, error)
    48  	GetLatestFinalizedBlockHeader(ctx context.Context) (*types.Header, error)
    49  	AvgBlockTime(ctx context.Context) (time.Duration, error)
    50  	EstimatedFinalizationTime(ctx context.Context) (time.Duration, error)
    51  	SendTransaction(ctx context.Context, tx *types.Transaction) error
    52  	Fund(toAddress string, amount *big.Float, gasEstimations GasEstimations) error
    53  	ReturnFunds(fromKey *ecdsa.PrivateKey) error
    54  	DeployContract(
    55  		contractName string,
    56  		deployer ContractDeployer,
    57  	) (*common.Address, *types.Transaction, interface{}, error)
    58  	// TODO: Load and Deploy need to both agree to use an address pointer, there's unnecessary casting going on
    59  	LoadContract(contractName string, address common.Address, loader ContractLoader) (interface{}, error)
    60  	TransactionOpts(from *EthereumWallet) (*bind.TransactOpts, error)
    61  	NewTx(
    62  		fromPrivateKey *ecdsa.PrivateKey,
    63  		nonce uint64,
    64  		to common.Address,
    65  		value *big.Int,
    66  		gasEstimations GasEstimations,
    67  	) (*types.Transaction, error)
    68  	ProcessTransaction(tx *types.Transaction) error
    69  
    70  	MarkTxAsSentOnL2(tx *types.Transaction) error
    71  	ProcessEvent(name string, event *types.Log, confirmedChan chan bool, errorChan chan error) error
    72  	IsEventConfirmed(event *types.Log) (confirmed, removed bool, err error)
    73  	IsTxConfirmed(txHash common.Hash) (bool, error)
    74  	IsTxHeadFinalized(txHdr, header *SafeEVMHeader) (bool, *big.Int, time.Time, error)
    75  	WaitForFinalizedTx(txHash common.Hash) (*big.Int, time.Time, error)
    76  	PollFinality() error
    77  	CancelFinalityPolling()
    78  	GetTxReceipt(txHash common.Hash) (*types.Receipt, error)
    79  	RevertReasonFromTx(txHash common.Hash, abiString string) (string, interface{}, error)
    80  
    81  	ParallelTransactions(enabled bool)
    82  	Close() error
    83  	Backend() bind.ContractBackend
    84  	DeployBackend() bind.DeployBackend
    85  	// Deal with wrapped headers
    86  	SubscribeNewHeaders(ctx context.Context, headerChan chan *SafeEVMHeader) (ethereum.Subscription, error)
    87  	HeaderByNumber(ctx context.Context, number *big.Int) (*SafeEVMHeader, error)
    88  	HeaderByHash(ctx context.Context, hash common.Hash) (*SafeEVMHeader, error)
    89  
    90  	// Gas Operations
    91  	EstimateCostForChainlinkOperations(amountOfOperations int) (*big.Float, error)
    92  	EstimateTransactionGasCost() (*big.Int, error)
    93  	GasStats() *GasStats
    94  	// EstimateGas provides all gas stats needed, best for estimating gas and prices for a specific transaction
    95  	EstimateGas(callMsg ethereum.CallMsg) (GasEstimations, error)
    96  	// EstimateGasPrice provides a plain gas price estimate, best for quick checks and contract deployments
    97  	EstimateGasPrice() (*big.Int, error)
    98  
    99  	// Connection Status
   100  	// ConnectionIssue returns a channel that will receive a timestamp when the connection is lost
   101  	ConnectionIssue() chan time.Time
   102  	// ConnectionRestored returns a channel that will receive a timestamp when the connection is restored
   103  	ConnectionRestored() chan time.Time
   104  
   105  	// Event Subscriptions
   106  	AddHeaderEventSubscription(key string, subscriber HeaderEventSubscription)
   107  	DeleteHeaderEventSubscription(key string)
   108  	WaitForEvents() error
   109  	SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
   110  
   111  	// Polling Events
   112  	FilterLogs(ctx context.Context, filterQuery ethereum.FilterQuery) ([]types.Log, error)
   113  
   114  	RawJsonRPCCall(ctx context.Context, result interface{}, method string, params ...interface{}) error
   115  }
   116  
   117  // NodeHeader header with the ID of the node that received it
   118  type NodeHeader struct {
   119  	NodeID int
   120  	SafeEVMHeader
   121  }
   122  
   123  // SafeEVMHeader is a wrapper for the EVM header, to allow for the addition/removal of fields without breaking the interface
   124  type SafeEVMHeader struct {
   125  	Hash      common.Hash
   126  	Number    *big.Int
   127  	Timestamp time.Time
   128  	BaseFee   *big.Int
   129  }
   130  
   131  // GasEstimations is a wrapper for the gas estimations
   132  type GasEstimations struct {
   133  	GasUnits     uint64   // How many units of gas the transaction will use
   134  	GasPrice     *big.Int // Gas price of the transaction (for Legacy transactions)
   135  	GasTipCap    *big.Int // Gas tip cap of the transaction (for DynamicFee transactions)
   136  	GasFeeCap    *big.Int // Gas fee cap of the transaction (for DynamicFee transactions)
   137  	TotalGasCost *big.Int // Total gas cost of the transaction (gas units * total gas price)
   138  }
   139  
   140  // UnmarshalJSON enables Geth to unmarshal block headers into our custom type
   141  func (h *SafeEVMHeader) UnmarshalJSON(bs []byte) error {
   142  	type head struct {
   143  		Hash      common.Hash    `json:"hash"`
   144  		Number    *hexutil.Big   `json:"number"`
   145  		Timestamp hexutil.Uint64 `json:"timestamp"`
   146  		BaseFee   *hexutil.Big   `json:"baseFeePerGas"`
   147  	}
   148  
   149  	var jsonHead head
   150  	err := json.Unmarshal(bs, &jsonHead)
   151  	if err != nil {
   152  		return err
   153  	}
   154  
   155  	if jsonHead.Number == nil {
   156  		*h = SafeEVMHeader{}
   157  		return nil
   158  	}
   159  
   160  	h.Hash = jsonHead.Hash
   161  	h.Number = (*big.Int)(jsonHead.Number)
   162  	h.Timestamp = time.Unix(int64(jsonHead.Timestamp), 0).UTC()
   163  	h.BaseFee = (*big.Int)(jsonHead.BaseFee)
   164  	return nil
   165  }
   166  
   167  // HeaderEventSubscription is an interface for allowing callbacks when the client receives a new header
   168  type HeaderEventSubscription interface {
   169  	ReceiveHeader(header NodeHeader) error
   170  	Wait() error
   171  	Complete() bool
   172  }
   173  
   174  // ContractDeployer acts as a go-between function for general contract deployment
   175  type ContractDeployer func(auth *bind.TransactOpts, backend bind.ContractBackend) (
   176  	common.Address,
   177  	*types.Transaction,
   178  	interface{},
   179  	error,
   180  )
   181  
   182  // ContractLoader helps loading already deployed contracts
   183  type ContractLoader func(address common.Address, backend bind.ContractBackend) (
   184  	interface{},
   185  	error,
   186  )