From 87d3207baf70a401e47138c6525ec71b10dd5a3a Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 29 May 2019 08:57:04 +0200 Subject: [PATCH] channeldb+routing: move control tower interface to routing This commit creates an empty shall for control tower in the routing package. It is a preparation for adding event notification. --- .../{control_tower.go => payment_control.go} | 52 ++-------- ..._tower_test.go => payment_control_test.go} | 0 routing/control_tower.go | 94 +++++++++++++++++++ routing/mock_test.go | 2 +- routing/router.go | 2 +- server.go | 4 +- 6 files changed, 109 insertions(+), 45 deletions(-) rename channeldb/{control_tower.go => payment_control.go} (83%) rename channeldb/{control_tower_test.go => payment_control_test.go} (100%) create mode 100644 routing/control_tower.go diff --git a/channeldb/control_tower.go b/channeldb/payment_control.go similarity index 83% rename from channeldb/control_tower.go rename to channeldb/payment_control.go index 97b44180..1cbc0b81 100644 --- a/channeldb/control_tower.go +++ b/channeldb/payment_control.go @@ -35,46 +35,14 @@ var ( ErrUnknownPaymentStatus = errors.New("unknown payment status") ) -// ControlTower tracks all outgoing payments made, whose primary purpose is to -// prevent duplicate payments to the same payment hash. In production, a -// persistent implementation is preferred so that tracking can survive across -// restarts. Payments are transitioned through various payment states, and the -// ControlTower interface provides access to driving the state transitions. -type ControlTower interface { - // InitPayment atomically moves the payment into the InFlight state. - // This method checks that no suceeded payment exist for this payment - // hash. - InitPayment(lntypes.Hash, *PaymentCreationInfo) error - - // RegisterAttempt atomically records the provided PaymentAttemptInfo. - RegisterAttempt(lntypes.Hash, *PaymentAttemptInfo) error - - // Success transitions a payment into the Succeeded state. After - // invoking this method, InitPayment should always return an error to - // prevent us from making duplicate payments to the same payment hash. - // The provided preimage is atomically saved to the DB for record - // keeping. - Success(lntypes.Hash, lntypes.Preimage) error - - // Fail transitions a payment into the Failed state, and records the - // reason the payment failed. After invoking this method, InitPayment - // should return nil on its next call for this payment hash, allowing - // the switch to make a subsequent payment. - Fail(lntypes.Hash, FailureReason) error - - // FetchInFlightPayments returns all payments with status InFlight. - FetchInFlightPayments() ([]*InFlightPayment, error) -} - -// paymentControl is persistent implementation of ControlTower to restrict -// double payment sending. -type paymentControl struct { +// PaymentControl implements persistence for payments and payment attempts. +type PaymentControl struct { db *DB } -// NewPaymentControl creates a new instance of the paymentControl. -func NewPaymentControl(db *DB) ControlTower { - return &paymentControl{ +// NewPaymentControl creates a new instance of the PaymentControl. +func NewPaymentControl(db *DB) *PaymentControl { + return &PaymentControl{ db: db, } } @@ -83,7 +51,7 @@ func NewPaymentControl(db *DB) ControlTower { // making sure it does not already exist as an in-flight payment. Then this // method returns successfully, the payment is guranteeed to be in the InFlight // state. -func (p *paymentControl) InitPayment(paymentHash lntypes.Hash, +func (p *PaymentControl) InitPayment(paymentHash lntypes.Hash, info *PaymentCreationInfo) error { var b bytes.Buffer @@ -173,7 +141,7 @@ func (p *paymentControl) InitPayment(paymentHash lntypes.Hash, // RegisterAttempt atomically records the provided PaymentAttemptInfo to the // DB. -func (p *paymentControl) RegisterAttempt(paymentHash lntypes.Hash, +func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash, attempt *PaymentAttemptInfo) error { // Serialize the information before opening the db transaction. @@ -218,7 +186,7 @@ func (p *paymentControl) RegisterAttempt(paymentHash lntypes.Hash, // method, InitPayment should always return an error to prevent us from making // duplicate payments to the same payment hash. The provided preimage is // atomically saved to the DB for record keeping. -func (p *paymentControl) Success(paymentHash lntypes.Hash, +func (p *PaymentControl) Success(paymentHash lntypes.Hash, preimage lntypes.Preimage) error { var updateErr error @@ -257,7 +225,7 @@ func (p *paymentControl) Success(paymentHash lntypes.Hash, // payment failed. After invoking this method, InitPayment should return nil on // its next call for this payment hash, allowing the switch to make a // subsequent payment. -func (p *paymentControl) Fail(paymentHash lntypes.Hash, +func (p *PaymentControl) Fail(paymentHash lntypes.Hash, reason FailureReason) error { var updateErr error @@ -402,7 +370,7 @@ type InFlightPayment struct { } // FetchInFlightPayments returns all payments with status InFlight. -func (p *paymentControl) FetchInFlightPayments() ([]*InFlightPayment, error) { +func (p *PaymentControl) FetchInFlightPayments() ([]*InFlightPayment, error) { var inFlights []*InFlightPayment err := p.db.View(func(tx *bbolt.Tx) error { payments := tx.Bucket(paymentsRootBucket) diff --git a/channeldb/control_tower_test.go b/channeldb/payment_control_test.go similarity index 100% rename from channeldb/control_tower_test.go rename to channeldb/payment_control_test.go diff --git a/routing/control_tower.go b/routing/control_tower.go new file mode 100644 index 00000000..c7a2216a --- /dev/null +++ b/routing/control_tower.go @@ -0,0 +1,94 @@ +package routing + +import ( + "github.com/lightningnetwork/lnd/channeldb" + + "github.com/lightningnetwork/lnd/lntypes" +) + +// ControlTower tracks all outgoing payments made, whose primary purpose is to +// prevent duplicate payments to the same payment hash. In production, a +// persistent implementation is preferred so that tracking can survive across +// restarts. Payments are transitioned through various payment states, and the +// ControlTower interface provides access to driving the state transitions. +type ControlTower interface { + // InitPayment atomically moves the payment into the InFlight state. + // This method checks that no suceeded payment exist for this payment + // hash. + InitPayment(lntypes.Hash, *channeldb.PaymentCreationInfo) error + + // RegisterAttempt atomically records the provided PaymentAttemptInfo. + RegisterAttempt(lntypes.Hash, *channeldb.PaymentAttemptInfo) error + + // Success transitions a payment into the Succeeded state. After + // invoking this method, InitPayment should always return an error to + // prevent us from making duplicate payments to the same payment hash. + // The provided preimage is atomically saved to the DB for record + // keeping. + Success(lntypes.Hash, lntypes.Preimage) error + + // Fail transitions a payment into the Failed state, and records the + // reason the payment failed. After invoking this method, InitPayment + // should return nil on its next call for this payment hash, allowing + // the switch to make a subsequent payment. + Fail(lntypes.Hash, channeldb.FailureReason) error + + // FetchInFlightPayments returns all payments with status InFlight. + FetchInFlightPayments() ([]*channeldb.InFlightPayment, error) +} + +// controlTower is persistent implementation of ControlTower to restrict +// double payment sending. +type controlTower struct { + db *channeldb.PaymentControl +} + +// NewControlTower creates a new instance of the controlTower. +func NewControlTower(db *channeldb.PaymentControl) ControlTower { + return &controlTower{ + db: db, + } +} + +// InitPayment checks or records the given PaymentCreationInfo with the DB, +// making sure it does not already exist as an in-flight payment. Then this +// method returns successfully, the payment is guranteeed to be in the InFlight +// state. +func (p *controlTower) InitPayment(paymentHash lntypes.Hash, + info *channeldb.PaymentCreationInfo) error { + + return p.db.InitPayment(paymentHash, info) +} + +// RegisterAttempt atomically records the provided PaymentAttemptInfo to the +// DB. +func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash, + attempt *channeldb.PaymentAttemptInfo) error { + + return p.db.RegisterAttempt(paymentHash, attempt) +} + +// Success transitions a payment into the Succeeded state. After invoking this +// method, InitPayment should always return an error to prevent us from making +// duplicate payments to the same payment hash. The provided preimage is +// atomically saved to the DB for record keeping. +func (p *controlTower) Success(paymentHash lntypes.Hash, + preimage lntypes.Preimage) error { + + return p.db.Success(paymentHash, preimage) +} + +// Fail transitions a payment into the Failed state, and records the reason the +// payment failed. After invoking this method, InitPayment should return nil on +// its next call for this payment hash, allowing the switch to make a +// subsequent payment. +func (p *controlTower) Fail(paymentHash lntypes.Hash, + reason channeldb.FailureReason) error { + + return p.db.Fail(paymentHash, reason) +} + +// FetchInFlightPayments returns all payments with status InFlight. +func (p *controlTower) FetchInFlightPayments() ([]*channeldb.InFlightPayment, error) { + return p.db.FetchInFlightPayments() +} diff --git a/routing/mock_test.go b/routing/mock_test.go index c5314b83..e61b6677 100644 --- a/routing/mock_test.go +++ b/routing/mock_test.go @@ -182,7 +182,7 @@ type mockControlTower struct { sync.Mutex } -var _ channeldb.ControlTower = (*mockControlTower)(nil) +var _ ControlTower = (*mockControlTower)(nil) func makeMockControlTower() *mockControlTower { return &mockControlTower{ diff --git a/routing/router.go b/routing/router.go index 88c894b7..72842003 100644 --- a/routing/router.go +++ b/routing/router.go @@ -218,7 +218,7 @@ type Config struct { // Control keeps track of the status of ongoing payments, ensuring we // can properly resume them across restarts. - Control channeldb.ControlTower + Control ControlTower // MissionControl is a shared memory of sorts that executions of // payment path finding use in order to remember which vertexes/edges diff --git a/server.go b/server.go index 64293b3e..6e85dc3d 100644 --- a/server.go +++ b/server.go @@ -649,12 +649,14 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, routerrpc.GetMissionControlConfig(cfg.SubRPCServers.RouterRPC), ) + paymentControl := channeldb.NewPaymentControl(chanDB) + s.chanRouter, err = routing.New(routing.Config{ Graph: chanGraph, Chain: cc.chainIO, ChainView: cc.chainView, Payer: s.htlcSwitch, - Control: channeldb.NewPaymentControl(chanDB), + Control: routing.NewControlTower(paymentControl), MissionControl: s.missionControl, ChannelPruneExpiry: routing.DefaultChannelPruneExpiry, GraphPruneInterval: time.Duration(time.Hour),