Documentation ¶
Index ¶
- Variables
- func BumpGas(config orm.ConfigReader, originalGasPrice *big.Int) (*big.Int, error)
- func FindEthTxesRequiringResend(db *gorm.DB, olderThan time.Time) (attempts []models.EthTxAttempt, err error)
- func FindEthTxsRequiringGasBump(db *gorm.DB, address gethCommon.Address, ...) (etxs []models.EthTx, err error)
- func FindEthTxsRequiringRebroadcast(db *gorm.DB, address gethCommon.Address, ...) (etxs []models.EthTx, err error)
- func FindEthTxsRequiringResubmissionDueToInsufficientEth(db *gorm.DB, address gethCommon.Address) (etxs []models.EthTx, err error)
- func GetNextNonce(db *gorm.DB, address gethCommon.Address) (int64, error)
- func IncrementNextNonce(db *gorm.DB, address gethCommon.Address, currentNonce int64) error
- func NewEthConfirmer(store *store.Store, config orm.ConfigReader) *ethConfirmer
- func SendEther(s *strpkg.Store, from, to gethCommon.Address, value assets.Eth) (etx models.EthTx, err error)
- type EthBroadcaster
- type EthResender
- type Log
- type NSinserttx
- type NonceSyncer
- type Receipt
Constants ¶
This section is empty.
Variables ¶
var ( // ErrCouldNotGetReceipt is the error string we save if we reach our finality depth for a confirmed transaction without ever getting a receipt // This most likely happened because an external wallet used the account for this nonce ErrCouldNotGetReceipt = "could not get receipt" )
Functions ¶
func BumpGas ¶
BumpGas computes the next gas price to attempt as the largest of: - A configured percentage bump (ETH_GAS_BUMP_PERCENT) on top of the baseline price. - A configured fixed amount of Wei (ETH_GAS_PRICE_WEI) on top of the baseline price. The baseline price is the maximum of the previous gas price attempt and the node's current gas price.
func FindEthTxesRequiringResend ¶
func FindEthTxesRequiringResend(db *gorm.DB, olderThan time.Time) (attempts []models.EthTxAttempt, err error)
FindEthTxesRequiringResend returns the highest priced attempt for each eth_tx that was last sent before or at the given time
func FindEthTxsRequiringGasBump ¶
func FindEthTxsRequiringGasBump(db *gorm.DB, address gethCommon.Address, blockNum, gasBumpThreshold, depth int64) (etxs []models.EthTx, err error)
FindEthTxsRequiringGasBump returns transactions that have all attempts which are unconfirmed for at least gasBumpThreshold blocks, limited by limit pending transactions
It also returns eth_txes that are unconfirmed with no eth_tx_attempts
func FindEthTxsRequiringRebroadcast ¶
func FindEthTxsRequiringRebroadcast(db *gorm.DB, address gethCommon.Address, blockNum, gasBumpThreshold, depth int64) (etxs []models.EthTx, err error)
FindEthTxsRequiringRebroadcast returns attempts that hit insufficient eth, and attempts that need bumping, in nonce ASC order
func FindEthTxsRequiringResubmissionDueToInsufficientEth ¶
func FindEthTxsRequiringResubmissionDueToInsufficientEth(db *gorm.DB, address gethCommon.Address) (etxs []models.EthTx, err error)
FindEthTxsRequiringResubmissionDueToInsufficientEth returns transactions that need to be re-sent because they hit an out-of-eth error on a previous block
func GetNextNonce ¶
GetNextNonce returns keys.next_nonce for the given address
func IncrementNextNonce ¶
IncrementNextNonce increments keys.next_nonce by 1
func NewEthConfirmer ¶
func NewEthConfirmer(store *store.Store, config orm.ConfigReader) *ethConfirmer
Types ¶
type EthBroadcaster ¶
type EthBroadcaster interface { Start() error Close() error Trigger() ProcessUnstartedEthTxs(models.Key) error }
EthBroadcaster monitors eth_txes for transactions that need to be broadcast, assigns nonces and ensures that at least one eth node somewhere has received the transaction successfully.
This does not guarantee delivery! A whole host of other things can subsequently go wrong such as transactions being evicted from the mempool, eth nodes going offline etc. Responsibility for ensuring eventual inclusion into the chain falls on the shoulders of the ethConfirmer.
What ethBroadcaster does guarantee is: - a monotonic series of increasing nonces for eth_txes that can all eventually be confirmed if you retry enough times - transition of eth_txes out of unstarted into either fatal_error or unconfirmed - existence of a saved eth_tx_attempt
func NewEthBroadcaster ¶
func NewEthBroadcaster(store *store.Store, config orm.ConfigReader, eventBroadcaster postgres.EventBroadcaster) EthBroadcaster
NewEthBroadcaster returns a new concrete ethBroadcaster
type EthResender ¶
type EthResender struct {
// contains filtered or unexported fields
}
EthResender periodically picks up transactions that have been languishing unconfirmed for a configured amount of time without being sent, and sends their highest priced attempt again. This helps to defend against geth/parity silently dropping txes, or txes being ejected from the mempool.
Previously we relied on the bumper to do this for us implicitly but there can occasionally be problems with this (e.g. abnormally long block times, or if gas bumping is disabled)
func NewEthResender ¶
func NewEthResender(db *gorm.DB, ethClient eth.Client, pollInterval time.Duration, config orm.ConfigReader) *EthResender
func (*EthResender) Start ¶
func (er *EthResender) Start()
func (*EthResender) Stop ¶
func (er *EthResender) Stop()
type Log ¶
type Log struct { Address common.Address `json:"address"` Topics []common.Hash `json:"topics"` Data []byte `json:"data"` BlockNumber uint64 `json:"blockNumber"` TxHash common.Hash `json:"transactionHash"` TxIndex uint `json:"transactionIndex"` BlockHash common.Hash `json:"blockHash"` Index uint `json:"logIndex"` Removed bool `json:"removed"` }
Log represents a contract log event.
Copied from go-ethereum: https://github.com/ethereum/go-ethereum/blob/ce9a289fa48e0d2593c4aaa7e207c8a5dd3eaa8a/core/types/log.go
We use our own version because Geth's version specifies various gencodec:"required" fields which cause unhelpful errors when unmarshalling from an empty JSON object which can happen in the batch fetcher.
func FromGethLog ¶
FromGethLog converts a gethTypes.Log to a Log
func (*Log) UnmarshalJSON ¶
UnmarshalJSON unmarshals from JSON.
type NSinserttx ¶
type NSinserttx struct { Etx models.EthTx Attempt models.EthTxAttempt }
NSinserttx represents an EthTx and Attempt to be inserted together
type NonceSyncer ¶
type NonceSyncer struct {
// contains filtered or unexported fields
}
NonceSyncer manages the delicate task of syncing the local nonce with the chain nonce in case of divergence.
On startup, we check each key for the nonce value on chain and compare it to our local value.
Usually the on-chain nonce will be the same as (or lower than) the next_nonce in the DB, in which case we do nothing.
If we are restoring from a backup however, or another wallet has used the account, the chain nonce might be higher than our local one. In this scenario, we must fastforward the local nonce to match the chain nonce.
The problem with doing this is that now Chainlink does not have any ownership or control over potentially pending transactions with nonces between our local highest nonce and the chain nonce. If one of those transactions is pushed out of the mempool or re-org'd out of the chain, we run the risk of being stuck with a gap in the nonce sequence that will never be filled.
The solution is to query the chain for our own transactions and take ownership of them by writing them to the database and letting the EthConfirmer handle them as it would any other transaction.
This is not quite as straightforward as one might expect. We cannot query transactions from our account to infinite depth (geth does not support this). The best we can do is to query for all transactions sent within the past ETH_FINALITY_DEPTH blocks and find the ones sent by our address(es).
This gives us re-org protection up to ETH_FINALITY_DEPTH deep in the worst case, which is in line with our other guarantees.
func NewNonceSyncer ¶
func NewNonceSyncer(store *store.Store, config orm.ConfigReader, ethClient eth.Client) *NonceSyncer
NewNonceSyncer returns a new syncer
type Receipt ¶
type Receipt struct { PostState []byte `json:"root"` Status uint64 `json:"status"` CumulativeGasUsed uint64 `json:"cumulativeGasUsed"` Bloom gethTypes.Bloom `json:"logsBloom"` Logs []*Log `json:"logs"` TxHash common.Hash `json:"transactionHash"` ContractAddress common.Address `json:"contractAddress"` GasUsed uint64 `json:"gasUsed"` BlockHash common.Hash `json:"blockHash,omitempty"` BlockNumber *big.Int `json:"blockNumber,omitempty"` TransactionIndex uint `json:"transactionIndex"` }
Receipt represents an ethereum receipt.
Copied from go-ethereum: https://github.com/ethereum/go-ethereum/blob/ce9a289fa48e0d2593c4aaa7e207c8a5dd3eaa8a/core/types/receipt.go#L50
We use our own version because Geth's version specifies various gencodec:"required" fields which cause unhelpful errors when unmarshalling from an empty JSON object which can happen in the batch fetcher.
func FromGethReceipt ¶
FromGethReceipt converts a gethTypes.Receipt to a Receipt
func (Receipt) IsUnmined ¶
IsUnmined returns true if the receipt is for a TX that has not been mined yet. Supposedly according to the spec this should never happen, but Parity does it anyway.
func (Receipt) IsZero ¶
IsZero returns true if receipt is the zero receipt Batch calls to the RPC will return a pointer to an empty Receipt struct Easiest way to check if the receipt was missing is to see if the hash is 0x0 Real receipts will always have the TxHash set
func (Receipt) MarshalJSON ¶
MarshalJSON marshals Receipt as JSON. Copied from: https://github.com/ethereum/go-ethereum/blob/ce9a289fa48e0d2593c4aaa7e207c8a5dd3eaa8a/core/types/gen_receipt_json.go
func (*Receipt) UnmarshalJSON ¶
UnmarshalJSON unmarshals from JSON.