From 4ff73ed7b4b902887f1635a1404a028c342aa9e5 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:54:17 -0700 Subject: [PATCH 01/17] fix: deposit cache --- p2p/pkg/depositmanager/deposit.go | 64 +++++++++++++++++++ p2p/pkg/node/node.go | 15 ++++- p2p/pkg/preconfirmation/preconfirmation.go | 16 +++++ .../preconfirmation/preconfirmation_test.go | 11 ++++ p2p/pkg/preconfirmation/tracker/tracker.go | 28 ++++++++ 5 files changed, 133 insertions(+), 1 deletion(-) diff --git a/p2p/pkg/depositmanager/deposit.go b/p2p/pkg/depositmanager/deposit.go index 4ea43d730..30c32a533 100644 --- a/p2p/pkg/depositmanager/deposit.go +++ b/p2p/pkg/depositmanager/deposit.go @@ -5,9 +5,11 @@ import ( "fmt" "log/slog" "math/big" + "sync" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + lru "github.com/hashicorp/golang-lru/v2" bidderregistry "github.com/primev/mev-commit/contracts-abi/clients/BidderRegistry" "github.com/primev/mev-commit/x/contracts/events" "golang.org/x/sync/errgroup" @@ -26,6 +28,14 @@ type Store interface { RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error } +type pendingRefund struct { + bidder common.Address + provider common.Address + amount *big.Int +} + +type CommitmentDigest [32]byte + type DepositManager struct { store Store evtMgr events.EventManager @@ -35,6 +45,8 @@ type DepositManager struct { withdrawals chan *bidderregistry.BidderregistryBidderWithdrawal thisProviderAddress common.Address logger *slog.Logger + pendingRefunds *lru.Cache[CommitmentDigest, pendingRefund] + pendingRefundsMu sync.RWMutex } func NewDepositManager( @@ -44,6 +56,10 @@ func NewDepositManager( thisProviderAddress common.Address, logger *slog.Logger, ) *DepositManager { + pendingRefunds, err := lru.New[CommitmentDigest, pendingRefund](1000) + if err != nil { + panic(err) + } return &DepositManager{ store: store, bidderRegistry: bidderRegistry, @@ -53,6 +69,7 @@ func NewDepositManager( evtMgr: evtMgr, thisProviderAddress: thisProviderAddress, logger: logger, + pendingRefunds: pendingRefunds, } } @@ -288,3 +305,50 @@ func (dm *DepositManager) getDefaultBalance( return balance, nil } + +func (dm *DepositManager) AddPendingRefund( + commitmentDigest CommitmentDigest, + bidder common.Address, + provider common.Address, + amount *big.Int, +) { + dm.pendingRefundsMu.Lock() + defer dm.pendingRefundsMu.Unlock() + evicted := dm.pendingRefunds.Add(commitmentDigest, pendingRefund{ + bidder: bidder, + provider: provider, + amount: amount, + }) + if evicted { + dm.logger.Warn("evicted pending refund. Tracker may not be working properly", "commitmentDigest", commitmentDigest) + } +} + +func (dm *DepositManager) ApplyPendingRefund( + commitmentDigest CommitmentDigest, +) error { + dm.pendingRefundsMu.Lock() + defer dm.pendingRefundsMu.Unlock() + + pendingRefund, ok := dm.pendingRefunds.Get(commitmentDigest) + if !ok { + return status.Errorf(codes.NotFound, "pending refund not found for commitment digest %x", commitmentDigest) + } + removed := dm.pendingRefunds.Remove(commitmentDigest) + if !removed { + return status.Errorf(codes.Internal, "failed to remove pending refund from cache") + } + return dm.store.RefundBalanceIfExists(pendingRefund.bidder, pendingRefund.provider, pendingRefund.amount) +} + +func (dm *DepositManager) DropPendingRefund( + commitmentDigest CommitmentDigest, +) error { + dm.pendingRefundsMu.Lock() + defer dm.pendingRefundsMu.Unlock() + removed := dm.pendingRefunds.Remove(commitmentDigest) + if !removed { + return status.Errorf(codes.Internal, "failed to remove pending refund from cache") + } + return nil +} diff --git a/p2p/pkg/node/node.go b/p2p/pkg/node/node.go index 062346354..23e160161 100644 --- a/p2p/pkg/node/node.go +++ b/p2p/pkg/node/node.go @@ -39,6 +39,7 @@ import ( "github.com/primev/mev-commit/p2p/pkg/apiserver" "github.com/primev/mev-commit/p2p/pkg/crypto" "github.com/primev/mev-commit/p2p/pkg/depositmanager" + dm "github.com/primev/mev-commit/p2p/pkg/depositmanager" depositmanagerstore "github.com/primev/mev-commit/p2p/pkg/depositmanager/store" "github.com/primev/mev-commit/p2p/pkg/discovery" "github.com/primev/mev-commit/p2p/pkg/keyexchange" @@ -568,13 +569,15 @@ func NewNode(opts *Options) (*Node, error) { providerapiv1.RegisterProviderServer(grpcServer, providerAPI) bidProcessor = providerAPI srv.RegisterMetricsCollectors(providerAPI.Metrics()...) - depositMgr = depositmanager.NewDepositManager( + dmConcrete := depositmanager.NewDepositManager( depositmanagerstore.New(store), evtMgr, bidderRegistry, opts.KeySigner.GetAddress(), opts.Logger.With("component", "depositmanager"), ) + depositMgr = dmConcrete + tracker.SetDepositManager(dmConcrete) startables = append( startables, StartableObjWithDesc{ @@ -941,6 +944,16 @@ func (noOpDepositManager) CheckAndDeductDeposit(_ context.Context, _ common.Addr return func() error { return nil }, nil } +func (noOpDepositManager) AddPendingRefund(_ dm.CommitmentDigest, _ common.Address, _ common.Address, _ *big.Int) { +} + +func (noOpDepositManager) ApplyPendingRefund(_ dm.CommitmentDigest) error { + return nil +} +func (noOpDepositManager) DropPendingRefund(_ dm.CommitmentDigest) error { + return nil +} + type channelCloser <-chan struct{} func channelCloserFunc(c <-chan struct{}) io.Closer { diff --git a/p2p/pkg/preconfirmation/preconfirmation.go b/p2p/pkg/preconfirmation/preconfirmation.go index 85c5de565..aa0d79100 100644 --- a/p2p/pkg/preconfirmation/preconfirmation.go +++ b/p2p/pkg/preconfirmation/preconfirmation.go @@ -4,6 +4,7 @@ import ( "context" "errors" "log/slog" + "math/big" "sync" "time" @@ -14,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" + dm "github.com/primev/mev-commit/p2p/pkg/depositmanager" "github.com/primev/mev-commit/p2p/pkg/p2p" "github.com/primev/mev-commit/p2p/pkg/preconfirmation/store" providerapi "github.com/primev/mev-commit/p2p/pkg/rpc/provider" @@ -58,6 +60,12 @@ type DepositManager interface { providerAddr common.Address, bidAmount string, ) (func() error, error) + AddPendingRefund( + commitmentDigest dm.CommitmentDigest, + bidder common.Address, + provider common.Address, + amount *big.Int, + ) } type Tracker interface { @@ -365,6 +373,14 @@ func (p *Preconfirmation) handleBid( // If we reach here, the bid was successful successful = true + // Add pending refund. Preconf tracker will handle applying or dropping it from here. + bidAmount, ok := new(big.Int).SetString(bid.BidAmount, 10) + if !ok { + p.logger.Error("failed to parse bid amount", "bidAmount", bid.BidAmount) + return status.Errorf(codes.Internal, "failed to parse bid amount: %v", bid.BidAmount) + } + p.depositMgr.AddPendingRefund(commitmentDigest, *bidderAddr, providerAddr, bidAmount) + return nil } } diff --git a/p2p/pkg/preconfirmation/preconfirmation_test.go b/p2p/pkg/preconfirmation/preconfirmation_test.go index 5626eccaa..da3095d9f 100644 --- a/p2p/pkg/preconfirmation/preconfirmation_test.go +++ b/p2p/pkg/preconfirmation/preconfirmation_test.go @@ -5,6 +5,7 @@ import ( "crypto/rand" "io" "log/slog" + "math/big" "os" "testing" "time" @@ -19,6 +20,7 @@ import ( preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" p2pcrypto "github.com/primev/mev-commit/p2p/pkg/crypto" + dm "github.com/primev/mev-commit/p2p/pkg/depositmanager" "github.com/primev/mev-commit/p2p/pkg/p2p" p2ptest "github.com/primev/mev-commit/p2p/pkg/p2p/testing" "github.com/primev/mev-commit/p2p/pkg/preconfirmation" @@ -120,6 +122,15 @@ func (t *testDepositManager) CheckAndDeductDeposit( return func() error { return nil }, nil } +func (t *testDepositManager) AddPendingRefund( + commitmentDigest dm.CommitmentDigest, + bidder common.Address, + provider common.Address, + amount *big.Int, +) { + +} + type testTracker struct{} func (t *testTracker) TrackCommitment( diff --git a/p2p/pkg/preconfirmation/tracker/tracker.go b/p2p/pkg/preconfirmation/tracker/tracker.go index 32fd5bb76..ec471ed05 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker.go +++ b/p2p/pkg/preconfirmation/tracker/tracker.go @@ -20,6 +20,7 @@ import ( oracle "github.com/primev/mev-commit/contracts-abi/clients/Oracle" preconfcommstore "github.com/primev/mev-commit/contracts-abi/clients/PreconfManager" "github.com/primev/mev-commit/p2p/pkg/crypto" + dm "github.com/primev/mev-commit/p2p/pkg/depositmanager" "github.com/primev/mev-commit/p2p/pkg/notifications" "github.com/primev/mev-commit/p2p/pkg/p2p" "github.com/primev/mev-commit/p2p/pkg/preconfirmation/store" @@ -58,6 +59,7 @@ type Tracker struct { triggerOpen chan struct{} metrics *metrics logger *slog.Logger + depositMgr DepositManager // Nullable and only used by provider } type OptsGetter func(context.Context) (*bind.TransactOpts, error) @@ -96,6 +98,11 @@ type Watcher interface { WatchTx(txnHash common.Hash, nonce uint64) <-chan txmonitor.Result } +type DepositManager interface { + ApplyPendingRefund(commitmentDigest dm.CommitmentDigest) error + DropPendingRefund(commitmentDigest dm.CommitmentDigest) error +} + func NewTracker( chainID *big.Int, peerType p2p.PeerType, @@ -136,6 +143,10 @@ func NewTracker( } } +func (t *Tracker) SetDepositManager(depositMgr DepositManager) { + t.depositMgr = depositMgr +} + func (t *Tracker) Start(ctx context.Context) <-chan struct{} { doneChan := make(chan struct{}) @@ -538,6 +549,14 @@ func (t *Tracker) openCommitments( "providerAddress", commitment.ProviderAddress, "winner", newL1Block.Winner, ) + if t.depositMgr != nil { + commitmentDigest := dm.CommitmentDigest{} + copy(commitmentDigest[:], commitment.Commitment[:]) + if err := t.depositMgr.ApplyPendingRefund(commitmentDigest); err != nil { + t.logger.Error("failed to apply pending refund", "error", err) + } + t.logger.Info("applied pending refund", "commitmentDigest", commitmentDigest) + } continue } startTime := time.Now() @@ -702,6 +721,15 @@ func (t *Tracker) handleOpenedCommitmentStored( } } + if t.depositMgr != nil { + commitmentDigest := dm.CommitmentDigest{} + copy(commitmentDigest[:], cs.CommitmentDigest[:]) + if err := t.depositMgr.DropPendingRefund(commitmentDigest); err != nil { + t.logger.Error("failed to drop pending refund", "error", err) + } + t.logger.Info("dropped pending refund", "commitmentDigest", commitmentDigest) + } + return nil } From f102a7a6f6dc9e7e2b8e9df88f31969fc1a51699 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:20:14 -0700 Subject: [PATCH 02/17] Update deposit.go --- p2p/pkg/depositmanager/deposit.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/p2p/pkg/depositmanager/deposit.go b/p2p/pkg/depositmanager/deposit.go index 30c32a533..877116c99 100644 --- a/p2p/pkg/depositmanager/deposit.go +++ b/p2p/pkg/depositmanager/deposit.go @@ -58,7 +58,8 @@ func NewDepositManager( ) *DepositManager { pendingRefunds, err := lru.New[CommitmentDigest, pendingRefund](1000) if err != nil { - panic(err) + logger.Error("failed to create pending refunds cache", "error", err) + pendingRefunds = nil } return &DepositManager{ store: store, From fccbd9fe6383ab975f49dd9ce9c8e50dea08f5b1 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:37:59 -0700 Subject: [PATCH 03/17] TestPendingRefunds --- p2p/pkg/depositmanager/deposit.go | 22 +++--- p2p/pkg/depositmanager/deposit_test.go | 92 ++++++++++++++++++++++++++ p2p/pkg/depositmanager/export_test.go | 5 ++ 3 files changed, 108 insertions(+), 11 deletions(-) create mode 100644 p2p/pkg/depositmanager/export_test.go diff --git a/p2p/pkg/depositmanager/deposit.go b/p2p/pkg/depositmanager/deposit.go index 877116c99..087f37462 100644 --- a/p2p/pkg/depositmanager/deposit.go +++ b/p2p/pkg/depositmanager/deposit.go @@ -28,10 +28,10 @@ type Store interface { RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error } -type pendingRefund struct { - bidder common.Address - provider common.Address - amount *big.Int +type PendingRefund struct { + Bidder common.Address + Provider common.Address + Amount *big.Int } type CommitmentDigest [32]byte @@ -45,7 +45,7 @@ type DepositManager struct { withdrawals chan *bidderregistry.BidderregistryBidderWithdrawal thisProviderAddress common.Address logger *slog.Logger - pendingRefunds *lru.Cache[CommitmentDigest, pendingRefund] + pendingRefunds *lru.Cache[CommitmentDigest, PendingRefund] pendingRefundsMu sync.RWMutex } @@ -56,7 +56,7 @@ func NewDepositManager( thisProviderAddress common.Address, logger *slog.Logger, ) *DepositManager { - pendingRefunds, err := lru.New[CommitmentDigest, pendingRefund](1000) + pendingRefunds, err := lru.New[CommitmentDigest, PendingRefund](1000) if err != nil { logger.Error("failed to create pending refunds cache", "error", err) pendingRefunds = nil @@ -315,10 +315,10 @@ func (dm *DepositManager) AddPendingRefund( ) { dm.pendingRefundsMu.Lock() defer dm.pendingRefundsMu.Unlock() - evicted := dm.pendingRefunds.Add(commitmentDigest, pendingRefund{ - bidder: bidder, - provider: provider, - amount: amount, + evicted := dm.pendingRefunds.Add(commitmentDigest, PendingRefund{ + Bidder: bidder, + Provider: provider, + Amount: amount, }) if evicted { dm.logger.Warn("evicted pending refund. Tracker may not be working properly", "commitmentDigest", commitmentDigest) @@ -339,7 +339,7 @@ func (dm *DepositManager) ApplyPendingRefund( if !removed { return status.Errorf(codes.Internal, "failed to remove pending refund from cache") } - return dm.store.RefundBalanceIfExists(pendingRefund.bidder, pendingRefund.provider, pendingRefund.amount) + return dm.store.RefundBalanceIfExists(pendingRefund.Bidder, pendingRefund.Provider, pendingRefund.Amount) } func (dm *DepositManager) DropPendingRefund( diff --git a/p2p/pkg/depositmanager/deposit_test.go b/p2p/pkg/depositmanager/deposit_test.go index ca592044a..90c751e3c 100644 --- a/p2p/pkg/depositmanager/deposit_test.go +++ b/p2p/pkg/depositmanager/deposit_test.go @@ -489,3 +489,95 @@ func publishBidderWithdrawal( return nil } + +func TestPendingRefunds(t *testing.T) { + t.Parallel() + + logger := util.NewTestLogger(io.Discard) + st := depositstore.New(inmemstorage.New()) + dm := depositmanager.NewDepositManager(st, nil, nil, logger) + + digest1 := depositmanager.CommitmentDigest{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + } + + pendingRefund, ok := dm.GetPendingRefund(digest1) + if ok { + t.Fatal("expected no pending refunds") + } + if pendingRefund != (depositmanager.PendingRefund{}) { + t.Fatal("expected zeroed pending refund") + } + + dm.AddPendingRefund(digest1, common.HexToAddress("0x123"), common.HexToAddress("0x456"), big.NewInt(100)) + + pendingRefund, ok = dm.GetPendingRefund(digest1) + if !ok { + t.Fatal("expected pending refund") + } + if pendingRefund.Bidder != common.HexToAddress("0x123") { + t.Fatal("expected bidder 0x123") + } + if pendingRefund.Provider != common.HexToAddress("0x456") { + t.Fatal("expected provider 0x456") + } + if pendingRefund.Amount.Cmp(big.NewInt(100)) != 0 { + t.Fatal("expected amount 100") + } + + err := st.SetBalance(common.HexToAddress("0x123"), common.HexToAddress("0x456"), big.NewInt(77)) + if err != nil { + t.Fatal(err) + } + + balance, err := st.GetBalance(common.HexToAddress("0x123"), common.HexToAddress("0x456")) + if err != nil { + t.Fatal(err) + } + if balance.Cmp(big.NewInt(77)) != 0 { + t.Fatal("expected balance 77") + } + + err = dm.ApplyPendingRefund(digest1) + if err != nil { + t.Fatal(err) + } + + balance, err = st.GetBalance(common.HexToAddress("0x123"), common.HexToAddress("0x456")) + if err != nil { + t.Fatal(err) + } + if balance.Cmp(big.NewInt(177)) != 0 { + t.Fatal("expected balance 177") + } + + digest2 := depositmanager.CommitmentDigest{ + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + } + + dm.AddPendingRefund(digest2, common.HexToAddress("0x123"), common.HexToAddress("0x456"), big.NewInt(302)) + + pendingRefund, ok = dm.GetPendingRefund(digest2) + if !ok { + t.Fatal("expected pending refund") + } + if pendingRefund.Bidder != common.HexToAddress("0x123") { + t.Fatal("expected bidder 0x123") + } + if pendingRefund.Provider != common.HexToAddress("0x456") { + t.Fatal("expected provider 0x456") + } + if pendingRefund.Amount.Cmp(big.NewInt(302)) != 0 { + t.Fatal("expected amount 302") + } + + err = dm.DropPendingRefund(digest2) + if err != nil { + t.Fatal(err) + } + + pendingRefund, ok = dm.GetPendingRefund(digest2) + if ok { + t.Fatal("expected no pending refund") + } +} diff --git a/p2p/pkg/depositmanager/export_test.go b/p2p/pkg/depositmanager/export_test.go new file mode 100644 index 000000000..64fadad00 --- /dev/null +++ b/p2p/pkg/depositmanager/export_test.go @@ -0,0 +1,5 @@ +package depositmanager + +func (d *DepositManager) GetPendingRefund(commitmentDigest CommitmentDigest) (PendingRefund, bool) { + return d.pendingRefunds.Get(commitmentDigest) +} From c79a9698c557e5585f002345c69f1c8f442e7497 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Fri, 29 Aug 2025 16:43:50 -0700 Subject: [PATCH 04/17] fix: changes w.r.t discussion --- p2p/pkg/depositmanager/deposit.go | 103 +++------------ p2p/pkg/depositmanager/deposit_test.go | 118 ++---------------- p2p/pkg/depositmanager/export_test.go | 5 - p2p/pkg/depositmanager/store/store.go | 27 +++- p2p/pkg/depositmanager/store/store_test.go | 49 +++++++- p2p/pkg/node/node.go | 13 +- p2p/pkg/preconfirmation/preconfirmation.go | 47 ++----- .../preconfirmation/preconfirmation_test.go | 17 +-- p2p/pkg/preconfirmation/store/store.go | 10 +- p2p/pkg/preconfirmation/tracker/tracker.go | 70 ++++++++--- 10 files changed, 168 insertions(+), 291 deletions(-) delete mode 100644 p2p/pkg/depositmanager/export_test.go diff --git a/p2p/pkg/depositmanager/deposit.go b/p2p/pkg/depositmanager/deposit.go index 087f37462..75831c53c 100644 --- a/p2p/pkg/depositmanager/deposit.go +++ b/p2p/pkg/depositmanager/deposit.go @@ -5,11 +5,9 @@ import ( "fmt" "log/slog" "math/big" - "sync" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - lru "github.com/hashicorp/golang-lru/v2" bidderregistry "github.com/primev/mev-commit/contracts-abi/clients/BidderRegistry" "github.com/primev/mev-commit/x/contracts/events" "golang.org/x/sync/errgroup" @@ -25,17 +23,10 @@ type Store interface { GetBalance(bidder common.Address, provider common.Address) (*big.Int, error) SetBalance(bidder common.Address, provider common.Address, balance *big.Int) error DeleteBalance(bidder common.Address, provider common.Address) error - RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error + IncreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error + DecreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error } -type PendingRefund struct { - Bidder common.Address - Provider common.Address - Amount *big.Int -} - -type CommitmentDigest [32]byte - type DepositManager struct { store Store evtMgr events.EventManager @@ -45,8 +36,6 @@ type DepositManager struct { withdrawals chan *bidderregistry.BidderregistryBidderWithdrawal thisProviderAddress common.Address logger *slog.Logger - pendingRefunds *lru.Cache[CommitmentDigest, PendingRefund] - pendingRefundsMu sync.RWMutex } func NewDepositManager( @@ -56,11 +45,6 @@ func NewDepositManager( thisProviderAddress common.Address, logger *slog.Logger, ) *DepositManager { - pendingRefunds, err := lru.New[CommitmentDigest, PendingRefund](1000) - if err != nil { - logger.Error("failed to create pending refunds cache", "error", err) - pendingRefunds = nil - } return &DepositManager{ store: store, bidderRegistry: bidderRegistry, @@ -70,7 +54,6 @@ func NewDepositManager( evtMgr: evtMgr, thisProviderAddress: thisProviderAddress, logger: logger, - pendingRefunds: pendingRefunds, } } @@ -209,38 +192,31 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { return doneChan } -func (dm *DepositManager) CheckAndDeductDeposit( +func (dm *DepositManager) CheckDeposit( ctx context.Context, bidderAddr common.Address, providerAddr common.Address, bidAmountStr string, -) (func() error, error) { +) error { bidAmount, ok := new(big.Int).SetString(bidAmountStr, 10) if !ok { dm.logger.Error("parsing bid amount", "amount", bidAmountStr) - return nil, status.Errorf(codes.InvalidArgument, "failed to parse bid amount") + return status.Errorf(codes.InvalidArgument, "failed to parse bid amount") } balance, err := dm.store.GetBalance(bidderAddr, providerAddr) if err != nil { dm.logger.Error("getting balance", "error", err) - return nil, status.Errorf(codes.Internal, "failed to get balance: %v", err) + return status.Errorf(codes.Internal, "failed to get balance: %v", err) } if balance != nil { newBalance := new(big.Int).Sub(balance, bidAmount) if newBalance.Cmp(big.NewInt(0)) < 0 { dm.logger.Error("insufficient balance", "balance", balance.Uint64(), "bidAmount", bidAmount.Uint64()) - return nil, status.Errorf(codes.FailedPrecondition, "insufficient balance") + return status.Errorf(codes.FailedPrecondition, "insufficient balance") } - - if err := dm.store.SetBalance(bidderAddr, providerAddr, newBalance); err != nil { - dm.logger.Error("setting balance", "error", err) - return nil, status.Errorf(codes.Internal, "failed to set balance: %v", err) - } - return func() error { - return dm.store.RefundBalanceIfExists(bidderAddr, providerAddr, bidAmount) - }, nil + return nil } dm.logger.Info("balance not found in store, defaulting to contract call", "bidder", bidderAddr.Hex(), @@ -249,29 +225,21 @@ func (dm *DepositManager) CheckAndDeductDeposit( defaultBalance, err := dm.getDefaultBalance(ctx, bidderAddr, providerAddr, nil) // nil for latest block if err != nil { - return nil, err + return err } if defaultBalance == nil { dm.logger.Error("bidder balance not found", "bidder", bidderAddr.Hex(), "provider", providerAddr.Hex()) - return nil, status.Errorf(codes.FailedPrecondition, + return status.Errorf(codes.FailedPrecondition, "balance not found for bidder %s and provider %s", bidderAddr.Hex(), providerAddr.Hex()) } if defaultBalance.Cmp(bidAmount) < 0 { dm.logger.Error("insufficient balance", "balance", defaultBalance, "bidAmount", bidAmount) - return nil, status.Errorf(codes.FailedPrecondition, "insufficient balance") + return status.Errorf(codes.FailedPrecondition, "insufficient balance") } - newBalance := new(big.Int).Sub(defaultBalance, bidAmount) - if err := dm.store.SetBalance(bidderAddr, providerAddr, newBalance); err != nil { - dm.logger.Error("setting balance for block", "error", err) - return nil, status.Errorf(codes.Internal, "failed to set balance for block: %v", err) - } - - return func() error { - return dm.store.RefundBalanceIfExists(bidderAddr, providerAddr, bidAmount) - }, nil + return nil } // fallback to contract if balance not found in store @@ -307,49 +275,10 @@ func (dm *DepositManager) getDefaultBalance( return balance, nil } -func (dm *DepositManager) AddPendingRefund( - commitmentDigest CommitmentDigest, - bidder common.Address, - provider common.Address, - amount *big.Int, -) { - dm.pendingRefundsMu.Lock() - defer dm.pendingRefundsMu.Unlock() - evicted := dm.pendingRefunds.Add(commitmentDigest, PendingRefund{ - Bidder: bidder, - Provider: provider, - Amount: amount, - }) - if evicted { - dm.logger.Warn("evicted pending refund. Tracker may not be working properly", "commitmentDigest", commitmentDigest) - } -} - -func (dm *DepositManager) ApplyPendingRefund( - commitmentDigest CommitmentDigest, -) error { - dm.pendingRefundsMu.Lock() - defer dm.pendingRefundsMu.Unlock() - - pendingRefund, ok := dm.pendingRefunds.Get(commitmentDigest) - if !ok { - return status.Errorf(codes.NotFound, "pending refund not found for commitment digest %x", commitmentDigest) - } - removed := dm.pendingRefunds.Remove(commitmentDigest) - if !removed { - return status.Errorf(codes.Internal, "failed to remove pending refund from cache") - } - return dm.store.RefundBalanceIfExists(pendingRefund.Bidder, pendingRefund.Provider, pendingRefund.Amount) +func (dm *DepositManager) IncreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error { + return dm.store.IncreaseBalanceIfExists(bidder, provider, amount) } -func (dm *DepositManager) DropPendingRefund( - commitmentDigest CommitmentDigest, -) error { - dm.pendingRefundsMu.Lock() - defer dm.pendingRefundsMu.Unlock() - removed := dm.pendingRefunds.Remove(commitmentDigest) - if !removed { - return status.Errorf(codes.Internal, "failed to remove pending refund from cache") - } - return nil +func (dm *DepositManager) DecreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error { + return dm.store.DecreaseBalanceIfExists(bidder, provider, amount) } diff --git a/p2p/pkg/depositmanager/deposit_test.go b/p2p/pkg/depositmanager/deposit_test.go index 90c751e3c..827020042 100644 --- a/p2p/pkg/depositmanager/deposit_test.go +++ b/p2p/pkg/depositmanager/deposit_test.go @@ -70,7 +70,7 @@ func TestDepositManager(t *testing.T) { done := dm.Start(ctx) // no deposit - refund, err := dm.CheckAndDeductDeposit( + err = dm.CheckDeposit( context.Background(), common.HexToAddress("0x123"), common.HexToAddress("0x456"), @@ -79,9 +79,6 @@ func TestDepositManager(t *testing.T) { if err == nil { t.Fatal("expected error") } - if refund != nil { - t.Fatal("expected nil refund") - } br := &bidderregistry.BidderregistryBidderDeposited{ Bidder: common.HexToAddress("0x123"), @@ -105,8 +102,7 @@ func TestDepositManager(t *testing.T) { time.Sleep(1 * time.Second) } - // deduct deposit - refund, err = dm.CheckAndDeductDeposit( + err = dm.CheckDeposit( context.Background(), common.HexToAddress("0x123"), common.HexToAddress("0x456"), @@ -116,24 +112,18 @@ func TestDepositManager(t *testing.T) { t.Fatal(err) } - // not enough deposit - _, err = dm.CheckAndDeductDeposit( + // not enough deposit to handle 101 + err = dm.CheckDeposit( context.Background(), common.HexToAddress("0x123"), common.HexToAddress("0x456"), - "10", + "101", ) if err == nil || !strings.Contains(err.Error(), "insufficient balance") { t.Fatal("expected error for insufficient balance") } - err = refund() - if err != nil { - t.Fatal(err) - } - - // deduct deposit after refund - _, err = dm.CheckAndDeductDeposit( + err = dm.CheckDeposit( context.Background(), common.HexToAddress("0x123"), common.HexToAddress("0x456"), @@ -150,8 +140,8 @@ func TestDepositManager(t *testing.T) { if err != nil { t.Fatal(err) } - if balance == nil || balance.Cmp(big.NewInt(90)) != 0 { - t.Fatal("expected balance of 90") + if balance == nil || balance.Cmp(big.NewInt(100)) != 0 { + t.Fatal("expected balance of 100") } err = publishBidderWithdrawalRequested(evtMgr, &brABI, &bidderregistry.BidderregistryWithdrawalRequested{ @@ -489,95 +479,3 @@ func publishBidderWithdrawal( return nil } - -func TestPendingRefunds(t *testing.T) { - t.Parallel() - - logger := util.NewTestLogger(io.Discard) - st := depositstore.New(inmemstorage.New()) - dm := depositmanager.NewDepositManager(st, nil, nil, logger) - - digest1 := depositmanager.CommitmentDigest{ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - } - - pendingRefund, ok := dm.GetPendingRefund(digest1) - if ok { - t.Fatal("expected no pending refunds") - } - if pendingRefund != (depositmanager.PendingRefund{}) { - t.Fatal("expected zeroed pending refund") - } - - dm.AddPendingRefund(digest1, common.HexToAddress("0x123"), common.HexToAddress("0x456"), big.NewInt(100)) - - pendingRefund, ok = dm.GetPendingRefund(digest1) - if !ok { - t.Fatal("expected pending refund") - } - if pendingRefund.Bidder != common.HexToAddress("0x123") { - t.Fatal("expected bidder 0x123") - } - if pendingRefund.Provider != common.HexToAddress("0x456") { - t.Fatal("expected provider 0x456") - } - if pendingRefund.Amount.Cmp(big.NewInt(100)) != 0 { - t.Fatal("expected amount 100") - } - - err := st.SetBalance(common.HexToAddress("0x123"), common.HexToAddress("0x456"), big.NewInt(77)) - if err != nil { - t.Fatal(err) - } - - balance, err := st.GetBalance(common.HexToAddress("0x123"), common.HexToAddress("0x456")) - if err != nil { - t.Fatal(err) - } - if balance.Cmp(big.NewInt(77)) != 0 { - t.Fatal("expected balance 77") - } - - err = dm.ApplyPendingRefund(digest1) - if err != nil { - t.Fatal(err) - } - - balance, err = st.GetBalance(common.HexToAddress("0x123"), common.HexToAddress("0x456")) - if err != nil { - t.Fatal(err) - } - if balance.Cmp(big.NewInt(177)) != 0 { - t.Fatal("expected balance 177") - } - - digest2 := depositmanager.CommitmentDigest{ - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - } - - dm.AddPendingRefund(digest2, common.HexToAddress("0x123"), common.HexToAddress("0x456"), big.NewInt(302)) - - pendingRefund, ok = dm.GetPendingRefund(digest2) - if !ok { - t.Fatal("expected pending refund") - } - if pendingRefund.Bidder != common.HexToAddress("0x123") { - t.Fatal("expected bidder 0x123") - } - if pendingRefund.Provider != common.HexToAddress("0x456") { - t.Fatal("expected provider 0x456") - } - if pendingRefund.Amount.Cmp(big.NewInt(302)) != 0 { - t.Fatal("expected amount 302") - } - - err = dm.DropPendingRefund(digest2) - if err != nil { - t.Fatal(err) - } - - pendingRefund, ok = dm.GetPendingRefund(digest2) - if ok { - t.Fatal("expected no pending refund") - } -} diff --git a/p2p/pkg/depositmanager/export_test.go b/p2p/pkg/depositmanager/export_test.go deleted file mode 100644 index 64fadad00..000000000 --- a/p2p/pkg/depositmanager/export_test.go +++ /dev/null @@ -1,5 +0,0 @@ -package depositmanager - -func (d *DepositManager) GetPendingRefund(commitmentDigest CommitmentDigest) (PendingRefund, bool) { - return d.pendingRefunds.Get(commitmentDigest) -} diff --git a/p2p/pkg/depositmanager/store/store.go b/p2p/pkg/depositmanager/store/store.go index a5de60770..d49eca4d2 100644 --- a/p2p/pkg/depositmanager/store/store.go +++ b/p2p/pkg/depositmanager/store/store.go @@ -64,7 +64,7 @@ func (s *Store) DeleteBalance(bidder common.Address, provider common.Address) er return s.st.Delete(balanceKey(bidder, provider)) } -func (s *Store) RefundBalanceIfExists( +func (s *Store) IncreaseBalanceIfExists( bidder common.Address, provider common.Address, amount *big.Int, @@ -75,7 +75,7 @@ func (s *Store) RefundBalanceIfExists( val, err := s.st.Get(balanceKey(bidder, provider)) switch { case errors.Is(err, storage.ErrKeyNotFound): - return status.Errorf(codes.FailedPrecondition, "balance not found, no refund needed") + return status.Errorf(codes.FailedPrecondition, "balance not found, no increase needed") case err != nil: return err } @@ -84,6 +84,29 @@ func (s *Store) RefundBalanceIfExists( return s.st.Put(balanceKey(bidder, provider), newAmount.Bytes()) } +func (s *Store) DecreaseBalanceIfExists( + bidder common.Address, + provider common.Address, + amount *big.Int, +) error { + s.mu.Lock() + defer s.mu.Unlock() + + val, err := s.st.Get(balanceKey(bidder, provider)) + switch { + case errors.Is(err, storage.ErrKeyNotFound): + return status.Errorf(codes.FailedPrecondition, "balance not found, no decrease needed") + case err != nil: + return err + } + + newBalance := new(big.Int).Sub(new(big.Int).SetBytes(val), amount) + if newBalance.Cmp(big.NewInt(0)) < 0 { + return status.Errorf(codes.Internal, "balance cannot be decreased below 0") + } + return s.st.Put(balanceKey(bidder, provider), newBalance.Bytes()) +} + func (s *Store) BalanceEntries(bidder common.Address) (int, error) { s.mu.RLock() defer s.mu.RUnlock() diff --git a/p2p/pkg/depositmanager/store/store_test.go b/p2p/pkg/depositmanager/store/store_test.go index 5c11c64b6..6da848c02 100644 --- a/p2p/pkg/depositmanager/store/store_test.go +++ b/p2p/pkg/depositmanager/store/store_test.go @@ -70,7 +70,7 @@ func TestStore_GetBalance_NoBalance(t *testing.T) { } } -func TestStore_RefundBalanceIfExists(t *testing.T) { +func TestStore_IncreaseBalanceIfExists(t *testing.T) { st := inmem.New() s := store.New(st) @@ -78,12 +78,12 @@ func TestStore_RefundBalanceIfExists(t *testing.T) { provider := common.HexToAddress("0x456") amount := big.NewInt(20) - err := s.RefundBalanceIfExists(bidder, provider, amount) + err := s.IncreaseBalanceIfExists(bidder, provider, amount) if err == nil { t.Fatal("expected error, got nil") } - if !strings.Contains(err.Error(), "balance not found, no refund needed") { - t.Fatalf("expected error containing 'balance not found, no refund needed', got %v", err) + if !strings.Contains(err.Error(), "balance not found, no increase needed") { + t.Fatalf("expected error containing 'balance not found, no increase needed', got %v", err) } err = s.SetBalance(bidder, provider, amount) @@ -91,8 +91,8 @@ func TestStore_RefundBalanceIfExists(t *testing.T) { t.Fatal(err) } - refundAmount := big.NewInt(5) - err = s.RefundBalanceIfExists(bidder, provider, refundAmount) + increaseAmount := big.NewInt(5) + err = s.IncreaseBalanceIfExists(bidder, provider, increaseAmount) if err != nil { t.Fatal(err) } @@ -107,6 +107,43 @@ func TestStore_RefundBalanceIfExists(t *testing.T) { } } +func TestStore_DecreaseBalanceIfExists(t *testing.T) { + st := inmem.New() + s := store.New(st) + + bidder := common.HexToAddress("0x123") + provider := common.HexToAddress("0x456") + initialBalance := big.NewInt(20) + + err := s.DecreaseBalanceIfExists(bidder, provider, big.NewInt(10)) + if err == nil { + t.Fatal("expected error, got nil") + } + if !strings.Contains(err.Error(), "balance not found, no decrease needed") { + t.Fatalf("expected error containing 'balance not found, no decrease needed', got %v", err) + } + + err = s.SetBalance(bidder, provider, initialBalance) + if err != nil { + t.Fatal(err) + } + + decreaseAmount := big.NewInt(5) + err = s.DecreaseBalanceIfExists(bidder, provider, decreaseAmount) + if err != nil { + t.Fatal(err) + } + + val, err := s.GetBalance(bidder, provider) + if err != nil { + t.Fatal(err) + } + expectedAmount := new(big.Int).SetUint64(15) + if val.Cmp(expectedAmount) != 0 { + t.Fatalf("expected %s, got %s", expectedAmount.String(), val.String()) + } +} + func TestStore_DeleteBalance(t *testing.T) { st := inmem.New() s := store.New(st) diff --git a/p2p/pkg/node/node.go b/p2p/pkg/node/node.go index 23e160161..766e741c0 100644 --- a/p2p/pkg/node/node.go +++ b/p2p/pkg/node/node.go @@ -39,7 +39,6 @@ import ( "github.com/primev/mev-commit/p2p/pkg/apiserver" "github.com/primev/mev-commit/p2p/pkg/crypto" "github.com/primev/mev-commit/p2p/pkg/depositmanager" - dm "github.com/primev/mev-commit/p2p/pkg/depositmanager" depositmanagerstore "github.com/primev/mev-commit/p2p/pkg/depositmanager/store" "github.com/primev/mev-commit/p2p/pkg/discovery" "github.com/primev/mev-commit/p2p/pkg/keyexchange" @@ -940,17 +939,7 @@ func (noOpBidProcessor) ProcessBid( type noOpDepositManager struct{} -func (noOpDepositManager) CheckAndDeductDeposit(_ context.Context, _ common.Address, _ common.Address, _ string) (func() error, error) { - return func() error { return nil }, nil -} - -func (noOpDepositManager) AddPendingRefund(_ dm.CommitmentDigest, _ common.Address, _ common.Address, _ *big.Int) { -} - -func (noOpDepositManager) ApplyPendingRefund(_ dm.CommitmentDigest) error { - return nil -} -func (noOpDepositManager) DropPendingRefund(_ dm.CommitmentDigest) error { +func (noOpDepositManager) CheckDeposit(_ context.Context, _ common.Address, _ common.Address, _ string) error { return nil } diff --git a/p2p/pkg/preconfirmation/preconfirmation.go b/p2p/pkg/preconfirmation/preconfirmation.go index aa0d79100..466ac23bd 100644 --- a/p2p/pkg/preconfirmation/preconfirmation.go +++ b/p2p/pkg/preconfirmation/preconfirmation.go @@ -15,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" - dm "github.com/primev/mev-commit/p2p/pkg/depositmanager" "github.com/primev/mev-commit/p2p/pkg/p2p" "github.com/primev/mev-commit/p2p/pkg/preconfirmation/store" providerapi "github.com/primev/mev-commit/p2p/pkg/rpc/provider" @@ -54,18 +53,12 @@ type BidProcessor interface { } type DepositManager interface { - CheckAndDeductDeposit( + CheckDeposit( ctx context.Context, bidderAddr common.Address, providerAddr common.Address, bidAmount string, - ) (func() error, error) - AddPendingRefund( - commitmentDigest dm.CommitmentDigest, - bidder common.Address, - provider common.Address, - amount *big.Int, - ) + ) error } type Tracker interface { @@ -285,6 +278,9 @@ func (p *Preconfirmation) handleBid( if err != nil { return err } + if bidderAddr == nil { + return status.Errorf(codes.Internal, "bidder address not provided") + } opts, err := p.optsGetter(ctx) if err != nil { @@ -292,25 +288,12 @@ func (p *Preconfirmation) handleBid( } providerAddr := opts.From - tryRefund, err := p.depositMgr.CheckAndDeductDeposit(ctx, *bidderAddr, providerAddr, bid.BidAmount) + err = p.depositMgr.CheckDeposit(ctx, *bidderAddr, providerAddr, bid.BidAmount) if err != nil { p.logger.Error("checking deposit", "error", err) return err } - // Setup defer for possible refund - successful := false - defer func() { - if !successful { - // Refund the deducted amount if the bid process did not succeed and deposit still exists in store. - // If deposit no longer exists, the bidder is in withdrawal process and refund is thrown away - refundErr := tryRefund() - if refundErr != nil { - p.logger.Error("refunding deposit", "error", refundErr) - } - } - }() - // try to get a decision within 30 seconds ctx, cancel := context.WithTimeout(ctx, p.providerTimeout) defer cancel() @@ -360,9 +343,16 @@ func (p *Preconfirmation) handleBid( return status.Errorf(codes.Internal, "failed to store commitments: %v", err) } + bidAmount, ok := new(big.Int).SetString(bid.BidAmount, 10) + if !ok { + return status.Errorf(codes.Internal, "failed to parse bid amount: %v", bid.BidAmount) + } + encryptedAndDecryptedPreconfirmation := &store.Commitment{ EncryptedPreConfirmation: encryptedPreConfirmation, PreConfirmation: preConfirmation, + BidderAddress: bidderAddr, + BidAmount: bidAmount, } if err := p.tracker.TrackCommitment(ctx, encryptedAndDecryptedPreconfirmation, txn); err != nil { @@ -370,17 +360,6 @@ func (p *Preconfirmation) handleBid( return status.Errorf(codes.Internal, "failed to track commitment: %v", err) } - // If we reach here, the bid was successful - successful = true - - // Add pending refund. Preconf tracker will handle applying or dropping it from here. - bidAmount, ok := new(big.Int).SetString(bid.BidAmount, 10) - if !ok { - p.logger.Error("failed to parse bid amount", "bidAmount", bid.BidAmount) - return status.Errorf(codes.Internal, "failed to parse bid amount: %v", bid.BidAmount) - } - p.depositMgr.AddPendingRefund(commitmentDigest, *bidderAddr, providerAddr, bidAmount) - return nil } } diff --git a/p2p/pkg/preconfirmation/preconfirmation_test.go b/p2p/pkg/preconfirmation/preconfirmation_test.go index da3095d9f..a0f7c7591 100644 --- a/p2p/pkg/preconfirmation/preconfirmation_test.go +++ b/p2p/pkg/preconfirmation/preconfirmation_test.go @@ -5,7 +5,6 @@ import ( "crypto/rand" "io" "log/slog" - "math/big" "os" "testing" "time" @@ -20,7 +19,6 @@ import ( preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" p2pcrypto "github.com/primev/mev-commit/p2p/pkg/crypto" - dm "github.com/primev/mev-commit/p2p/pkg/depositmanager" "github.com/primev/mev-commit/p2p/pkg/p2p" p2ptest "github.com/primev/mev-commit/p2p/pkg/p2p/testing" "github.com/primev/mev-commit/p2p/pkg/preconfirmation" @@ -113,22 +111,13 @@ func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { type testDepositManager struct{} -func (t *testDepositManager) CheckAndDeductDeposit( +func (t *testDepositManager) CheckDeposit( ctx context.Context, bidderAddr common.Address, providerAddr common.Address, bidAmountStr string, -) (func() error, error) { - return func() error { return nil }, nil -} - -func (t *testDepositManager) AddPendingRefund( - commitmentDigest dm.CommitmentDigest, - bidder common.Address, - provider common.Address, - amount *big.Int, -) { - +) error { + return nil } type testTracker struct{} diff --git a/p2p/pkg/preconfirmation/store/store.go b/p2p/pkg/preconfirmation/store/store.go index 03dd69c54..3107c9edf 100644 --- a/p2p/pkg/preconfirmation/store/store.go +++ b/p2p/pkg/preconfirmation/store/store.go @@ -84,10 +84,12 @@ const ( type Commitment struct { *preconfpb.EncryptedPreConfirmation *preconfpb.PreConfirmation - Status CommitmentStatus - Details string - Payment string - Refund string + Status CommitmentStatus + Details string + Payment string + Refund string + BidderAddress *common.Address + BidAmount *big.Int } type BlockWinner struct { diff --git a/p2p/pkg/preconfirmation/tracker/tracker.go b/p2p/pkg/preconfirmation/tracker/tracker.go index ec471ed05..4309c29f7 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker.go +++ b/p2p/pkg/preconfirmation/tracker/tracker.go @@ -20,7 +20,6 @@ import ( oracle "github.com/primev/mev-commit/contracts-abi/clients/Oracle" preconfcommstore "github.com/primev/mev-commit/contracts-abi/clients/PreconfManager" "github.com/primev/mev-commit/p2p/pkg/crypto" - dm "github.com/primev/mev-commit/p2p/pkg/depositmanager" "github.com/primev/mev-commit/p2p/pkg/notifications" "github.com/primev/mev-commit/p2p/pkg/p2p" "github.com/primev/mev-commit/p2p/pkg/preconfirmation/store" @@ -99,8 +98,8 @@ type Watcher interface { } type DepositManager interface { - ApplyPendingRefund(commitmentDigest dm.CommitmentDigest) error - DropPendingRefund(commitmentDigest dm.CommitmentDigest) error + IncreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error + DecreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error } func NewTracker( @@ -457,6 +456,12 @@ func (t *Tracker) statusUpdater( details = fmt.Sprintf("failed to store commitment: %s", r.Err) } else { status = store.CommitmentStatusStored + if t.depositMgr != nil { + // Try to decrease cached balance now that commitment was successfully stored + if err := t.tryDecreaseCachedBalance(task.commitment); err != nil { + t.logger.Error("failed to decrease cached balance", "error", err) + } + } } case store.CommitmentStatusOpened: if r.Err != nil { @@ -550,12 +555,10 @@ func (t *Tracker) openCommitments( "winner", newL1Block.Winner, ) if t.depositMgr != nil { - commitmentDigest := dm.CommitmentDigest{} - copy(commitmentDigest[:], commitment.Commitment[:]) - if err := t.depositMgr.ApplyPendingRefund(commitmentDigest); err != nil { - t.logger.Error("failed to apply pending refund", "error", err) + // This node isn't the winner, so try to refund relevant cached balance + if err := t.tryIncreaseCachedBalance(commitment); err != nil { + t.logger.Error("failed to refund cached balance", "error", err) } - t.logger.Info("applied pending refund", "commitmentDigest", commitmentDigest) } continue } @@ -721,15 +724,6 @@ func (t *Tracker) handleOpenedCommitmentStored( } } - if t.depositMgr != nil { - commitmentDigest := dm.CommitmentDigest{} - copy(commitmentDigest[:], cs.CommitmentDigest[:]) - if err := t.depositMgr.DropPendingRefund(commitmentDigest); err != nil { - t.logger.Error("failed to drop pending refund", "error", err) - } - t.logger.Info("dropped pending refund", "commitmentDigest", commitmentDigest) - } - return nil } @@ -805,3 +799,45 @@ func (t *Tracker) generateBidderProof( zeroInt, } } + +func (t *Tracker) tryIncreaseCachedBalance( + commitment *store.Commitment, +) error { + if commitment.BidderAddress == nil || commitment.ProviderAddress == nil || commitment.BidAmount == nil { + return fmt.Errorf("nil commitment fields") + } + if err := t.depositMgr.IncreaseBalanceIfExists( + *commitment.BidderAddress, + common.BytesToAddress(commitment.ProviderAddress), + commitment.BidAmount, + ); err != nil { + return fmt.Errorf("failed to increase balance: %w", err) + } + t.logger.Info("increased cached balance from commitment", + "bidder", commitment.BidderAddress, + "provider", common.BytesToAddress(commitment.ProviderAddress), + "amount", commitment.BidAmount, + ) + return nil +} + +func (t *Tracker) tryDecreaseCachedBalance( + commitment *store.Commitment, +) error { + if commitment.BidderAddress == nil || commitment.ProviderAddress == nil || commitment.BidAmount == nil { + return fmt.Errorf("nil commitment fields") + } + if err := t.depositMgr.DecreaseBalanceIfExists( + *commitment.BidderAddress, + common.BytesToAddress(commitment.ProviderAddress), + commitment.BidAmount, + ); err != nil { + return fmt.Errorf("failed to decrease balance: %w", err) + } + t.logger.Info("decreased cached balance from commitment", + "bidder", commitment.BidderAddress, + "provider", common.BytesToAddress(commitment.ProviderAddress), + "amount", commitment.BidAmount, + ) + return nil +} From 09e38401e582552a3d53645f368d85c465bf5c87 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:29:50 -0700 Subject: [PATCH 05/17] fix: durable progress store --- p2p/pkg/node/node.go | 19 ++---------- p2p/pkg/node/store.go | 52 +++++++++++++++++++++++++++++++ p2p/pkg/node/store_test.go | 63 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 p2p/pkg/node/store.go create mode 100644 p2p/pkg/node/store_test.go diff --git a/p2p/pkg/node/node.go b/p2p/pkg/node/node.go index 766e741c0..1b2679589 100644 --- a/p2p/pkg/node/node.go +++ b/p2p/pkg/node/node.go @@ -11,7 +11,6 @@ import ( "net" "net/http" "strings" - "sync/atomic" "time" "github.com/bufbuild/protovalidate-go" @@ -167,8 +166,6 @@ func NewNode(opts *Options) (*Node, error) { } } - progressstore := &progressStore{contractRPC: contractRPC} - chainID, err := contractRPC.ChainID(context.Background()) if err != nil { opts.Logger.Error("failed to get chain ID", "error", err) @@ -219,6 +216,8 @@ func NewNode(opts *Options) (*Node, error) { } nd.closers = append(nd.closers, store) + progressstore := NewDurableProgressStore(store, contractRPC) + contracts, err := getContractABIs(opts) if err != nil { opts.Logger.Error("failed to get contract ABIs", "error", err) @@ -983,20 +982,6 @@ func (f StartableFunc) Start(ctx context.Context) <-chan struct{} { return f(ctx) } -type progressStore struct { - contractRPC *ethclient.Client - lastBlock atomic.Uint64 -} - -func (p *progressStore) LastBlock() (uint64, error) { - return p.contractRPC.BlockNumber(context.Background()) -} - -func (p *progressStore) SetLastBlock(block uint64) error { - p.lastBlock.Store(block) - return nil -} - func setDefault(field *string, defaultValue string) { if *field == "" { *field = defaultValue diff --git a/p2p/pkg/node/store.go b/p2p/pkg/node/store.go new file mode 100644 index 000000000..e689d556b --- /dev/null +++ b/p2p/pkg/node/store.go @@ -0,0 +1,52 @@ +package node + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + + "github.com/primev/mev-commit/p2p/pkg/storage" +) + +const ( + progressNS = "p2progress/" + progressLastBlockKey = progressNS + "last_block" +) + +type DurableProgressStore struct { + contractRPC ContractRPC + kv storage.Storage +} + +type ContractRPC interface { + BlockNumber(ctx context.Context) (uint64, error) +} + +func NewDurableProgressStore(kv storage.Storage, contractRPC ContractRPC) *DurableProgressStore { + return &DurableProgressStore{ + contractRPC: contractRPC, + kv: kv, + } +} + +func (p *DurableProgressStore) LastBlock() (uint64, error) { + buf, err := p.kv.Get(progressLastBlockKey) + switch { + case err == nil: + if len(buf) != 8 { + return 0, fmt.Errorf("invalid %q length: got %d, want 8", progressLastBlockKey, len(buf)) + } + return binary.BigEndian.Uint64(buf), nil + case errors.Is(err, storage.ErrKeyNotFound): + return p.contractRPC.BlockNumber(context.Background()) + default: + return 0, err + } +} + +func (p *DurableProgressStore) SetLastBlock(block uint64) error { + var b [8]byte + binary.BigEndian.PutUint64(b[:], block) + return p.kv.Put(progressLastBlockKey, b[:]) +} diff --git a/p2p/pkg/node/store_test.go b/p2p/pkg/node/store_test.go new file mode 100644 index 000000000..376c0f7c3 --- /dev/null +++ b/p2p/pkg/node/store_test.go @@ -0,0 +1,63 @@ +package node + +import ( + "context" + "encoding/binary" + "testing" + + inmem "github.com/primev/mev-commit/p2p/pkg/storage/inmem" +) + +type mockContractRPC struct { + blockNumber uint64 +} + +func (m *mockContractRPC) BlockNumber(ctx context.Context) (uint64, error) { + return m.blockNumber, nil +} + +func TestDurableProgressStore_LastBlock_FallbackToRPCWhenUnset(t *testing.T) { + kv := inmem.New() + mockRPC := &mockContractRPC{blockNumber: 12345} + + ps := NewDurableProgressStore(kv, mockRPC) + + got, err := ps.LastBlock() + if err != nil { + t.Fatalf("LastBlock: %v", err) + } + if got != 12345 { + t.Fatalf("LastBlock fallback mismatch: got %d want %d", got, 12345) + } +} + +func TestDurableProgressStore_SetAndGet(t *testing.T) { + kv := inmem.New() + mockRPC := &mockContractRPC{blockNumber: 0} + + ps := NewDurableProgressStore(kv, mockRPC) + + want := uint64(9876543210) + if err := ps.SetLastBlock(want); err != nil { + t.Fatalf("SetLastBlock: %v", err) + } + + got, err := ps.LastBlock() + if err != nil { + t.Fatalf("LastBlock: %v", err) + } + if got != uint64(9876543210) { + t.Fatalf("LastBlock persisted mismatch: got %d want %d", got, want) + } + + raw, err := kv.Get(progressLastBlockKey) + if err != nil { + t.Fatalf("kv.Get: %v", err) + } + if len(raw) != 8 { + t.Fatalf("stored length mismatch: got %d want 8", len(raw)) + } + if binary.BigEndian.Uint64(raw) != uint64(9876543210) { + t.Fatalf("stored value mismatch: got %d want %d", binary.BigEndian.Uint64(raw), want) + } +} From 4efa3fcdb0544f4b29744ed4bcef938afefb44dc Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:33:24 -0700 Subject: [PATCH 06/17] Update tracker.go --- p2p/pkg/preconfirmation/tracker/tracker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/pkg/preconfirmation/tracker/tracker.go b/p2p/pkg/preconfirmation/tracker/tracker.go index 4309c29f7..9f6772dc2 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker.go +++ b/p2p/pkg/preconfirmation/tracker/tracker.go @@ -459,7 +459,7 @@ func (t *Tracker) statusUpdater( if t.depositMgr != nil { // Try to decrease cached balance now that commitment was successfully stored if err := t.tryDecreaseCachedBalance(task.commitment); err != nil { - t.logger.Error("failed to decrease cached balance", "error", err) + t.logger.Warn("failed to decrease cached balance. Bidder is likely withdrawing", "error", err) } } } @@ -557,7 +557,7 @@ func (t *Tracker) openCommitments( if t.depositMgr != nil { // This node isn't the winner, so try to refund relevant cached balance if err := t.tryIncreaseCachedBalance(commitment); err != nil { - t.logger.Error("failed to refund cached balance", "error", err) + t.logger.Warn("failed to refund cached balance. Bidder is likely withdrawing", "error", err) } } continue From 1b5c3ffb1681e0d3bfe942523fc1da5f8eb5f9f6 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 12:04:06 -0700 Subject: [PATCH 07/17] refund/deduct naming --- p2p/pkg/depositmanager/deposit.go | 12 +++++------ p2p/pkg/depositmanager/store/store.go | 4 ++-- p2p/pkg/depositmanager/store/store_test.go | 12 +++++------ p2p/pkg/preconfirmation/tracker/tracker.go | 24 +++++++++++----------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/p2p/pkg/depositmanager/deposit.go b/p2p/pkg/depositmanager/deposit.go index 75831c53c..998abae90 100644 --- a/p2p/pkg/depositmanager/deposit.go +++ b/p2p/pkg/depositmanager/deposit.go @@ -23,8 +23,8 @@ type Store interface { GetBalance(bidder common.Address, provider common.Address) (*big.Int, error) SetBalance(bidder common.Address, provider common.Address, balance *big.Int) error DeleteBalance(bidder common.Address, provider common.Address) error - IncreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error - DecreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error + RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error + DeductBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error } type DepositManager struct { @@ -275,10 +275,10 @@ func (dm *DepositManager) getDefaultBalance( return balance, nil } -func (dm *DepositManager) IncreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error { - return dm.store.IncreaseBalanceIfExists(bidder, provider, amount) +func (dm *DepositManager) RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error { + return dm.store.RefundBalanceIfExists(bidder, provider, amount) } -func (dm *DepositManager) DecreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error { - return dm.store.DecreaseBalanceIfExists(bidder, provider, amount) +func (dm *DepositManager) DeductBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error { + return dm.store.DeductBalanceIfExists(bidder, provider, amount) } diff --git a/p2p/pkg/depositmanager/store/store.go b/p2p/pkg/depositmanager/store/store.go index d49eca4d2..91eb31ccc 100644 --- a/p2p/pkg/depositmanager/store/store.go +++ b/p2p/pkg/depositmanager/store/store.go @@ -64,7 +64,7 @@ func (s *Store) DeleteBalance(bidder common.Address, provider common.Address) er return s.st.Delete(balanceKey(bidder, provider)) } -func (s *Store) IncreaseBalanceIfExists( +func (s *Store) RefundBalanceIfExists( bidder common.Address, provider common.Address, amount *big.Int, @@ -84,7 +84,7 @@ func (s *Store) IncreaseBalanceIfExists( return s.st.Put(balanceKey(bidder, provider), newAmount.Bytes()) } -func (s *Store) DecreaseBalanceIfExists( +func (s *Store) DeductBalanceIfExists( bidder common.Address, provider common.Address, amount *big.Int, diff --git a/p2p/pkg/depositmanager/store/store_test.go b/p2p/pkg/depositmanager/store/store_test.go index 6da848c02..40c3a7da3 100644 --- a/p2p/pkg/depositmanager/store/store_test.go +++ b/p2p/pkg/depositmanager/store/store_test.go @@ -70,7 +70,7 @@ func TestStore_GetBalance_NoBalance(t *testing.T) { } } -func TestStore_IncreaseBalanceIfExists(t *testing.T) { +func TestStore_RefundBalanceIfExists(t *testing.T) { st := inmem.New() s := store.New(st) @@ -78,7 +78,7 @@ func TestStore_IncreaseBalanceIfExists(t *testing.T) { provider := common.HexToAddress("0x456") amount := big.NewInt(20) - err := s.IncreaseBalanceIfExists(bidder, provider, amount) + err := s.RefundBalanceIfExists(bidder, provider, amount) if err == nil { t.Fatal("expected error, got nil") } @@ -92,7 +92,7 @@ func TestStore_IncreaseBalanceIfExists(t *testing.T) { } increaseAmount := big.NewInt(5) - err = s.IncreaseBalanceIfExists(bidder, provider, increaseAmount) + err = s.RefundBalanceIfExists(bidder, provider, increaseAmount) if err != nil { t.Fatal(err) } @@ -107,7 +107,7 @@ func TestStore_IncreaseBalanceIfExists(t *testing.T) { } } -func TestStore_DecreaseBalanceIfExists(t *testing.T) { +func TestStore_DeductBalanceIfExists(t *testing.T) { st := inmem.New() s := store.New(st) @@ -115,7 +115,7 @@ func TestStore_DecreaseBalanceIfExists(t *testing.T) { provider := common.HexToAddress("0x456") initialBalance := big.NewInt(20) - err := s.DecreaseBalanceIfExists(bidder, provider, big.NewInt(10)) + err := s.DeductBalanceIfExists(bidder, provider, big.NewInt(10)) if err == nil { t.Fatal("expected error, got nil") } @@ -129,7 +129,7 @@ func TestStore_DecreaseBalanceIfExists(t *testing.T) { } decreaseAmount := big.NewInt(5) - err = s.DecreaseBalanceIfExists(bidder, provider, decreaseAmount) + err = s.DeductBalanceIfExists(bidder, provider, decreaseAmount) if err != nil { t.Fatal(err) } diff --git a/p2p/pkg/preconfirmation/tracker/tracker.go b/p2p/pkg/preconfirmation/tracker/tracker.go index 9f6772dc2..3dd4cd61c 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker.go +++ b/p2p/pkg/preconfirmation/tracker/tracker.go @@ -98,8 +98,8 @@ type Watcher interface { } type DepositManager interface { - IncreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error - DecreaseBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error + RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error + DeductBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error } func NewTracker( @@ -457,9 +457,9 @@ func (t *Tracker) statusUpdater( } else { status = store.CommitmentStatusStored if t.depositMgr != nil { - // Try to decrease cached balance now that commitment was successfully stored - if err := t.tryDecreaseCachedBalance(task.commitment); err != nil { - t.logger.Warn("failed to decrease cached balance. Bidder is likely withdrawing", "error", err) + // Try to deduct cached balance now that commitment was successfully stored + if err := t.tryDeductCachedBalance(task.commitment); err != nil { + t.logger.Warn("failed to deduct cached balance. Bidder is likely withdrawing", "error", err) } } } @@ -556,7 +556,7 @@ func (t *Tracker) openCommitments( ) if t.depositMgr != nil { // This node isn't the winner, so try to refund relevant cached balance - if err := t.tryIncreaseCachedBalance(commitment); err != nil { + if err := t.tryRefundCachedBalance(commitment); err != nil { t.logger.Warn("failed to refund cached balance. Bidder is likely withdrawing", "error", err) } } @@ -800,20 +800,20 @@ func (t *Tracker) generateBidderProof( } } -func (t *Tracker) tryIncreaseCachedBalance( +func (t *Tracker) tryRefundCachedBalance( commitment *store.Commitment, ) error { if commitment.BidderAddress == nil || commitment.ProviderAddress == nil || commitment.BidAmount == nil { return fmt.Errorf("nil commitment fields") } - if err := t.depositMgr.IncreaseBalanceIfExists( + if err := t.depositMgr.RefundBalanceIfExists( *commitment.BidderAddress, common.BytesToAddress(commitment.ProviderAddress), commitment.BidAmount, ); err != nil { - return fmt.Errorf("failed to increase balance: %w", err) + return fmt.Errorf("failed to refund balance: %w", err) } - t.logger.Info("increased cached balance from commitment", + t.logger.Info("refunded cached balance from commitment", "bidder", commitment.BidderAddress, "provider", common.BytesToAddress(commitment.ProviderAddress), "amount", commitment.BidAmount, @@ -821,13 +821,13 @@ func (t *Tracker) tryIncreaseCachedBalance( return nil } -func (t *Tracker) tryDecreaseCachedBalance( +func (t *Tracker) tryDeductCachedBalance( commitment *store.Commitment, ) error { if commitment.BidderAddress == nil || commitment.ProviderAddress == nil || commitment.BidAmount == nil { return fmt.Errorf("nil commitment fields") } - if err := t.depositMgr.DecreaseBalanceIfExists( + if err := t.depositMgr.DeductBalanceIfExists( *commitment.BidderAddress, common.BytesToAddress(commitment.ProviderAddress), commitment.BidAmount, From 205768f42eba5e0bd86d0cf3dfff24dbd54f5fba Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:03:55 -0700 Subject: [PATCH 08/17] req changes --- p2p/pkg/depositmanager/deposit.go | 97 ++++++++++++++----- p2p/pkg/depositmanager/deposit_test.go | 37 ++++--- p2p/pkg/depositmanager/store/store.go | 23 ----- p2p/pkg/depositmanager/store/store_test.go | 37 ------- p2p/pkg/node/node.go | 9 +- p2p/pkg/notifications/notifications.go | 2 + p2p/pkg/preconfirmation/preconfirmation.go | 32 +++--- .../preconfirmation/preconfirmation_test.go | 7 +- p2p/pkg/preconfirmation/tracker/tracker.go | 76 +++------------ 9 files changed, 134 insertions(+), 186 deletions(-) diff --git a/p2p/pkg/depositmanager/deposit.go b/p2p/pkg/depositmanager/deposit.go index 998abae90..59971ed73 100644 --- a/p2p/pkg/depositmanager/deposit.go +++ b/p2p/pkg/depositmanager/deposit.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" bidderregistry "github.com/primev/mev-commit/contracts-abi/clients/BidderRegistry" + "github.com/primev/mev-commit/p2p/pkg/notifications" "github.com/primev/mev-commit/x/contracts/events" "golang.org/x/sync/errgroup" "google.golang.org/grpc/codes" @@ -24,12 +25,12 @@ type Store interface { SetBalance(bidder common.Address, provider common.Address, balance *big.Int) error DeleteBalance(bidder common.Address, provider common.Address) error RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error - DeductBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error } type DepositManager struct { store Store evtMgr events.EventManager + notifiee notifications.Notifiee bidderRegistry BidderRegistryContract deposits chan *bidderregistry.BidderregistryBidderDeposited withdrawRequests chan *bidderregistry.BidderregistryWithdrawalRequested @@ -41,12 +42,14 @@ type DepositManager struct { func NewDepositManager( store Store, evtMgr events.EventManager, + notifiee notifications.Notifiee, bidderRegistry BidderRegistryContract, thisProviderAddress common.Address, logger *slog.Logger, ) *DepositManager { return &DepositManager{ store: store, + notifiee: notifiee, bidderRegistry: bidderRegistry, deposits: make(chan *bidderregistry.BidderregistryBidderDeposited), withdrawRequests: make(chan *bidderregistry.BidderregistryWithdrawalRequested), @@ -62,6 +65,11 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { eg, egCtx := errgroup.WithContext(ctx) + notifCh := dm.notifiee.Subscribe( + notifications.TopicCommitmentStoreFailed, + notifications.TopicOtherProviderWonBlock, + ) + ev1 := events.NewEventHandler( "BidderDeposited", func(bidderDeposit *bidderregistry.BidderregistryBidderDeposited) { @@ -104,6 +112,11 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { eg.Go(func() error { defer sub.Unsubscribe() + defer func() { + unsubDone := dm.notifiee.Unsubscribe(notifCh) + <-unsubDone + }() + select { case <-egCtx.Done(): dm.logger.Info("event subscription context done") @@ -120,6 +133,34 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { dm.logger.Info("deposit manager context done") return nil + case n := <-notifCh: + topic := n.Topic() + if topic != notifications.TopicOtherProviderWonBlock && topic != notifications.TopicCommitmentStoreFailed { + dm.logger.Debug("ignoring notification for topic", "topic", topic) + continue + } + + val := n.Value() + bidderHex := val["bidder"].(string) + bidAmount := val["bidAmount"].(string) + + if bidderHex == "" || bidAmount == "" { + dm.logger.Error("bidder and bid amount are required to refund", "bidder", bidderHex, "bidAmount", bidAmount) + continue + } + bidder := common.HexToAddress(bidderHex) + bidAmountInt, ok := new(big.Int).SetString(bidAmount, 10) + if !ok { + dm.logger.Error("failed to parse bid amount", "bidAmount", bidAmount) + continue + } + + if err := dm.store.RefundBalanceIfExists(bidder, dm.thisProviderAddress, bidAmountInt); err != nil { + dm.logger.Error("refunding balance", "error", err) + return err + } + dm.logger.Info("refunded balance from notification", "bidder", bidder, "bidAmount", bidAmountInt) + case deposit := <-dm.deposits: if deposit.Provider != dm.thisProviderAddress { dm.logger.Debug("ignoring deposit event for different provider", "provider", deposit.Provider) @@ -192,54 +233,68 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { return doneChan } -func (dm *DepositManager) CheckDeposit( +func (dm *DepositManager) CheckAndDeductDeposit( ctx context.Context, bidderAddr common.Address, - providerAddr common.Address, bidAmountStr string, -) error { +) (func() error, error) { bidAmount, ok := new(big.Int).SetString(bidAmountStr, 10) if !ok { dm.logger.Error("parsing bid amount", "amount", bidAmountStr) - return status.Errorf(codes.InvalidArgument, "failed to parse bid amount") + return nil, status.Errorf(codes.InvalidArgument, "failed to parse bid amount") } - balance, err := dm.store.GetBalance(bidderAddr, providerAddr) + balance, err := dm.store.GetBalance(bidderAddr, dm.thisProviderAddress) if err != nil { dm.logger.Error("getting balance", "error", err) - return status.Errorf(codes.Internal, "failed to get balance: %v", err) + return nil, status.Errorf(codes.Internal, "failed to get balance: %v", err) } if balance != nil { newBalance := new(big.Int).Sub(balance, bidAmount) if newBalance.Cmp(big.NewInt(0)) < 0 { dm.logger.Error("insufficient balance", "balance", balance.Uint64(), "bidAmount", bidAmount.Uint64()) - return status.Errorf(codes.FailedPrecondition, "insufficient balance") + return nil, status.Errorf(codes.FailedPrecondition, "insufficient balance") + } + + if err := dm.store.SetBalance(bidderAddr, dm.thisProviderAddress, newBalance); err != nil { + dm.logger.Error("setting balance", "error", err) + return nil, status.Errorf(codes.Internal, "failed to set balance: %v", err) } - return nil + return func() error { + return dm.store.RefundBalanceIfExists(bidderAddr, dm.thisProviderAddress, bidAmount) + }, nil } dm.logger.Info("balance not found in store, defaulting to contract call", "bidder", bidderAddr.Hex(), - "provider", providerAddr.Hex(), + "provider", dm.thisProviderAddress.Hex(), ) - defaultBalance, err := dm.getDefaultBalance(ctx, bidderAddr, providerAddr, nil) // nil for latest block + defaultBalance, err := dm.getDefaultBalance(ctx, bidderAddr, dm.thisProviderAddress, nil) // nil for latest block if err != nil { - return err + return nil, err } if defaultBalance == nil { - dm.logger.Error("bidder balance not found", "bidder", bidderAddr.Hex(), "provider", providerAddr.Hex()) - return status.Errorf(codes.FailedPrecondition, - "balance not found for bidder %s and provider %s", bidderAddr.Hex(), providerAddr.Hex()) + dm.logger.Error("bidder balance not found", "bidder", bidderAddr.Hex(), "provider", dm.thisProviderAddress.Hex()) + return nil, status.Errorf(codes.FailedPrecondition, + "balance not found for bidder %s and provider %s", bidderAddr.Hex(), dm.thisProviderAddress.Hex()) } if defaultBalance.Cmp(bidAmount) < 0 { dm.logger.Error("insufficient balance", "balance", defaultBalance, "bidAmount", bidAmount) - return status.Errorf(codes.FailedPrecondition, "insufficient balance") + return nil, status.Errorf(codes.FailedPrecondition, "insufficient balance") } - return nil + newBalance := new(big.Int).Sub(defaultBalance, bidAmount) + if err := dm.store.SetBalance(bidderAddr, dm.thisProviderAddress, newBalance); err != nil { + dm.logger.Error("setting balance for block", "error", err) + return nil, status.Errorf(codes.Internal, "failed to set balance for block: %v", err) + } + + return func() error { + return dm.store.RefundBalanceIfExists(bidderAddr, dm.thisProviderAddress, bidAmount) + }, nil } // fallback to contract if balance not found in store @@ -274,11 +329,3 @@ func (dm *DepositManager) getDefaultBalance( return balance, nil } - -func (dm *DepositManager) RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error { - return dm.store.RefundBalanceIfExists(bidder, provider, amount) -} - -func (dm *DepositManager) DeductBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error { - return dm.store.DeductBalanceIfExists(bidder, provider, amount) -} diff --git a/p2p/pkg/depositmanager/deposit_test.go b/p2p/pkg/depositmanager/deposit_test.go index 827020042..2bd6b6ac7 100644 --- a/p2p/pkg/depositmanager/deposit_test.go +++ b/p2p/pkg/depositmanager/deposit_test.go @@ -18,6 +18,7 @@ import ( blocktracker "github.com/primev/mev-commit/contracts-abi/clients/BlockTracker" "github.com/primev/mev-commit/p2p/pkg/depositmanager" depositstore "github.com/primev/mev-commit/p2p/pkg/depositmanager/store" + "github.com/primev/mev-commit/p2p/pkg/notifications" inmemstorage "github.com/primev/mev-commit/p2p/pkg/storage/inmem" "github.com/primev/mev-commit/x/contracts/events" "github.com/primev/mev-commit/x/util" @@ -66,19 +67,21 @@ func TestDepositManager(t *testing.T) { providerAddress := common.HexToAddress("0x456") - dm := depositmanager.NewDepositManager(st, evtMgr, bidderRegistry, providerAddress, logger) + dm := depositmanager.NewDepositManager(st, evtMgr, notifications.New(10), bidderRegistry, providerAddress, logger) done := dm.Start(ctx) // no deposit - err = dm.CheckDeposit( + refund, err := dm.CheckAndDeductDeposit( context.Background(), common.HexToAddress("0x123"), - common.HexToAddress("0x456"), "10", ) if err == nil { t.Fatal("expected error") } + if refund != nil { + t.Fatal("expected nil refund") + } br := &bidderregistry.BidderregistryBidderDeposited{ Bidder: common.HexToAddress("0x123"), @@ -102,31 +105,35 @@ func TestDepositManager(t *testing.T) { time.Sleep(1 * time.Second) } - err = dm.CheckDeposit( + // deduct deposit + refund, err = dm.CheckAndDeductDeposit( context.Background(), common.HexToAddress("0x123"), - common.HexToAddress("0x456"), "100", ) if err != nil { t.Fatal(err) } - // not enough deposit to handle 101 - err = dm.CheckDeposit( + // not enough deposit + _, err = dm.CheckAndDeductDeposit( context.Background(), common.HexToAddress("0x123"), - common.HexToAddress("0x456"), - "101", + "10", ) if err == nil || !strings.Contains(err.Error(), "insufficient balance") { t.Fatal("expected error for insufficient balance") } - err = dm.CheckDeposit( + err = refund() + if err != nil { + t.Fatal(err) + } + + // deduct deposit after refund + _, err = dm.CheckAndDeductDeposit( context.Background(), common.HexToAddress("0x123"), - common.HexToAddress("0x456"), "10", ) if err != nil { @@ -140,8 +147,8 @@ func TestDepositManager(t *testing.T) { if err != nil { t.Fatal(err) } - if balance == nil || balance.Cmp(big.NewInt(100)) != 0 { - t.Fatal("expected balance of 100") + if balance == nil || balance.Cmp(big.NewInt(90)) != 0 { + t.Fatal("expected balance of 90") } err = publishBidderWithdrawalRequested(evtMgr, &brABI, &bidderregistry.BidderregistryWithdrawalRequested{ @@ -244,7 +251,7 @@ func TestStartWithBidderAlreadyDeposited(t *testing.T) { providerAddress := common.HexToAddress("0x456") - dm := depositmanager.NewDepositManager(st, evtMgr, bidderRegistry, providerAddress, logger) + dm := depositmanager.NewDepositManager(st, evtMgr, notifications.New(10), bidderRegistry, providerAddress, logger) done := dm.Start(ctx) err = publishBidderDeposited(evtMgr, &brABI, &bidderregistry.BidderregistryBidderDeposited{ @@ -306,7 +313,7 @@ func TestOtherProvidersEventsAreIgnored(t *testing.T) { providerAddress := common.HexToAddress("0x456") - dm := depositmanager.NewDepositManager(st, evtMgr, bidderRegistry, providerAddress, logger) + dm := depositmanager.NewDepositManager(st, evtMgr, notifications.New(10), bidderRegistry, providerAddress, logger) done := dm.Start(ctx) differentProvider := common.HexToAddress("0x789") diff --git a/p2p/pkg/depositmanager/store/store.go b/p2p/pkg/depositmanager/store/store.go index 91eb31ccc..fb5ba6475 100644 --- a/p2p/pkg/depositmanager/store/store.go +++ b/p2p/pkg/depositmanager/store/store.go @@ -84,29 +84,6 @@ func (s *Store) RefundBalanceIfExists( return s.st.Put(balanceKey(bidder, provider), newAmount.Bytes()) } -func (s *Store) DeductBalanceIfExists( - bidder common.Address, - provider common.Address, - amount *big.Int, -) error { - s.mu.Lock() - defer s.mu.Unlock() - - val, err := s.st.Get(balanceKey(bidder, provider)) - switch { - case errors.Is(err, storage.ErrKeyNotFound): - return status.Errorf(codes.FailedPrecondition, "balance not found, no decrease needed") - case err != nil: - return err - } - - newBalance := new(big.Int).Sub(new(big.Int).SetBytes(val), amount) - if newBalance.Cmp(big.NewInt(0)) < 0 { - return status.Errorf(codes.Internal, "balance cannot be decreased below 0") - } - return s.st.Put(balanceKey(bidder, provider), newBalance.Bytes()) -} - func (s *Store) BalanceEntries(bidder common.Address) (int, error) { s.mu.RLock() defer s.mu.RUnlock() diff --git a/p2p/pkg/depositmanager/store/store_test.go b/p2p/pkg/depositmanager/store/store_test.go index 40c3a7da3..8ab6324fd 100644 --- a/p2p/pkg/depositmanager/store/store_test.go +++ b/p2p/pkg/depositmanager/store/store_test.go @@ -107,43 +107,6 @@ func TestStore_RefundBalanceIfExists(t *testing.T) { } } -func TestStore_DeductBalanceIfExists(t *testing.T) { - st := inmem.New() - s := store.New(st) - - bidder := common.HexToAddress("0x123") - provider := common.HexToAddress("0x456") - initialBalance := big.NewInt(20) - - err := s.DeductBalanceIfExists(bidder, provider, big.NewInt(10)) - if err == nil { - t.Fatal("expected error, got nil") - } - if !strings.Contains(err.Error(), "balance not found, no decrease needed") { - t.Fatalf("expected error containing 'balance not found, no decrease needed', got %v", err) - } - - err = s.SetBalance(bidder, provider, initialBalance) - if err != nil { - t.Fatal(err) - } - - decreaseAmount := big.NewInt(5) - err = s.DeductBalanceIfExists(bidder, provider, decreaseAmount) - if err != nil { - t.Fatal(err) - } - - val, err := s.GetBalance(bidder, provider) - if err != nil { - t.Fatal(err) - } - expectedAmount := new(big.Int).SetUint64(15) - if val.Cmp(expectedAmount) != 0 { - t.Fatalf("expected %s, got %s", expectedAmount.String(), val.String()) - } -} - func TestStore_DeleteBalance(t *testing.T) { st := inmem.New() s := store.New(st) diff --git a/p2p/pkg/node/node.go b/p2p/pkg/node/node.go index 1b2679589..a3cb0df43 100644 --- a/p2p/pkg/node/node.go +++ b/p2p/pkg/node/node.go @@ -567,15 +567,14 @@ func NewNode(opts *Options) (*Node, error) { providerapiv1.RegisterProviderServer(grpcServer, providerAPI) bidProcessor = providerAPI srv.RegisterMetricsCollectors(providerAPI.Metrics()...) - dmConcrete := depositmanager.NewDepositManager( + depositMgr = depositmanager.NewDepositManager( depositmanagerstore.New(store), evtMgr, + notificationsSvc, bidderRegistry, opts.KeySigner.GetAddress(), opts.Logger.With("component", "depositmanager"), ) - depositMgr = dmConcrete - tracker.SetDepositManager(dmConcrete) startables = append( startables, StartableObjWithDesc{ @@ -938,8 +937,8 @@ func (noOpBidProcessor) ProcessBid( type noOpDepositManager struct{} -func (noOpDepositManager) CheckDeposit(_ context.Context, _ common.Address, _ common.Address, _ string) error { - return nil +func (noOpDepositManager) CheckAndDeductDeposit(_ context.Context, _ common.Address, _ string) (func() error, error) { + return nil, nil } type channelCloser <-chan struct{} diff --git a/p2p/pkg/notifications/notifications.go b/p2p/pkg/notifications/notifications.go index 023be5c16..33ad22445 100644 --- a/p2p/pkg/notifications/notifications.go +++ b/p2p/pkg/notifications/notifications.go @@ -17,6 +17,7 @@ const ( TopicProviderDeregistered Topic = "provider_deregistered" TopicCommitmentStoreFailed Topic = "commitment_store_failed" TopicCommitmentOpenFailed Topic = "commitment_open_failed" + TopicOtherProviderWonBlock Topic = "other_provider_won_block" ) var validTopic = map[Topic]struct{}{ @@ -30,6 +31,7 @@ var validTopic = map[Topic]struct{}{ TopicProviderDeregistered: {}, TopicCommitmentStoreFailed: {}, TopicCommitmentOpenFailed: {}, + TopicOtherProviderWonBlock: {}, } func IsTopicValid(topic Topic) bool { diff --git a/p2p/pkg/preconfirmation/preconfirmation.go b/p2p/pkg/preconfirmation/preconfirmation.go index 466ac23bd..d6d1c2b21 100644 --- a/p2p/pkg/preconfirmation/preconfirmation.go +++ b/p2p/pkg/preconfirmation/preconfirmation.go @@ -53,12 +53,11 @@ type BidProcessor interface { } type DepositManager interface { - CheckDeposit( + CheckAndDeductDeposit( ctx context.Context, bidderAddr common.Address, - providerAddr common.Address, bidAmount string, - ) error + ) (func() error, error) } type Tracker interface { @@ -278,22 +277,26 @@ func (p *Preconfirmation) handleBid( if err != nil { return err } - if bidderAddr == nil { - return status.Errorf(codes.Internal, "bidder address not provided") - } - - opts, err := p.optsGetter(ctx) - if err != nil { - return err - } - providerAddr := opts.From - err = p.depositMgr.CheckDeposit(ctx, *bidderAddr, providerAddr, bid.BidAmount) + tryRefund, err := p.depositMgr.CheckAndDeductDeposit(ctx, *bidderAddr, bid.BidAmount) if err != nil { p.logger.Error("checking deposit", "error", err) return err } + // Setup defer for possible refund + successful := false + defer func() { + if !successful { + // Refund the deducted amount if the bid process did not succeed and deposit still exists in store. + // If deposit no longer exists, the bidder is in withdrawal process and refund is thrown away + refundErr := tryRefund() + if refundErr != nil { + p.logger.Error("refunding deposit", "error", refundErr) + } + } + }() + // try to get a decision within 30 seconds ctx, cancel := context.WithTimeout(ctx, p.providerTimeout) defer cancel() @@ -360,6 +363,9 @@ func (p *Preconfirmation) handleBid( return status.Errorf(codes.Internal, "failed to track commitment: %v", err) } + // If we reach here, the bid was successful + successful = true + return nil } } diff --git a/p2p/pkg/preconfirmation/preconfirmation_test.go b/p2p/pkg/preconfirmation/preconfirmation_test.go index a0f7c7591..4d3697b6b 100644 --- a/p2p/pkg/preconfirmation/preconfirmation_test.go +++ b/p2p/pkg/preconfirmation/preconfirmation_test.go @@ -111,13 +111,12 @@ func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { type testDepositManager struct{} -func (t *testDepositManager) CheckDeposit( +func (t *testDepositManager) CheckAndDeductDeposit( ctx context.Context, bidderAddr common.Address, - providerAddr common.Address, bidAmountStr string, -) error { - return nil +) (func() error, error) { + return nil, nil } type testTracker struct{} diff --git a/p2p/pkg/preconfirmation/tracker/tracker.go b/p2p/pkg/preconfirmation/tracker/tracker.go index 3dd4cd61c..e8d1a0008 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker.go +++ b/p2p/pkg/preconfirmation/tracker/tracker.go @@ -58,7 +58,6 @@ type Tracker struct { triggerOpen chan struct{} metrics *metrics logger *slog.Logger - depositMgr DepositManager // Nullable and only used by provider } type OptsGetter func(context.Context) (*bind.TransactOpts, error) @@ -97,11 +96,6 @@ type Watcher interface { WatchTx(txnHash common.Hash, nonce uint64) <-chan txmonitor.Result } -type DepositManager interface { - RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error - DeductBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error -} - func NewTracker( chainID *big.Int, peerType p2p.PeerType, @@ -142,10 +136,6 @@ func NewTracker( } } -func (t *Tracker) SetDepositManager(depositMgr DepositManager) { - t.depositMgr = depositMgr -} - func (t *Tracker) Start(ctx context.Context) <-chan struct{} { doneChan := make(chan struct{}) @@ -456,12 +446,6 @@ func (t *Tracker) statusUpdater( details = fmt.Sprintf("failed to store commitment: %s", r.Err) } else { status = store.CommitmentStatusStored - if t.depositMgr != nil { - // Try to deduct cached balance now that commitment was successfully stored - if err := t.tryDeductCachedBalance(task.commitment); err != nil { - t.logger.Warn("failed to deduct cached balance. Bidder is likely withdrawing", "error", err) - } - } } case store.CommitmentStatusOpened: if r.Err != nil { @@ -492,6 +476,8 @@ func (t *Tracker) statusUpdater( "commitmentDigest": hex.EncodeToString(task.commitment.Commitment[:]), "txnHash": task.commitment.Bid.TxHash, "error": r.Err.Error(), + "bidder": common.Bytes2Hex(task.commitment.BidderAddress[:]), + "bidAmount": task.commitment.BidAmount.String(), } switch task.onSuccess { case store.CommitmentStatusStored: @@ -554,12 +540,16 @@ func (t *Tracker) openCommitments( "providerAddress", commitment.ProviderAddress, "winner", newL1Block.Winner, ) - if t.depositMgr != nil { - // This node isn't the winner, so try to refund relevant cached balance - if err := t.tryRefundCachedBalance(commitment); err != nil { - t.logger.Warn("failed to refund cached balance. Bidder is likely withdrawing", "error", err) - } - } + t.notifier.Notify( + notifications.NewNotification( + notifications.TopicOtherProviderWonBlock, + map[string]any{ + "commitmentDigest": hex.EncodeToString(commitment.Commitment[:]), + "bidder": common.Bytes2Hex(commitment.BidderAddress[:]), + "bidAmount": commitment.BidAmount.String(), + }, + ), + ) continue } startTime := time.Now() @@ -799,45 +789,3 @@ func (t *Tracker) generateBidderProof( zeroInt, } } - -func (t *Tracker) tryRefundCachedBalance( - commitment *store.Commitment, -) error { - if commitment.BidderAddress == nil || commitment.ProviderAddress == nil || commitment.BidAmount == nil { - return fmt.Errorf("nil commitment fields") - } - if err := t.depositMgr.RefundBalanceIfExists( - *commitment.BidderAddress, - common.BytesToAddress(commitment.ProviderAddress), - commitment.BidAmount, - ); err != nil { - return fmt.Errorf("failed to refund balance: %w", err) - } - t.logger.Info("refunded cached balance from commitment", - "bidder", commitment.BidderAddress, - "provider", common.BytesToAddress(commitment.ProviderAddress), - "amount", commitment.BidAmount, - ) - return nil -} - -func (t *Tracker) tryDeductCachedBalance( - commitment *store.Commitment, -) error { - if commitment.BidderAddress == nil || commitment.ProviderAddress == nil || commitment.BidAmount == nil { - return fmt.Errorf("nil commitment fields") - } - if err := t.depositMgr.DeductBalanceIfExists( - *commitment.BidderAddress, - common.BytesToAddress(commitment.ProviderAddress), - commitment.BidAmount, - ); err != nil { - return fmt.Errorf("failed to decrease balance: %w", err) - } - t.logger.Info("decreased cached balance from commitment", - "bidder", commitment.BidderAddress, - "provider", common.BytesToAddress(commitment.ProviderAddress), - "amount", commitment.BidAmount, - ) - return nil -} From 60e868d7b483d5c5be4fdc963fb9fe4da92dbdf1 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:07:25 -0700 Subject: [PATCH 09/17] Update store.go --- p2p/pkg/depositmanager/store/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/pkg/depositmanager/store/store.go b/p2p/pkg/depositmanager/store/store.go index fb5ba6475..a5de60770 100644 --- a/p2p/pkg/depositmanager/store/store.go +++ b/p2p/pkg/depositmanager/store/store.go @@ -75,7 +75,7 @@ func (s *Store) RefundBalanceIfExists( val, err := s.st.Get(balanceKey(bidder, provider)) switch { case errors.Is(err, storage.ErrKeyNotFound): - return status.Errorf(codes.FailedPrecondition, "balance not found, no increase needed") + return status.Errorf(codes.FailedPrecondition, "balance not found, no refund needed") case err != nil: return err } From 4cd165b4533e73da5e638b3c9546c2284de8702d Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:08:22 -0700 Subject: [PATCH 10/17] Update store_test.go --- p2p/pkg/depositmanager/store/store_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/pkg/depositmanager/store/store_test.go b/p2p/pkg/depositmanager/store/store_test.go index 8ab6324fd..26f0e22e9 100644 --- a/p2p/pkg/depositmanager/store/store_test.go +++ b/p2p/pkg/depositmanager/store/store_test.go @@ -82,8 +82,8 @@ func TestStore_RefundBalanceIfExists(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - if !strings.Contains(err.Error(), "balance not found, no increase needed") { - t.Fatalf("expected error containing 'balance not found, no increase needed', got %v", err) + if !strings.Contains(err.Error(), "balance not found, no refund needed") { + t.Fatalf("expected error containing 'balance not found, no refund needed', got %v", err) } err = s.SetBalance(bidder, provider, amount) From 6ae6a43b5430266eb12762de3396fd981d6bad7e Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:09:31 -0700 Subject: [PATCH 11/17] Update node.go --- p2p/pkg/node/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/pkg/node/node.go b/p2p/pkg/node/node.go index a3cb0df43..2da591e6c 100644 --- a/p2p/pkg/node/node.go +++ b/p2p/pkg/node/node.go @@ -938,7 +938,7 @@ func (noOpBidProcessor) ProcessBid( type noOpDepositManager struct{} func (noOpDepositManager) CheckAndDeductDeposit(_ context.Context, _ common.Address, _ string) (func() error, error) { - return nil, nil + return func() error { return nil }, nil } type channelCloser <-chan struct{} From 7d5b6229bf6a77de6b485de41e79aa5a98b8de62 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:10:19 -0700 Subject: [PATCH 12/17] Update preconfirmation_test.go --- p2p/pkg/preconfirmation/preconfirmation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/pkg/preconfirmation/preconfirmation_test.go b/p2p/pkg/preconfirmation/preconfirmation_test.go index 4d3697b6b..c98c3094f 100644 --- a/p2p/pkg/preconfirmation/preconfirmation_test.go +++ b/p2p/pkg/preconfirmation/preconfirmation_test.go @@ -116,7 +116,7 @@ func (t *testDepositManager) CheckAndDeductDeposit( bidderAddr common.Address, bidAmountStr string, ) (func() error, error) { - return nil, nil + return func() error { return nil }, nil } type testTracker struct{} From 0a9a411fe73a865008af20d8068c93eb67921e10 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:30:13 -0700 Subject: [PATCH 13/17] fix: guard against nil BidderAddress and BidAmount --- p2p/pkg/preconfirmation/tracker/tracker.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/p2p/pkg/preconfirmation/tracker/tracker.go b/p2p/pkg/preconfirmation/tracker/tracker.go index e8d1a0008..81297ea73 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker.go +++ b/p2p/pkg/preconfirmation/tracker/tracker.go @@ -476,8 +476,12 @@ func (t *Tracker) statusUpdater( "commitmentDigest": hex.EncodeToString(task.commitment.Commitment[:]), "txnHash": task.commitment.Bid.TxHash, "error": r.Err.Error(), - "bidder": common.Bytes2Hex(task.commitment.BidderAddress[:]), - "bidAmount": task.commitment.BidAmount.String(), + } + if task.commitment.BidderAddress != nil { + notificationPayload["bidder"] = common.Bytes2Hex(task.commitment.BidderAddress[:]) + } + if task.commitment.BidAmount != nil { + notificationPayload["bidAmount"] = task.commitment.BidAmount.String() } switch task.onSuccess { case store.CommitmentStatusStored: @@ -540,6 +544,14 @@ func (t *Tracker) openCommitments( "providerAddress", commitment.ProviderAddress, "winner", newL1Block.Winner, ) + if commitment.BidderAddress == nil { + t.logger.Warn("commitment's bidder address is nil. No notification will be sent", "commitment", commitment) + continue + } + if commitment.BidAmount == nil { + t.logger.Warn("commitment's bid amount is nil. No notification will be sent", "commitment", commitment) + continue + } t.notifier.Notify( notifications.NewNotification( notifications.TopicOtherProviderWonBlock, From b3dd706fafd2f5ee672c8ccf7efba59ec77a73d4 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:50:05 -0700 Subject: [PATCH 14/17] TestOtherProviderWonBlockNotification --- .../preconfirmation/tracker/tracker_test.go | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/p2p/pkg/preconfirmation/tracker/tracker_test.go b/p2p/pkg/preconfirmation/tracker/tracker_test.go index 70d001acc..b3cec5391 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker_test.go +++ b/p2p/pkg/preconfirmation/tracker/tracker_test.go @@ -565,6 +565,149 @@ func TestTrackerIgnoreOldBlocks(t *testing.T) { <-doneChan } +func TestOtherProviderWonBlockNotification(t *testing.T) { + t.Parallel() + + pcABI, err := abi.JSON(strings.NewReader(preconf.PreconfmanagerABI)) + if err != nil { + t.Fatal(err) + } + btABI, err := abi.JSON(strings.NewReader(blocktracker.BlocktrackerABI)) + if err != nil { + t.Fatal(err) + } + brABI, err := abi.JSON(strings.NewReader(bidderregistry.BidderregistryABI)) + if err != nil { + t.Fatal(err) + } + orABI, err := abi.JSON(strings.NewReader(oracle.OracleABI)) + if err != nil { + t.Fatal(err) + } + + evtMgr := events.NewListener( + util.NewTestLogger(os.Stdout), + &btABI, + &pcABI, + &brABI, + &orABI, + ) + + st := store.New(inmemstorage.New()) + + contract := &testPreconfContract{ + openedCommitments: make(chan openedCommitment, 1), + } + + watcher := &mockWatcher{} + notifier := &mockNotifier{ + evt: make(chan *notifications.Notification, 1), + } + + sk, pk, err := crypto.GenerateKeyPairBN254() + if err != nil { + t.Fatal(err) + } + + tracker := preconftracker.NewTracker( + big.NewInt(5), + p2p.PeerTypeProvider, + common.HexToAddress("0x1234"), + evtMgr, + st, + contract, + watcher, + notifier, + pk, + sk, + func(context.Context) (*bind.TransactOpts, error) { + return &bind.TransactOpts{ + From: common.HexToAddress("0x1234"), + }, nil + }, + util.NewTestLogger(os.Stdout), + ) + + ctx, cancel := context.WithCancel(context.Background()) + doneChan := tracker.Start(ctx) + defer func() { + cancel() + select { + case <-doneChan: + case <-time.After(2 * time.Second): + } + }() + + winnerProvider := common.HexToAddress("0x1111") + loserProvider := common.HexToAddress("0x2222") + bidderAddr := common.HexToAddress("0x3333") + + digest := common.HexToHash("0xabc") + cmt := &store.Commitment{ + EncryptedPreConfirmation: &preconfpb.EncryptedPreConfirmation{ + Commitment: digest.Bytes(), + Signature: []byte("sig"), + }, + PreConfirmation: &preconfpb.PreConfirmation{ + Bid: &preconfpb.Bid{ + TxHash: common.HexToHash("0xdeadbeef").String(), + BidAmount: "100", + SlashAmount: "0", + BlockNumber: 1, + DecayStartTimestamp: 1, + DecayEndTimestamp: 2, + Digest: digest.Bytes(), + Signature: []byte("bidsig"), + }, + Digest: digest.Bytes(), + Signature: []byte("pcs"), + ProviderAddress: loserProvider.Bytes(), + SharedSecret: []byte("shared"), + }, + BidderAddress: &bidderAddr, + BidAmount: big.NewInt(100), + } + + if err := tracker.TrackCommitment(context.Background(), cmt, nil); err != nil { + t.Fatal(err) + } + + if err := publishUnopenedCommitment(evtMgr, &pcABI, preconf.PreconfmanagerUnopenedCommitmentStored{ + Committer: loserProvider, + CommitmentIndex: common.HexToHash("0x01"), + CommitmentDigest: digest, + CommitmentSignature: cmt.EncryptedPreConfirmation.Signature, + DispatchTimestamp: uint64(1), + }); err != nil { + t.Fatal(err) + } + cmt.CommitmentIndex = common.HexToHash("0x01").Bytes() + + publishNewWinner(evtMgr, &btABI, blocktracker.BlocktrackerNewL1Block{ + BlockNumber: big.NewInt(1), + Winner: winnerProvider, // Different than commitment provider + }) + + select { + case n := <-notifier.evt: + if n.Topic() != notifications.TopicOtherProviderWonBlock { + t.Fatalf("expected topic %s, got %s", notifications.TopicOtherProviderWonBlock, n.Topic()) + } + val := n.Value() + if val == nil { + t.Fatal("expected non-nil notification payload") + } + if got, ok := val["bidder"].(string); !ok || got != common.Bytes2Hex(bidderAddr[:]) { + t.Fatalf("expected bidder %s, got %v", common.Bytes2Hex(bidderAddr[:]), val["bidder"]) + } + if got, ok := val["bidAmount"].(string); !ok || got != "100" { + t.Fatalf("expected bidAmount 100, got %v", val["bidAmount"]) + } + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for TopicOtherProviderWonBlock notification") + } +} + type openedCommitment struct { encryptedCommitmentIndex [32]byte bid *big.Int From 7f472c16046238cd2132ab0a75b8fba4b7a904f4 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 23:40:15 -0700 Subject: [PATCH 15/17] refactor: remove redundant check --- p2p/pkg/depositmanager/deposit.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/p2p/pkg/depositmanager/deposit.go b/p2p/pkg/depositmanager/deposit.go index 59971ed73..5a63ac8bf 100644 --- a/p2p/pkg/depositmanager/deposit.go +++ b/p2p/pkg/depositmanager/deposit.go @@ -144,10 +144,6 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { bidderHex := val["bidder"].(string) bidAmount := val["bidAmount"].(string) - if bidderHex == "" || bidAmount == "" { - dm.logger.Error("bidder and bid amount are required to refund", "bidder", bidderHex, "bidAmount", bidAmount) - continue - } bidder := common.HexToAddress(bidderHex) bidAmountInt, ok := new(big.Int).SetString(bidAmount, 10) if !ok { From 394ad8913307007d197b7fba7f13010fcff047a7 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sat, 30 Aug 2025 23:45:59 -0700 Subject: [PATCH 16/17] Update tracker.go --- p2p/pkg/preconfirmation/tracker/tracker.go | 27 +++++++++------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/p2p/pkg/preconfirmation/tracker/tracker.go b/p2p/pkg/preconfirmation/tracker/tracker.go index 81297ea73..fe8e984c6 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker.go +++ b/p2p/pkg/preconfirmation/tracker/tracker.go @@ -544,24 +544,19 @@ func (t *Tracker) openCommitments( "providerAddress", commitment.ProviderAddress, "winner", newL1Block.Winner, ) - if commitment.BidderAddress == nil { - t.logger.Warn("commitment's bidder address is nil. No notification will be sent", "commitment", commitment) - continue + notificationPayload := map[string]any{ + "commitmentDigest": hex.EncodeToString(commitment.Commitment[:]), } - if commitment.BidAmount == nil { - t.logger.Warn("commitment's bid amount is nil. No notification will be sent", "commitment", commitment) - continue + if commitment.BidderAddress != nil { + notificationPayload["bidder"] = common.Bytes2Hex(commitment.BidderAddress[:]) } - t.notifier.Notify( - notifications.NewNotification( - notifications.TopicOtherProviderWonBlock, - map[string]any{ - "commitmentDigest": hex.EncodeToString(commitment.Commitment[:]), - "bidder": common.Bytes2Hex(commitment.BidderAddress[:]), - "bidAmount": commitment.BidAmount.String(), - }, - ), - ) + if commitment.BidAmount != nil { + notificationPayload["bidAmount"] = commitment.BidAmount.String() + } + t.notifier.Notify(notifications.NewNotification( + notifications.TopicOtherProviderWonBlock, + notificationPayload, + )) continue } startTime := time.Now() From 72e608c5a63dd0d7f1b57c6a84c4bbf227ddf6fc Mon Sep 17 00:00:00 2001 From: Shawn <44221603+shaspitz@users.noreply.github.com> Date: Sun, 31 Aug 2025 00:06:47 -0700 Subject: [PATCH 17/17] refactor: remove provider from deposit key --- p2p/pkg/depositmanager/deposit.go | 32 +++++++++++----------- p2p/pkg/depositmanager/deposit_test.go | 5 ---- p2p/pkg/depositmanager/store/store.go | 21 +++++++------- p2p/pkg/depositmanager/store/store_test.go | 31 +++++++++------------ 4 files changed, 39 insertions(+), 50 deletions(-) diff --git a/p2p/pkg/depositmanager/deposit.go b/p2p/pkg/depositmanager/deposit.go index 5a63ac8bf..8404b10ea 100644 --- a/p2p/pkg/depositmanager/deposit.go +++ b/p2p/pkg/depositmanager/deposit.go @@ -21,10 +21,10 @@ type BidderRegistryContract interface { } type Store interface { - GetBalance(bidder common.Address, provider common.Address) (*big.Int, error) - SetBalance(bidder common.Address, provider common.Address, balance *big.Int) error - DeleteBalance(bidder common.Address, provider common.Address) error - RefundBalanceIfExists(bidder common.Address, provider common.Address, amount *big.Int) error + GetBalance(bidder common.Address) (*big.Int, error) + SetBalance(bidder common.Address, balance *big.Int) error + DeleteBalance(bidder common.Address) error + RefundBalanceIfExists(bidder common.Address, amount *big.Int) error } type DepositManager struct { @@ -151,7 +151,7 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { continue } - if err := dm.store.RefundBalanceIfExists(bidder, dm.thisProviderAddress, bidAmountInt); err != nil { + if err := dm.store.RefundBalanceIfExists(bidder, bidAmountInt); err != nil { dm.logger.Error("refunding balance", "error", err) return err } @@ -162,13 +162,13 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { dm.logger.Debug("ignoring deposit event for different provider", "provider", deposit.Provider) continue } - currentBalance, err := dm.store.GetBalance(deposit.Bidder, deposit.Provider) + currentBalance, err := dm.store.GetBalance(deposit.Bidder) if err != nil { dm.logger.Error("getting balance", "error", err) return err } if currentBalance == nil { - if err := dm.store.SetBalance(deposit.Bidder, deposit.Provider, deposit.NewAvailableAmount); err != nil { + if err := dm.store.SetBalance(deposit.Bidder, deposit.NewAvailableAmount); err != nil { dm.logger.Error("setting balance", "error", err) return err } @@ -179,7 +179,7 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { ) } else { newBalance := new(big.Int).Add(currentBalance, deposit.DepositedAmount) - if err := dm.store.SetBalance(deposit.Bidder, deposit.Provider, newBalance); err != nil { + if err := dm.store.SetBalance(deposit.Bidder, newBalance); err != nil { dm.logger.Error("setting balance", "error", err) return err } @@ -194,7 +194,7 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { dm.logger.Debug("ignoring withdrawal request event for different provider", "provider", withdrawalRequest.Provider) continue } - if err := dm.store.DeleteBalance(withdrawalRequest.Bidder, withdrawalRequest.Provider); err != nil { + if err := dm.store.DeleteBalance(withdrawalRequest.Bidder); err != nil { dm.logger.Error("deleting balance", "error", err) return err } @@ -208,7 +208,7 @@ func (dm *DepositManager) Start(ctx context.Context) <-chan struct{} { dm.logger.Debug("ignoring withdrawal event for different provider", "provider", withdrawal.Provider) continue } - if err := dm.store.DeleteBalance(withdrawal.Bidder, withdrawal.Provider); err != nil { + if err := dm.store.DeleteBalance(withdrawal.Bidder); err != nil { dm.logger.Error("deleting balance", "error", err) return err } @@ -240,7 +240,7 @@ func (dm *DepositManager) CheckAndDeductDeposit( return nil, status.Errorf(codes.InvalidArgument, "failed to parse bid amount") } - balance, err := dm.store.GetBalance(bidderAddr, dm.thisProviderAddress) + balance, err := dm.store.GetBalance(bidderAddr) if err != nil { dm.logger.Error("getting balance", "error", err) return nil, status.Errorf(codes.Internal, "failed to get balance: %v", err) @@ -253,12 +253,12 @@ func (dm *DepositManager) CheckAndDeductDeposit( return nil, status.Errorf(codes.FailedPrecondition, "insufficient balance") } - if err := dm.store.SetBalance(bidderAddr, dm.thisProviderAddress, newBalance); err != nil { + if err := dm.store.SetBalance(bidderAddr, newBalance); err != nil { dm.logger.Error("setting balance", "error", err) return nil, status.Errorf(codes.Internal, "failed to set balance: %v", err) } return func() error { - return dm.store.RefundBalanceIfExists(bidderAddr, dm.thisProviderAddress, bidAmount) + return dm.store.RefundBalanceIfExists(bidderAddr, bidAmount) }, nil } dm.logger.Info("balance not found in store, defaulting to contract call", @@ -283,13 +283,13 @@ func (dm *DepositManager) CheckAndDeductDeposit( } newBalance := new(big.Int).Sub(defaultBalance, bidAmount) - if err := dm.store.SetBalance(bidderAddr, dm.thisProviderAddress, newBalance); err != nil { + if err := dm.store.SetBalance(bidderAddr, newBalance); err != nil { dm.logger.Error("setting balance for block", "error", err) return nil, status.Errorf(codes.Internal, "failed to set balance for block: %v", err) } return func() error { - return dm.store.RefundBalanceIfExists(bidderAddr, dm.thisProviderAddress, bidAmount) + return dm.store.RefundBalanceIfExists(bidderAddr, bidAmount) }, nil } @@ -313,7 +313,7 @@ func (dm *DepositManager) getDefaultBalance( } if balance.Cmp(big.NewInt(0)) > 0 { - if err := dm.store.SetBalance(bidderAddr, providerAddr, balance); err != nil { + if err := dm.store.SetBalance(bidderAddr, balance); err != nil { dm.logger.Error("setting balance", "error", err) return nil, status.Errorf(codes.Internal, "failed to set balance: %v", err) } diff --git a/p2p/pkg/depositmanager/deposit_test.go b/p2p/pkg/depositmanager/deposit_test.go index 2bd6b6ac7..4dff9707d 100644 --- a/p2p/pkg/depositmanager/deposit_test.go +++ b/p2p/pkg/depositmanager/deposit_test.go @@ -98,7 +98,6 @@ func TestDepositManager(t *testing.T) { for { if val, err := st.GetBalance( common.HexToAddress("0x123"), - common.HexToAddress("0x456"), ); err == nil && val != nil && val.Cmp(big.NewInt(100)) == 0 { break } @@ -142,7 +141,6 @@ func TestDepositManager(t *testing.T) { balance, err := st.GetBalance( common.HexToAddress("0x123"), - common.HexToAddress("0x456"), ) if err != nil { t.Fatal(err) @@ -165,7 +163,6 @@ func TestDepositManager(t *testing.T) { for { if val, err := st.GetBalance( common.HexToAddress("0x123"), - common.HexToAddress("0x456"), ); err == nil && val == nil { break } @@ -206,7 +203,6 @@ func TestDepositManager(t *testing.T) { for { if val, err := st.GetBalance( common.HexToAddress("0x123"), - common.HexToAddress("0x456"), ); err == nil && val != nil && val.Cmp(big.NewInt(777)) == 0 { break } @@ -270,7 +266,6 @@ func TestStartWithBidderAlreadyDeposited(t *testing.T) { for { if val, err := st.GetBalance( common.HexToAddress("0x123"), - common.HexToAddress("0x456"), ); err == nil && val != nil && val.Cmp(big.NewInt(133)) == 0 { break } diff --git a/p2p/pkg/depositmanager/store/store.go b/p2p/pkg/depositmanager/store/store.go index a5de60770..d06782d78 100644 --- a/p2p/pkg/depositmanager/store/store.go +++ b/p2p/pkg/depositmanager/store/store.go @@ -17,8 +17,8 @@ const ( ) var ( - balanceKey = func(bidder common.Address, provider common.Address) string { - return fmt.Sprintf("%s%s/%s", balanceNS, bidder, provider) + balanceKey = func(bidder common.Address) string { + return fmt.Sprintf("%s%s", balanceNS, bidder) } balancePrefix = func(bidder common.Address) string { return fmt.Sprintf("%s%s", balanceNS, bidder) @@ -36,18 +36,18 @@ func New(st storage.Storage) *Store { } } -func (s *Store) SetBalance(bidder common.Address, provider common.Address, depositedAmount *big.Int) error { +func (s *Store) SetBalance(bidder common.Address, depositedAmount *big.Int) error { s.mu.Lock() defer s.mu.Unlock() - return s.st.Put(balanceKey(bidder, provider), depositedAmount.Bytes()) + return s.st.Put(balanceKey(bidder), depositedAmount.Bytes()) } -func (s *Store) GetBalance(bidder common.Address, provider common.Address) (*big.Int, error) { +func (s *Store) GetBalance(bidder common.Address) (*big.Int, error) { s.mu.RLock() defer s.mu.RUnlock() - val, err := s.st.Get(balanceKey(bidder, provider)) + val, err := s.st.Get(balanceKey(bidder)) switch { case errors.Is(err, storage.ErrKeyNotFound): return nil, nil @@ -58,21 +58,20 @@ func (s *Store) GetBalance(bidder common.Address, provider common.Address) (*big return new(big.Int).SetBytes(val), nil } -func (s *Store) DeleteBalance(bidder common.Address, provider common.Address) error { +func (s *Store) DeleteBalance(bidder common.Address) error { s.mu.Lock() defer s.mu.Unlock() - return s.st.Delete(balanceKey(bidder, provider)) + return s.st.Delete(balanceKey(bidder)) } func (s *Store) RefundBalanceIfExists( bidder common.Address, - provider common.Address, amount *big.Int, ) error { s.mu.Lock() defer s.mu.Unlock() - val, err := s.st.Get(balanceKey(bidder, provider)) + val, err := s.st.Get(balanceKey(bidder)) switch { case errors.Is(err, storage.ErrKeyNotFound): return status.Errorf(codes.FailedPrecondition, "balance not found, no refund needed") @@ -81,7 +80,7 @@ func (s *Store) RefundBalanceIfExists( } newAmount := new(big.Int).Add(new(big.Int).SetBytes(val), amount) - return s.st.Put(balanceKey(bidder, provider), newAmount.Bytes()) + return s.st.Put(balanceKey(bidder), newAmount.Bytes()) } func (s *Store) BalanceEntries(bidder common.Address) (int, error) { diff --git a/p2p/pkg/depositmanager/store/store_test.go b/p2p/pkg/depositmanager/store/store_test.go index 26f0e22e9..ed3253159 100644 --- a/p2p/pkg/depositmanager/store/store_test.go +++ b/p2p/pkg/depositmanager/store/store_test.go @@ -15,15 +15,14 @@ func TestStore_SetBalance(t *testing.T) { s := store.New(st) bidder := common.HexToAddress("0x123") - provider := common.HexToAddress("0x456") depositedAmount := big.NewInt(10) - err := s.SetBalance(bidder, provider, depositedAmount) + err := s.SetBalance(bidder, depositedAmount) if err != nil { t.Fatal(err) } - val, err := s.GetBalance(bidder, provider) + val, err := s.GetBalance(bidder) if err != nil { t.Fatal(err) } @@ -37,15 +36,14 @@ func TestStore_GetBalance(t *testing.T) { s := store.New(st) bidder := common.HexToAddress("0x123") - provider := common.HexToAddress("0x456") depositedAmount := big.NewInt(10) - err := s.SetBalance(bidder, provider, depositedAmount) + err := s.SetBalance(bidder, depositedAmount) if err != nil { t.Fatal(err) } - val, err := s.GetBalance(bidder, provider) + val, err := s.GetBalance(bidder) if err != nil { t.Fatal(err) } @@ -59,9 +57,8 @@ func TestStore_GetBalance_NoBalance(t *testing.T) { s := store.New(st) bidder := common.HexToAddress("0x123") - provider := common.HexToAddress("0x456") - val, err := s.GetBalance(bidder, provider) + val, err := s.GetBalance(bidder) if err != nil { t.Fatal(err) } @@ -75,10 +72,9 @@ func TestStore_RefundBalanceIfExists(t *testing.T) { s := store.New(st) bidder := common.HexToAddress("0x123") - provider := common.HexToAddress("0x456") amount := big.NewInt(20) - err := s.RefundBalanceIfExists(bidder, provider, amount) + err := s.RefundBalanceIfExists(bidder, amount) if err == nil { t.Fatal("expected error, got nil") } @@ -86,18 +82,18 @@ func TestStore_RefundBalanceIfExists(t *testing.T) { t.Fatalf("expected error containing 'balance not found, no refund needed', got %v", err) } - err = s.SetBalance(bidder, provider, amount) + err = s.SetBalance(bidder, amount) if err != nil { t.Fatal(err) } increaseAmount := big.NewInt(5) - err = s.RefundBalanceIfExists(bidder, provider, increaseAmount) + err = s.RefundBalanceIfExists(bidder, increaseAmount) if err != nil { t.Fatal(err) } - val, err := s.GetBalance(bidder, provider) + val, err := s.GetBalance(bidder) if err != nil { t.Fatal(err) } @@ -112,15 +108,14 @@ func TestStore_DeleteBalance(t *testing.T) { s := store.New(st) bidder := common.HexToAddress("0x123") - provider := common.HexToAddress("0x456") depositedAmount := big.NewInt(10) - err := s.SetBalance(bidder, provider, depositedAmount) + err := s.SetBalance(bidder, depositedAmount) if err != nil { t.Fatal(err) } - val, err := s.GetBalance(bidder, provider) + val, err := s.GetBalance(bidder) if err != nil { t.Fatal(err) } @@ -128,12 +123,12 @@ func TestStore_DeleteBalance(t *testing.T) { t.Fatalf("expected %s, got %s", depositedAmount.String(), val.String()) } - err = s.DeleteBalance(bidder, provider) + err = s.DeleteBalance(bidder) if err != nil { t.Fatal(err) } - val, err = s.GetBalance(bidder, provider) + val, err = s.GetBalance(bidder) if err != nil { t.Fatal(err) }