Files
explorer-monorepo/backend/mempool/tracker.go

95 lines
2.3 KiB
Go

package mempool
import (
"context"
"database/sql"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/jackc/pgx/v5/pgxpool"
)
// Tracker tracks pending transactions in the mempool
type Tracker struct {
db *pgxpool.Pool
client *ethclient.Client
chainID int
}
// NewTracker creates a new mempool tracker
func NewTracker(db *pgxpool.Pool, client *ethclient.Client, chainID int) *Tracker {
return &Tracker{
db: db,
client: client,
chainID: chainID,
}
}
// TrackPendingTransaction tracks a pending transaction
func (t *Tracker) TrackPendingTransaction(ctx context.Context, tx *types.Transaction) error {
from, _ := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)
var toAddress sql.NullString
if tx.To() != nil {
toAddress.String = tx.To().Hex()
toAddress.Valid = true
}
var maxFeePerGas, maxPriorityFeePerGas sql.NullInt64
if tx.Type() == types.DynamicFeeTxType {
if tx.GasFeeCap() != nil {
maxFeePerGas.Int64 = tx.GasFeeCap().Int64()
maxFeePerGas.Valid = true
}
if tx.GasTipCap() != nil {
maxPriorityFeePerGas.Int64 = tx.GasTipCap().Int64()
maxPriorityFeePerGas.Valid = true
}
}
query := `
INSERT INTO mempool_transactions (
time, chain_id, hash, from_address, to_address, value,
gas_price, max_fee_per_gas, max_priority_fee_per_gas,
gas_limit, nonce, input_data_length, first_seen, status
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
ON CONFLICT (time, chain_id, hash) DO UPDATE SET
status = $14,
updated_at = NOW()
`
_, err := t.db.Exec(ctx, query,
time.Now(),
t.chainID,
tx.Hash().Hex(),
from.Hex(),
toAddress,
tx.Value().String(),
tx.GasPrice().Int64(),
maxFeePerGas,
maxPriorityFeePerGas,
tx.Gas(),
tx.Nonce(),
len(tx.Data()),
time.Now(),
"pending",
)
return err
}
// UpdateTransactionStatus updates transaction status when confirmed
func (t *Tracker) UpdateTransactionStatus(ctx context.Context, txHash common.Hash, blockNumber int64, status string) error {
query := `
UPDATE mempool_transactions
SET status = $1, confirmed_block_number = $2, confirmed_at = NOW()
WHERE chain_id = $3 AND hash = $4
`
_, err := t.db.Exec(ctx, query, status, blockNumber, t.chainID, txHash.Hex())
return err
}