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 )