Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tools/preconf-rpc/backrunner/backrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ func (b *backrunner) checkRewards(ctx context.Context, start int64) error {
if !ok {
continue
}
// 90% to user, 10% to platform
amount = new(big.Int).Div(new(big.Int).Mul(amount, big.NewInt(90)), big.NewInt(100))
if updated, err := b.store.UpdateSwapReward(ctx, amount, record.BundleHashes); err != nil {
return fmt.Errorf("updating backrun reward: %w", err)
} else if updated {
Expand Down
1 change: 1 addition & 0 deletions tools/preconf-rpc/backrunner/backrunner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ func TestBackrun(t *testing.T) {
for {
if reward, exists := st.GetReward(common.HexToHash("0xa3d8155e77cc46237e007e7a1274ca277209c47f27bae4405c74f01bb14673ec")); exists {
expectedReward := big.NewInt(111444335163840)
expectedReward = new(big.Int).Div(new(big.Int).Mul(expectedReward, big.NewInt(90)), big.NewInt(100)) // 90% to user
if reward.Cmp(expectedReward) != 0 {
t.Fatalf("unexpected reward: got %v, want %v", reward, expectedReward)
}
Expand Down
41 changes: 35 additions & 6 deletions tools/preconf-rpc/blocktracker/blocktracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/primev/mev-commit/x/contracts/txmonitor"
"golang.org/x/sync/errgroup"
)

Expand All @@ -22,6 +23,15 @@ type EthClient interface {
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
}

type BatchReceiptGetter interface {
BatchReceipts(ctx context.Context, txHashes []common.Hash) ([]txmonitor.Result, error)
}

type ReceiptStore interface {
GetReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
StoreReceipt(ctx context.Context, receipt *types.Receipt) error
}

type LatestBlockInfo struct {
Number uint64
Time int64
Expand All @@ -33,24 +43,28 @@ type blockTracker struct {
latestBlockInfo atomic.Pointer[LatestBlockInfo]
blocks *lru.Cache[uint64, *types.Block]
client EthClient
receiptGetter BatchReceiptGetter
receiptStore ReceiptStore
log *slog.Logger
txnToCheckMu sync.Mutex
txnsToCheck map[common.Hash]chan uint64
newBlockChan chan uint64
}

func NewBlockTracker(client EthClient, log *slog.Logger) (*blockTracker, error) {
func NewBlockTracker(client EthClient, receiptGetter BatchReceiptGetter, receiptStore ReceiptStore, log *slog.Logger) (*blockTracker, error) {
cache, err := lru.New[uint64, *types.Block](1000)
if err != nil {
log.Error("Failed to create LRU cache", "error", err)
return nil, err
}
return &blockTracker{
blocks: cache,
client: client,
log: log,
txnsToCheck: make(map[common.Hash]chan uint64),
newBlockChan: make(chan uint64, 1),
blocks: cache,
client: client,
receiptGetter: receiptGetter,
receiptStore: receiptStore,
log: log,
txnsToCheck: make(map[common.Hash]chan uint64),
newBlockChan: make(chan uint64, 1),
}, nil
}

Expand Down Expand Up @@ -141,6 +155,21 @@ func (b *blockTracker) Start(ctx context.Context) <-chan struct{} {
delete(b.txnsToCheck, txHash)
}
b.txnToCheckMu.Unlock()
receipts, err := b.receiptGetter.BatchReceipts(egCtx, txnsToClear)
if err != nil {
b.log.Error("Failed to get batch receipts", "error", err)
continue
}
for _, res := range receipts {
if res.Err != nil {
b.log.Error("Failed to get receipt for txn", "txHash", res.Receipt.TxHash.Hex(), "error", res.Err)
continue
}
err = b.receiptStore.StoreReceipt(egCtx, res.Receipt)
if err != nil {
b.log.Error("Failed to store receipt", "txHash", res.Receipt.TxHash.Hex(), "error", err)
}
}
}
}
})
Expand Down
60 changes: 59 additions & 1 deletion tools/preconf-rpc/blocktracker/blocktracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package blocktracker_test

import (
"context"
"errors"
"hash"
"math/big"
"os"
Expand All @@ -12,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/primev/mev-commit/tools/preconf-rpc/blocktracker"
"github.com/primev/mev-commit/x/contracts/txmonitor"
"github.com/primev/mev-commit/x/util"
"golang.org/x/crypto/sha3"
)
Expand Down Expand Up @@ -58,6 +60,40 @@ func (m *mockEthClient) PendingNonceAt(ctx context.Context, account common.Addre
return 0, nil
}

type mockBatchReceiptGetter struct {
receipts map[common.Hash]*types.Receipt
}

func (m *mockBatchReceiptGetter) BatchReceipts(ctx context.Context, txHashes []common.Hash) ([]txmonitor.Result, error) {
receipts := make([]txmonitor.Result, len(txHashes))
for i := range txHashes {
receipt, exists := m.receipts[txHashes[i]]
if exists {
receipts[i] = txmonitor.Result{Receipt: receipt, Err: nil}
} else {
receipts[i] = txmonitor.Result{Receipt: nil, Err: errors.New("receipt not found")}
}
}
return receipts, nil
}

type mockReceiptStore struct {
receipts map[common.Hash]*types.Receipt
}

func (m *mockReceiptStore) GetReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
receipt, exists := m.receipts[txHash]
if !exists {
return nil, errors.New("receipt not found")
}
return receipt, nil
}

func (m *mockReceiptStore) StoreReceipt(ctx context.Context, receipt *types.Receipt) error {
m.receipts[receipt.TxHash] = receipt
return nil
}

type testHasher struct {
hasher hash.Hash
}
Expand Down Expand Up @@ -128,7 +164,29 @@ func TestBlockTracker(t *testing.T) {
},
}

tracker, err := blocktracker.NewBlockTracker(client, util.NewTestLogger(os.Stdout))
receiptGetter := &mockBatchReceiptGetter{
receipts: map[common.Hash]*types.Receipt{
tx1.Hash(): {
TxHash: tx1.Hash(),
BlockNumber: big.NewInt(100),
},
tx2.Hash(): {
TxHash: tx2.Hash(),
BlockNumber: big.NewInt(100),
},
tx3.Hash(): {
TxHash: tx3.Hash(),
BlockNumber: big.NewInt(101),
},
tx4.Hash(): nil, // Simulate missing receipt
},
}

receiptStore := &mockReceiptStore{
receipts: make(map[common.Hash]*types.Receipt),
}

tracker, err := blocktracker.NewBlockTracker(client, receiptGetter, receiptStore, util.NewTestLogger(os.Stdout))
if err != nil {
t.Fatalf("Failed to create block tracker: %v", err)
}
Expand Down
21 changes: 20 additions & 1 deletion tools/preconf-rpc/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type Store interface {
HasBalance(ctx context.Context, account common.Address, amount *big.Int) bool
AlreadySubsidized(ctx context.Context, account common.Address) bool
AddSubsidy(ctx context.Context, account common.Address, amount *big.Int) error
GetReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
StoreReceipt(ctx context.Context, receipt *types.Receipt) error
}

type BlockTracker interface {
Expand Down Expand Up @@ -583,13 +585,30 @@ func (h *rpcMethodHandler) handleGetTxReceipt(ctx context.Context, params ...any

txHash := common.HexToHash(txHashStr)

receipt, err := h.store.GetReceipt(ctx, txHash)
if err == nil && receipt != nil {
receiptJSON, err := json.Marshal(receipt)
if err != nil {
h.logger.Error("Failed to marshal receipt to JSON", "error", err, "txHash", txHash)
return nil, false, rpcserver.NewJSONErr(
rpcserver.CodeCustomError,
"failed to marshal receipt",
)
}
return receiptJSON, false, nil
}

txn, err := h.store.GetTransactionByHash(ctx, txHash)
if err != nil {
return nil, true, nil
}

if txn.Status != sender.TxStatusFailed && txn.Status != sender.TxStatusPreConfirmed {
switch txn.Status {
case sender.TxStatusPending, sender.TxStatusConfirmed:
// go to RPC proxy
return nil, true, nil
case sender.TxStatusPreConfirmed, sender.TxStatusFailed:
// continue processing
}

logs, err := h.store.GetTransactionLogs(ctx, txHash)
Expand Down
3 changes: 2 additions & 1 deletion tools/preconf-rpc/points/points.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
"github.com/ethereum/go-ethereum/common"
)

const weiPerPoint = 33_333_333_333_333
// 0.00001 ETH in wei
const weiPerPoint = 10000000000000

type pointsTracker struct {
apiURL string
Expand Down
7 changes: 6 additions & 1 deletion tools/preconf-rpc/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"sync"
"time"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
_ "github.com/lib/pq"
Expand All @@ -36,6 +37,7 @@ import (
"github.com/primev/mev-commit/tools/preconf-rpc/sim"
"github.com/primev/mev-commit/tools/preconf-rpc/store"
"github.com/primev/mev-commit/x/accountsync"
"github.com/primev/mev-commit/x/contracts/txmonitor"
"github.com/primev/mev-commit/x/health"
"github.com/primev/mev-commit/x/keysigner"
"github.com/primev/mev-commit/x/transfer"
Expand Down Expand Up @@ -246,6 +248,8 @@ func New(config *Config) (*Service, error) {

blockTracker, err := blocktracker.NewBlockTracker(
l1RPCClient,
txmonitor.NewEVMHelperWithLogger(l1RPCClient, config.Logger.With("module", "evmhelper"), map[common.Address]*abi.ABI{}),
rpcstore,
config.Logger.With("module", "blocktracker"),
)
if err != nil {
Expand Down Expand Up @@ -712,7 +716,8 @@ func initDB(opts *Config) (db *sql.DB, err error) {

db.SetMaxOpenConns(50)
db.SetMaxIdleConns(25)
db.SetConnMaxLifetime(1 * time.Hour)
db.SetConnMaxLifetime(2 * time.Hour)
db.SetConnMaxIdleTime(15 * time.Minute)

return db, err
}
Expand Down
Loading
Loading