diff --git a/client.go b/client.go index c765637..89abf7c 100644 --- a/client.go +++ b/client.go @@ -138,12 +138,12 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) { } swaps = append(swaps, &SwapInfo{ - SwapType: TypeOut, - SwapContract: swp.Contract.SwapContract, - State: swp.State(), - SwapHash: swp.Hash, - LastUpdate: swp.LastUpdateTime(), - HtlcAddress: htlc.Address, + SwapType: TypeOut, + SwapContract: swp.Contract.SwapContract, + SwapStateData: swp.State(), + SwapHash: swp.Hash, + LastUpdate: swp.LastUpdateTime(), + HtlcAddress: htlc.Address, }) } @@ -158,12 +158,12 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) { } swaps = append(swaps, &SwapInfo{ - SwapType: TypeIn, - SwapContract: swp.Contract.SwapContract, - State: swp.State(), - SwapHash: swp.Hash, - LastUpdate: swp.LastUpdateTime(), - HtlcAddress: htlc.Address, + SwapType: TypeIn, + SwapContract: swp.Contract.SwapContract, + SwapStateData: swp.State(), + SwapHash: swp.Hash, + LastUpdate: swp.LastUpdateTime(), + HtlcAddress: htlc.Address, }) } @@ -259,7 +259,7 @@ func (s *Client) resumeSwaps(ctx context.Context, } for _, pend := range loopOutSwaps { - if pend.State().Type() != loopdb.StateTypePending { + if pend.State().State.Type() != loopdb.StateTypePending { continue } swap, err := resumeLoopOutSwap(ctx, swapCfg, pend) @@ -272,7 +272,7 @@ func (s *Client) resumeSwaps(ctx context.Context, } for _, pend := range loopInSwaps { - if pend.State().Type() != loopdb.StateTypePending { + if pend.State().State.Type() != loopdb.StateTypePending { continue } swap, err := resumeLoopInSwap(ctx, swapCfg, pend) diff --git a/client_test.go b/client_test.go index 09b921a..9419521 100644 --- a/client_test.go +++ b/client_test.go @@ -202,7 +202,9 @@ func testResume(t *testing.T, expired, preimageRevealed, expectSuccess bool) { Loop: loopdb.Loop{ Events: []*loopdb.LoopEvent{ { - State: state, + SwapStateData: loopdb.SwapStateData{ + State: state, + }, }, }, Hash: hash, diff --git a/cmd/loop/main.go b/cmd/loop/main.go index bb0b969..b518775 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -176,11 +176,22 @@ func parseAmt(text string) (btcutil.Amount, error) { } func logSwap(swap *looprpc.SwapStatus) { - fmt.Printf("%v %v %v %v - %v\n", + fmt.Printf("%v %v %v %v - %v", time.Unix(0, swap.LastUpdateTime).Format(time.RFC3339), swap.Type, swap.State, btcutil.Amount(swap.Amt), swap.HtlcAddress, ) + + if swap.State != looprpc.SwapState_INITIATED && + swap.State != looprpc.SwapState_HTLC_PUBLISHED && + swap.State != looprpc.SwapState_PREIMAGE_REVEALED { + + fmt.Printf(" (cost: server %v, onchain %v, offchain %v)", + swap.CostServer, swap.CostOnchain, swap.CostOffchain, + ) + } + + fmt.Println() } func getClientConn(address string) (*grpc.ClientConn, error) { diff --git a/cmd/loop/monitor.go b/cmd/loop/monitor.go index 8f51fcf..7247cf8 100644 --- a/cmd/loop/monitor.go +++ b/cmd/loop/monitor.go @@ -28,6 +28,9 @@ func monitor(ctx *cli.Context) error { return err } + fmt.Printf("Note: offchain cost may report as 0 after loopd restart " + + "during swap\n") + for { swap, err := stream.Recv() if err != nil { diff --git a/cmd/loopd/swapclient_server.go b/cmd/loopd/swapclient_server.go index 38179d6..4761af8 100644 --- a/cmd/loopd/swapclient_server.go +++ b/cmd/loopd/swapclient_server.go @@ -121,6 +121,9 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) ( LastUpdateTime: loopSwap.LastUpdate.UnixNano(), HtlcAddress: loopSwap.HtlcAddress.EncodeAddress(), Type: swapType, + CostServer: int64(loopSwap.Cost.Server), + CostOnchain: int64(loopSwap.Cost.Onchain), + CostOffchain: int64(loopSwap.Cost.Offchain), }, nil } diff --git a/cmd/loopd/view.go b/cmd/loopd/view.go index c2583b0..eefc47f 100644 --- a/cmd/loopd/view.go +++ b/cmd/loopd/view.go @@ -6,6 +6,7 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/lightninglabs/loop" + "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/swap" ) @@ -77,9 +78,19 @@ func viewOut(swapClient *loop.Client, chainParams *chaincfg.Params) error { s.Contract.AmountRequested, s.Contract.CltvExpiry, ) for i, e := range s.Events { - fmt.Printf(" Update %v, Time %v, State: %v\n", + fmt.Printf(" Update %v, Time %v, State: %v", i, e.Time, e.State, ) + if e.State.Type() != loopdb.StateTypePending { + fmt.Printf(", Cost: server=%v, onchain=%v, "+ + "offchain=%v", + e.Cost.Server, + e.Cost.Onchain, + e.Cost.Offchain, + ) + } + + fmt.Println() } fmt.Println() } diff --git a/interface.go b/interface.go index 15d8245..04756f5 100644 --- a/interface.go +++ b/interface.go @@ -83,15 +83,6 @@ type Out struct { SwapInfoKit } -// SwapCost is a breakdown of the final swap costs. -type SwapCost struct { - // Swap is the amount paid to the server. - Server btcutil.Amount - - // Onchain is the amount paid to miners for the onchain tx. - Onchain btcutil.Amount -} - // LoopOutQuoteRequest specifies the swap parameters for which a quote is // requested. type LoopOutQuoteRequest struct { @@ -280,12 +271,12 @@ func (t Type) String() string { // SwapInfo exposes common info fields for loop in and loop out swaps. type SwapInfo struct { + loopdb.SwapStateData + LastUpdate time.Time SwapHash lntypes.Hash - State loopdb.SwapState - SwapType Type loopdb.SwapContract diff --git a/loopdb/interface.go b/loopdb/interface.go index 72b92d0..86dd853 100644 --- a/loopdb/interface.go +++ b/loopdb/interface.go @@ -18,7 +18,8 @@ type SwapStore interface { // UpdateLoopOut stores a new event for a target loop out swap. This // appends to the event log for a particular swap as it goes through // the various stages in its lifetime. - UpdateLoopOut(hash lntypes.Hash, time time.Time, state SwapState) error + UpdateLoopOut(hash lntypes.Hash, time time.Time, + state SwapStateData) error // FetchLoopInSwaps returns all swaps currently in the store. FetchLoopInSwaps() ([]*LoopIn, error) @@ -29,7 +30,8 @@ type SwapStore interface { // UpdateLoopIn stores a new event for a target loop in swap. This // appends to the event log for a particular swap as it goes through // the various stages in its lifetime. - UpdateLoopIn(hash lntypes.Hash, time time.Time, state SwapState) error + UpdateLoopIn(hash lntypes.Hash, time time.Time, + state SwapStateData) error // Close closes the underlying database. Close() error diff --git a/loopdb/log.go b/loopdb/log.go index 73cc81d..4497196 100644 --- a/loopdb/log.go +++ b/loopdb/log.go @@ -1,44 +1,21 @@ package loopdb import ( + "os" + "github.com/btcsuite/btclog" ) -// log is a logger that is initialized with no output filters. This means -// the package will not perform any logging by default until the caller -// requests it. -var log btclog.Logger - -// The default amount of logging is none. -func init() { - DisableLog() -} - -// DisableLog disables all library log output. Logging output is disabled -// by default until either UseLogger or SetLogWriter are called. -func DisableLog() { - log = btclog.Disabled -} - -// UseLogger uses a specified Logger to output package logging info. -// This should be used in preference to SetLogWriter if the caller is also -// using btclog. -func UseLogger(logger btclog.Logger) { - log = logger -} - -// logClosure is used to provide a closure over expensive logging operations so -// don't have to be performed when the logging level doesn't warrant it. -type logClosure func() string +var ( + backendLog = btclog.NewBackend(logWriter{}) + log = backendLog.Logger("STORE") +) -// String invokes the underlying function and returns the result. -func (c logClosure) String() string { - return c() -} +// logWriter implements an io.Writer that outputs to both standard output and +// the write-end pipe of an initialized log rotator. +type logWriter struct{} -// newLogClosure returns a new closure over a function that returns a string -// which itself provides a Stringer interface so that it can be used with the -// logging system. -func newLogClosure(c func() string) logClosure { - return logClosure(c) +func (logWriter) Write(p []byte) (n int, err error) { + os.Stdout.Write(p) + return len(p), nil } diff --git a/loopdb/loop.go b/loopdb/loop.go index 80298e8..870df9f 100644 --- a/loopdb/loop.go +++ b/loopdb/loop.go @@ -53,21 +53,22 @@ type Loop struct { // LoopEvent contains the dynamic data of a swap. type LoopEvent struct { - // State is the new state for this swap as a result of this event. - State SwapState + SwapStateData // Time is the time that this swap had its state changed. Time time.Time } // State returns the most recent state of this swap. -func (s *Loop) State() SwapState { +func (s *Loop) State() SwapStateData { lastUpdate := s.LastUpdate() if lastUpdate == nil { - return StateInitiated + return SwapStateData{ + State: StateInitiated, + } } - return lastUpdate.State + return lastUpdate.SwapStateData } // LastUpdate returns the most recent update of this swap. @@ -84,7 +85,7 @@ func (s *Loop) LastUpdate() *LoopEvent { // serializeLoopEvent serializes a state update of a swap. This is used for both // in and out swaps. -func serializeLoopEvent(time time.Time, state SwapState) ( +func serializeLoopEvent(time time.Time, state SwapStateData) ( []byte, error) { var b bytes.Buffer @@ -93,7 +94,19 @@ func serializeLoopEvent(time time.Time, state SwapState) ( return nil, err } - if err := binary.Write(&b, byteOrder, state); err != nil { + if err := binary.Write(&b, byteOrder, state.State); err != nil { + return nil, err + } + + if err := binary.Write(&b, byteOrder, state.Cost.Server); err != nil { + return nil, err + } + + if err := binary.Write(&b, byteOrder, state.Cost.Onchain); err != nil { + return nil, err + } + + if err := binary.Write(&b, byteOrder, state.Cost.Offchain); err != nil { return nil, err } @@ -117,5 +130,17 @@ func deserializeLoopEvent(value []byte) (*LoopEvent, error) { return nil, err } + if err := binary.Read(r, byteOrder, &update.Cost.Server); err != nil { + return nil, err + } + + if err := binary.Read(r, byteOrder, &update.Cost.Onchain); err != nil { + return nil, err + } + + if err := binary.Read(r, byteOrder, &update.Cost.Offchain); err != nil { + return nil, err + } + return update, nil } diff --git a/loopdb/meta.go b/loopdb/meta.go index a1d9a18..e1a3127 100644 --- a/loopdb/meta.go +++ b/loopdb/meta.go @@ -10,7 +10,7 @@ import ( var ( // metaBucket stores all the meta information concerning the state of // the database. - metaBucket = []byte("metadata") + metaBucketKey = []byte("metadata") // dbVersionKey is a boltdb key and it's used for storing/retrieving // current database version. @@ -31,7 +31,7 @@ var ( // of database don't match with latest version this list will be used // for retrieving all migration function that are need to apply to the // current db. - migrations = []migration{} + migrations = []migration{migrateCosts} latestDBVersion = uint32(len(migrations)) ) @@ -41,7 +41,7 @@ func getDBVersion(db *bbolt.DB) (uint32, error) { var version uint32 err := db.View(func(tx *bbolt.Tx) error { - metaBucket := tx.Bucket(metaBucket) + metaBucket := tx.Bucket(metaBucketKey) if metaBucket == nil { return errors.New("bucket does not exist") } @@ -61,11 +61,11 @@ func getDBVersion(db *bbolt.DB) (uint32, error) { return version, nil } -// getDBVersion updates the current db version. +// setDBVersion updates the current db version. func setDBVersion(tx *bbolt.Tx, version uint32) error { - metaBucket := tx.Bucket(metaBucket) - if metaBucket == nil { - return errors.New("bucket does not exist") + metaBucket, err := tx.CreateBucketIfNotExists(metaBucketKey) + if err != nil { + return fmt.Errorf("set db version: %v", err) } scratch := make([]byte, 4) diff --git a/loopdb/migration_01_costs.go b/loopdb/migration_01_costs.go new file mode 100644 index 0000000..55d1df5 --- /dev/null +++ b/loopdb/migration_01_costs.go @@ -0,0 +1,78 @@ +package loopdb + +import ( + "errors" + "fmt" + + "github.com/coreos/bbolt" +) + +// noMigrationAvailable is the fall back migration in case there is no migration +// implemented. +func migrateCosts(tx *bbolt.Tx) error { + if err := migrateCostsForBucket(tx, loopInBucketKey); err != nil { + return err + } + if err := migrateCostsForBucket(tx, loopOutBucketKey); err != nil { + return err + } + return nil +} + +func migrateCostsForBucket(tx *bbolt.Tx, bucketKey []byte) error { + // First, we'll grab our main loop in bucket key. + rootBucket := tx.Bucket(bucketKey) + if rootBucket == nil { + return errors.New("bucket does not exist") + } + + // We'll now traverse the root bucket for all active swaps. The + // primary key is the swap hash itself. + return rootBucket.ForEach(func(swapHash, v []byte) error { + // Only go into things that we know are sub-bucket + // keys. + if v != nil { + return nil + } + + // From the root bucket, we'll grab the next swap + // bucket for this swap from its swaphash. + swapBucket := rootBucket.Bucket(swapHash) + if swapBucket == nil { + return fmt.Errorf("swap bucket %x not found", + swapHash) + } + + // Get the updates bucket. + updatesBucket := swapBucket.Bucket(updatesBucketKey) + if updatesBucket == nil { + return errors.New("updates bucket not found") + } + + // Get list of all update ids. + var ids [][]byte + err := updatesBucket.ForEach(func(k, v []byte) error { + ids = append(ids, k) + return nil + }) + if err != nil { + return err + } + + // Append three zeroed cost factors to all updates. + var emptyCosts [3 * 8]byte + for _, id := range ids { + v := updatesBucket.Get(id) + if v == nil { + return errors.New("empty value") + } + v = append(v, emptyCosts[:]...) + err := updatesBucket.Put(id, v) + if err != nil { + return err + } + } + + return nil + }) +} diff --git a/loopdb/store.go b/loopdb/store.go index 463395f..2a90ce8 100644 --- a/loopdb/store.go +++ b/loopdb/store.go @@ -100,18 +100,33 @@ func NewBoltSwapStore(dbPath string, chainParams *chaincfg.Params) ( // We'll create all the buckets we need if this is the first time we're // starting up. If they already exist, then these calls will be noops. err = bdb.Update(func(tx *bbolt.Tx) error { - _, err := tx.CreateBucketIfNotExists(loopOutBucketKey) - if err != nil { - return err + // Check if the meta bucket exists. If it exists, we consider + // the database as initialized and assume the meta bucket + // contains the db version. + metaBucket := tx.Bucket(metaBucketKey) + if metaBucket == nil { + log.Infof("Initializing new database with version %v", + latestDBVersion) + + // Set db version to the current version. + err := setDBVersion(tx, latestDBVersion) + if err != nil { + return err + } } - _, err = tx.CreateBucketIfNotExists(loopInBucketKey) + + // Try creating these buckets, because loop in was added without + // bumping the db version number. + _, err = tx.CreateBucketIfNotExists(loopOutBucketKey) if err != nil { return err } - _, err = tx.CreateBucketIfNotExists(metaBucket) + + _, err = tx.CreateBucketIfNotExists(loopInBucketKey) if err != nil { return err } + return nil }) if err != nil { @@ -346,7 +361,7 @@ func (s *boltSwapStore) CreateLoopIn(hash lntypes.Hash, // updateLoop saves a new swap state transition to the store. It takes in a // bucket key so that this function can be used for both in and out swaps. func (s *boltSwapStore) updateLoop(bucketKey []byte, hash lntypes.Hash, - time time.Time, state SwapState) error { + time time.Time, state SwapStateData) error { return s.db.Update(func(tx *bbolt.Tx) error { // Starting from the root bucket, we'll traverse the bucket @@ -386,7 +401,7 @@ func (s *boltSwapStore) updateLoop(bucketKey []byte, hash lntypes.Hash, // // NOTE: Part of the loopdb.SwapStore interface. func (s *boltSwapStore) UpdateLoopOut(hash lntypes.Hash, time time.Time, - state SwapState) error { + state SwapStateData) error { return s.updateLoop(loopOutBucketKey, hash, time, state) } @@ -396,7 +411,7 @@ func (s *boltSwapStore) UpdateLoopOut(hash lntypes.Hash, time time.Time, // // NOTE: Part of the loopdb.SwapStore interface. func (s *boltSwapStore) UpdateLoopIn(hash lntypes.Hash, time time.Time, - state SwapState) error { + state SwapStateData) error { return s.updateLoop(loopInBucketKey, hash, time, state) } diff --git a/loopdb/store_test.go b/loopdb/store_test.go index f2a0869..64d9451 100644 --- a/loopdb/store_test.go +++ b/loopdb/store_test.go @@ -4,11 +4,13 @@ import ( "crypto/sha256" "io/ioutil" "os" + "path/filepath" "reflect" "testing" "time" "github.com/btcsuite/btcd/chaincfg" + "github.com/coreos/bbolt" "github.com/lightninglabs/loop/test" "github.com/lightningnetwork/lnd/lntypes" ) @@ -107,7 +109,7 @@ func TestLoopOutStore(t *testing.T) { t.Fatal("invalid pending swap data") } - if swaps[0].State() != expectedState { + if swaps[0].State().State != expectedState { t.Fatalf("expected state %v, but got %v", expectedState, swaps[0].State(), ) @@ -130,7 +132,10 @@ func TestLoopOutStore(t *testing.T) { // Next, we'll update to the next state of the pre-image being // revealed. The state should be reflected here again. err = store.UpdateLoopOut( - hash, testTime, StatePreimageRevealed, + hash, testTime, + SwapStateData{ + State: StatePreimageRevealed, + }, ) if err != nil { t.Fatal(err) @@ -140,7 +145,10 @@ func TestLoopOutStore(t *testing.T) { // Next, we'll update to the final state to ensure that the state is // properly updated. err = store.UpdateLoopOut( - hash, testTime, StateFailInsufficientValue, + hash, testTime, + SwapStateData{ + State: StateFailInsufficientValue, + }, ) if err != nil { t.Fatal(err) @@ -229,7 +237,7 @@ func TestLoopInStore(t *testing.T) { t.Fatal("invalid pending swap data") } - if swaps[0].State() != expectedState { + if swaps[0].State().State != expectedState { t.Fatalf("expected state %v, but got %v", expectedState, swaps[0].State(), ) @@ -252,7 +260,10 @@ func TestLoopInStore(t *testing.T) { // Next, we'll update to the next state of the pre-image being // revealed. The state should be reflected here again. err = store.UpdateLoopIn( - hash, testTime, StatePreimageRevealed, + hash, testTime, + SwapStateData{ + State: StatePreimageRevealed, + }, ) if err != nil { t.Fatal(err) @@ -262,7 +273,10 @@ func TestLoopInStore(t *testing.T) { // Next, we'll update to the final state to ensure that the state is // properly updated. err = store.UpdateLoopIn( - hash, testTime, StateFailInsufficientValue, + hash, testTime, + SwapStateData{ + State: StateFailInsufficientValue, + }, ) if err != nil { t.Fatal(err) @@ -281,3 +295,72 @@ func TestLoopInStore(t *testing.T) { } checkSwap(StateFailInsufficientValue) } + +// TestVersionNew tests that a new database is initialized with the current +// version. +func TestVersionNew(t *testing.T) { + tempDirName, err := ioutil.TempDir("", "clientstore") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempDirName) + + store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams) + if err != nil { + t.Fatal(err) + } + + ver, err := getDBVersion(store.db) + if err != nil { + t.Fatal(err) + } + + if ver != latestDBVersion { + t.Fatal("db not at latest version") + } +} + +// TestVersionNew tests that an existing version zero database is migrated to +// the latest version. +func TestVersionMigrated(t *testing.T) { + tempDirName, err := ioutil.TempDir("", "clientstore") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempDirName) + + createVersionZeroDb(t, tempDirName) + + store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams) + if err != nil { + t.Fatal(err) + } + + ver, err := getDBVersion(store.db) + if err != nil { + t.Fatal(err) + } + + if ver != latestDBVersion { + t.Fatal("db not at latest version") + } +} + +// createVersionZeroDb creates a database with an empty meta bucket. In version +// zero, there was no version key specified yet. +func createVersionZeroDb(t *testing.T, dbPath string) { + path := filepath.Join(dbPath, dbFileName) + bdb, err := bbolt.Open(path, 0600, nil) + if err != nil { + t.Fatal(err) + } + defer bdb.Close() + + err = bdb.Update(func(tx *bbolt.Tx) error { + _, err := tx.CreateBucket(metaBucketKey) + return err + }) + if err != nil { + t.Fatal(err) + } +} diff --git a/loopdb/swapstate.go b/loopdb/swapstate.go index db795a1..eb10f3f 100644 --- a/loopdb/swapstate.go +++ b/loopdb/swapstate.go @@ -1,5 +1,7 @@ package loopdb +import "github.com/btcsuite/btcutil" + // SwapState indicates the current state of a swap. This enumeration is the // union of loop in and loop out states. A single type is used for both swap // types to be able to reduce code duplication that would otherwise be required. @@ -125,3 +127,24 @@ func (s SwapState) String() string { return "Unknown" } } + +// SwapCost is a breakdown of the final swap costs. +type SwapCost struct { + // Swap is the amount paid to the server. + Server btcutil.Amount + + // Onchain is the amount paid to miners for the onchain tx. + Onchain btcutil.Amount + + // Offchain is the amount paid in routing fees. + Offchain btcutil.Amount +} + +// SwapStateData is all persistent data to describe the current swap state. +type SwapStateData struct { + // SwapState is the state the swap is in. + State SwapState + + // Cost are the accrued (final) costs so far. + Cost SwapCost +} diff --git a/loopin.go b/loopin.go index 050c180..cc9a9f9 100644 --- a/loopin.go +++ b/loopin.go @@ -261,10 +261,11 @@ func (s *loopInSwap) execute(mainCtx context.Context, } s.log.Infof("Loop in swap completed: %v "+ - "(final cost: server %v, onchain %v)", + "(final cost: server %v, onchain %v, offchain %v)", s.state, s.cost.Server, s.cost.Onchain, + s.cost.Offchain, ) return nil @@ -616,7 +617,13 @@ func (s *loopInSwap) publishTimeoutTx(ctx context.Context, // persistState updates the swap state and sends out an update notification. func (s *loopInSwap) persistState(ctx context.Context) error { // Update state in store. - err := s.store.UpdateLoopIn(s.hash, s.lastUpdateTime, s.state) + err := s.store.UpdateLoopIn( + s.hash, s.lastUpdateTime, + loopdb.SwapStateData{ + State: s.state, + Cost: s.cost, + }, + ) if err != nil { return err } diff --git a/loopin_test.go b/loopin_test.go index 35cc717..a2ae55b 100644 --- a/loopin_test.go +++ b/loopin_test.go @@ -248,7 +248,9 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool) { Loop: loopdb.Loop{ Events: []*loopdb.LoopEvent{ { - State: state, + SwapStateData: loopdb.SwapStateData{ + State: state, + }, }, }, Hash: testPreimage.Hash(), diff --git a/loopout.go b/loopout.go index a7dcacf..f2129c8 100644 --- a/loopout.go +++ b/loopout.go @@ -224,6 +224,7 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error { continue } s.cost.Server += result.PaidAmt + s.cost.Offchain += result.PaidFee case result := <-s.prePaymentChan: s.prePaymentChan = nil @@ -235,6 +236,7 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error { continue } s.cost.Server += result.PaidAmt + s.cost.Offchain += result.PaidFee case <-globalCtx.Done(): return globalCtx.Err() @@ -243,10 +245,11 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error { // Mark swap completed in store. s.log.Infof("Swap completed: %v "+ - "(final cost: server %v, onchain %v)", + "(final cost: server %v, onchain %v, offchain %v)", s.state, s.cost.Server, s.cost.Onchain, + s.cost.Offchain, ) return s.persistState(globalCtx) @@ -342,7 +345,13 @@ func (s *loopOutSwap) persistState(ctx context.Context) error { s.lastUpdateTime = updateTime // Update state in store. - err := s.store.UpdateLoopOut(s.hash, updateTime, s.state) + err := s.store.UpdateLoopOut( + s.hash, updateTime, + loopdb.SwapStateData{ + State: s.state, + Cost: s.cost, + }, + ) if err != nil { return err } @@ -441,6 +450,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) ( return nil, nil } s.cost.Server += result.PaidAmt + s.cost.Offchain += result.PaidFee // If the prepay fails, abandon the swap. Because we // didn't reveal the preimage, the swap payment will be @@ -455,6 +465,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) ( return nil, nil } s.cost.Server += result.PaidAmt + s.cost.Offchain += result.PaidFee // Unexpected error on the confirm channel happened, // abandon the swap. diff --git a/looprpc/client.pb.go b/looprpc/client.pb.go index 3ebbeac..6689e21 100644 --- a/looprpc/client.pb.go +++ b/looprpc/client.pb.go @@ -46,7 +46,7 @@ func (x SwapType) String() string { return proto.EnumName(SwapType_name, int32(x)) } func (SwapType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{0} + return fileDescriptor_client_cce8684ac06bdedc, []int{0} } type SwapState int32 @@ -103,7 +103,7 @@ func (x SwapState) String() string { return proto.EnumName(SwapState_name, int32(x)) } func (SwapState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{1} + return fileDescriptor_client_cce8684ac06bdedc, []int{1} } type LoopOutRequest struct { @@ -161,7 +161,7 @@ func (m *LoopOutRequest) Reset() { *m = LoopOutRequest{} } func (m *LoopOutRequest) String() string { return proto.CompactTextString(m) } func (*LoopOutRequest) ProtoMessage() {} func (*LoopOutRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{0} + return fileDescriptor_client_cce8684ac06bdedc, []int{0} } func (m *LoopOutRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LoopOutRequest.Unmarshal(m, b) @@ -274,7 +274,7 @@ func (m *LoopInRequest) Reset() { *m = LoopInRequest{} } func (m *LoopInRequest) String() string { return proto.CompactTextString(m) } func (*LoopInRequest) ProtoMessage() {} func (*LoopInRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{1} + return fileDescriptor_client_cce8684ac06bdedc, []int{1} } func (m *LoopInRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LoopInRequest.Unmarshal(m, b) @@ -346,7 +346,7 @@ func (m *SwapResponse) Reset() { *m = SwapResponse{} } func (m *SwapResponse) String() string { return proto.CompactTextString(m) } func (*SwapResponse) ProtoMessage() {} func (*SwapResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{2} + return fileDescriptor_client_cce8684ac06bdedc, []int{2} } func (m *SwapResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SwapResponse.Unmarshal(m, b) @@ -390,7 +390,7 @@ func (m *MonitorRequest) Reset() { *m = MonitorRequest{} } func (m *MonitorRequest) String() string { return proto.CompactTextString(m) } func (*MonitorRequest) ProtoMessage() {} func (*MonitorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{3} + return fileDescriptor_client_cce8684ac06bdedc, []int{3} } func (m *MonitorRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MonitorRequest.Unmarshal(m, b) @@ -433,7 +433,13 @@ type SwapStatus struct { LastUpdateTime int64 `protobuf:"varint,6,opt,name=last_update_time,json=lastUpdateTime,proto3" json:"last_update_time,omitempty"` // * // Htlc address. - HtlcAddress string `protobuf:"bytes,7,opt,name=htlc_address,json=htlcAddress,proto3" json:"htlc_address,omitempty"` + HtlcAddress string `protobuf:"bytes,7,opt,name=htlc_address,json=htlcAddress,proto3" json:"htlc_address,omitempty"` + // / Swap server cost + CostServer int64 `protobuf:"varint,8,opt,name=cost_server,json=costServer,proto3" json:"cost_server,omitempty"` + // On-chain transaction cost + CostOnchain int64 `protobuf:"varint,9,opt,name=cost_onchain,json=costOnchain,proto3" json:"cost_onchain,omitempty"` + // Off-chain routing fees + CostOffchain int64 `protobuf:"varint,10,opt,name=cost_offchain,json=costOffchain,proto3" json:"cost_offchain,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -443,7 +449,7 @@ func (m *SwapStatus) Reset() { *m = SwapStatus{} } func (m *SwapStatus) String() string { return proto.CompactTextString(m) } func (*SwapStatus) ProtoMessage() {} func (*SwapStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{4} + return fileDescriptor_client_cce8684ac06bdedc, []int{4} } func (m *SwapStatus) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SwapStatus.Unmarshal(m, b) @@ -512,6 +518,27 @@ func (m *SwapStatus) GetHtlcAddress() string { return "" } +func (m *SwapStatus) GetCostServer() int64 { + if m != nil { + return m.CostServer + } + return 0 +} + +func (m *SwapStatus) GetCostOnchain() int64 { + if m != nil { + return m.CostOnchain + } + return 0 +} + +func (m *SwapStatus) GetCostOffchain() int64 { + if m != nil { + return m.CostOffchain + } + return 0 +} + type TermsRequest struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -522,7 +549,7 @@ func (m *TermsRequest) Reset() { *m = TermsRequest{} } func (m *TermsRequest) String() string { return proto.CompactTextString(m) } func (*TermsRequest) ProtoMessage() {} func (*TermsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{5} + return fileDescriptor_client_cce8684ac06bdedc, []int{5} } func (m *TermsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TermsRequest.Unmarshal(m, b) @@ -574,7 +601,7 @@ func (m *TermsResponse) Reset() { *m = TermsResponse{} } func (m *TermsResponse) String() string { return proto.CompactTextString(m) } func (*TermsResponse) ProtoMessage() {} func (*TermsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{6} + return fileDescriptor_client_cce8684ac06bdedc, []int{6} } func (m *TermsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TermsResponse.Unmarshal(m, b) @@ -656,7 +683,7 @@ func (m *QuoteRequest) Reset() { *m = QuoteRequest{} } func (m *QuoteRequest) String() string { return proto.CompactTextString(m) } func (*QuoteRequest) ProtoMessage() {} func (*QuoteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{7} + return fileDescriptor_client_cce8684ac06bdedc, []int{7} } func (m *QuoteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QuoteRequest.Unmarshal(m, b) @@ -702,7 +729,7 @@ func (m *QuoteResponse) Reset() { *m = QuoteResponse{} } func (m *QuoteResponse) String() string { return proto.CompactTextString(m) } func (*QuoteResponse) ProtoMessage() {} func (*QuoteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_client_ba4b73c10b9bbc2a, []int{8} + return fileDescriptor_client_cce8684ac06bdedc, []int{8} } func (m *QuoteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QuoteResponse.Unmarshal(m, b) @@ -1099,67 +1126,70 @@ var _SwapClient_serviceDesc = grpc.ServiceDesc{ Metadata: "client.proto", } -func init() { proto.RegisterFile("client.proto", fileDescriptor_client_ba4b73c10b9bbc2a) } - -var fileDescriptor_client_ba4b73c10b9bbc2a = []byte{ - // 941 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xdd, 0x8e, 0xda, 0x46, - 0x18, 0x8d, 0x0d, 0xbb, 0xc0, 0xb7, 0xc6, 0xc0, 0x6c, 0xb2, 0xa1, 0xb4, 0x91, 0xa8, 0xdb, 0xa4, - 0x68, 0x2f, 0x96, 0x76, 0x73, 0x51, 0xb5, 0x37, 0x15, 0x01, 0x27, 0x6b, 0x89, 0x5d, 0xa8, 0x61, - 0x23, 0xf5, 0xca, 0x9a, 0xc0, 0x64, 0x63, 0xc9, 0xf6, 0x38, 0xf6, 0x38, 0x61, 0x55, 0xf5, 0xa6, - 0x6f, 0xd0, 0xf6, 0x4d, 0xaa, 0xbe, 0x49, 0x5f, 0xa1, 0xaf, 0xd0, 0xfb, 0x6a, 0x7e, 0x70, 0x6c, - 0xe8, 0xde, 0xe4, 0xce, 0x9c, 0x39, 0x73, 0xe6, 0xfb, 0xce, 0x9c, 0x6f, 0x00, 0x63, 0x15, 0xf8, - 0x24, 0x62, 0x67, 0x71, 0x42, 0x19, 0x45, 0xb5, 0x80, 0xd2, 0x38, 0x89, 0x57, 0xbd, 0xcf, 0x6e, - 0x28, 0xbd, 0x09, 0xc8, 0x10, 0xc7, 0xfe, 0x10, 0x47, 0x11, 0x65, 0x98, 0xf9, 0x34, 0x4a, 0x25, - 0xcd, 0xfa, 0x53, 0x07, 0x73, 0x4a, 0x69, 0x3c, 0xcb, 0x98, 0x4b, 0xde, 0x66, 0x24, 0x65, 0xa8, - 0x0d, 0x15, 0x1c, 0xb2, 0xae, 0xd6, 0xd7, 0x06, 0x15, 0x97, 0x7f, 0x22, 0x04, 0xd5, 0x35, 0x49, - 0x59, 0x57, 0xef, 0x6b, 0x83, 0x86, 0x2b, 0xbe, 0xd1, 0x10, 0xee, 0x87, 0x78, 0xe3, 0xa5, 0xef, - 0x71, 0xec, 0x25, 0x34, 0x63, 0x7e, 0x74, 0xe3, 0xbd, 0x26, 0xa4, 0x5b, 0x11, 0xdb, 0x3a, 0x21, - 0xde, 0x2c, 0xde, 0xe3, 0xd8, 0x95, 0x2b, 0xcf, 0x09, 0x41, 0x4f, 0xe1, 0x84, 0x6f, 0x88, 0x13, - 0x12, 0xe3, 0xdb, 0xd2, 0x96, 0xaa, 0xd8, 0x72, 0x1c, 0xe2, 0xcd, 0x5c, 0x2c, 0x16, 0x36, 0xf5, - 0xc1, 0xc8, 0x4f, 0xe1, 0xd4, 0x03, 0x41, 0x05, 0xa5, 0xce, 0x19, 0x5f, 0x82, 0x59, 0x90, 0xe5, - 0x85, 0x1f, 0x0a, 0x8e, 0x91, 0xcb, 0x8d, 0x42, 0x86, 0x2c, 0x68, 0x72, 0x56, 0xe8, 0x47, 0x24, - 0x11, 0x42, 0x35, 0x41, 0x3a, 0x0a, 0xf1, 0xe6, 0x92, 0x63, 0x5c, 0x69, 0x00, 0x6d, 0xee, 0x99, - 0x47, 0x33, 0xe6, 0xad, 0xde, 0xe0, 0x28, 0x22, 0x41, 0xb7, 0xde, 0xd7, 0x06, 0x55, 0xd7, 0x0c, - 0xa4, 0x43, 0x63, 0x89, 0x5a, 0x7f, 0x69, 0xd0, 0xe4, 0xa6, 0x39, 0xd1, 0xdd, 0x9e, 0xed, 0x56, - 0xae, 0xef, 0x55, 0xbe, 0x57, 0x53, 0x65, 0xbf, 0xa6, 0x27, 0xd0, 0x12, 0x35, 0xf9, 0x51, 0x5e, - 0x52, 0x55, 0x94, 0xd4, 0x0c, 0xc4, 0xf9, 0xaa, 0x22, 0xf4, 0x05, 0x34, 0xc9, 0x86, 0x91, 0x24, - 0xc2, 0x81, 0xf7, 0x86, 0x05, 0x2b, 0x61, 0x54, 0xdd, 0x35, 0xb6, 0xe0, 0x05, 0x0b, 0x56, 0xd6, - 0x08, 0x0c, 0x71, 0x27, 0x24, 0x8d, 0x69, 0x94, 0x12, 0x64, 0x82, 0xee, 0xaf, 0x45, 0xcd, 0x0d, - 0x57, 0xf7, 0xd7, 0xe8, 0x73, 0x30, 0xf8, 0x5e, 0x0f, 0xaf, 0xd7, 0x09, 0x49, 0x53, 0x75, 0xdd, - 0x47, 0x1c, 0x1b, 0x49, 0xc8, 0x6a, 0x83, 0x79, 0x49, 0x23, 0x9f, 0xd1, 0x44, 0x75, 0x6e, 0xfd, - 0xab, 0x01, 0x70, 0xd5, 0x05, 0xc3, 0x2c, 0x4b, 0xff, 0xc7, 0x08, 0x79, 0x8a, 0x9e, 0x9f, 0xf2, - 0x18, 0xaa, 0xec, 0x36, 0x96, 0xdd, 0x9a, 0xe7, 0x9d, 0x33, 0x95, 0xd3, 0x33, 0x2e, 0xb2, 0xbc, - 0x8d, 0x89, 0x2b, 0x96, 0xd1, 0x00, 0x0e, 0x52, 0x86, 0x99, 0x4c, 0x87, 0x79, 0x8e, 0x4a, 0x3c, - 0x7e, 0x18, 0x71, 0x25, 0x01, 0x7d, 0x05, 0x2d, 0x3f, 0xf2, 0x99, 0x2f, 0x72, 0xed, 0x31, 0x3f, - 0xdc, 0xc6, 0xc4, 0xfc, 0x00, 0x2f, 0xfd, 0x50, 0x5e, 0x30, 0x4e, 0x99, 0x97, 0xc5, 0x6b, 0xcc, - 0x88, 0x64, 0xca, 0xb0, 0x98, 0x1c, 0xbf, 0x16, 0xb0, 0x60, 0xee, 0x3a, 0x51, 0xdb, 0x77, 0xc2, - 0x04, 0x63, 0x49, 0x92, 0x30, 0xdd, 0xfa, 0xf0, 0x9b, 0x0e, 0x4d, 0x05, 0x28, 0x7b, 0x4f, 0xa1, - 0x23, 0x6e, 0x3f, 0xc6, 0xb7, 0x21, 0x89, 0x98, 0x27, 0x46, 0x48, 0xba, 0xdd, 0xe2, 0x0b, 0x73, - 0x89, 0x4f, 0x78, 0x7e, 0x2c, 0x68, 0x6e, 0x93, 0xe2, 0xbd, 0xc2, 0xe9, 0x36, 0x2e, 0x47, 0xa9, - 0xcc, 0xca, 0x33, 0x9c, 0x92, 0x12, 0x27, 0xe1, 0xce, 0x54, 0x4a, 0x1c, 0x97, 0x7b, 0xf1, 0x08, - 0xa0, 0x30, 0x09, 0x72, 0xb0, 0x1a, 0x71, 0x3e, 0x06, 0x4f, 0xa0, 0x15, 0xfa, 0x91, 0x0c, 0x25, - 0x0e, 0x69, 0x16, 0x31, 0x65, 0x55, 0x33, 0xf4, 0x23, 0x6e, 0xec, 0x48, 0x80, 0x82, 0xb7, 0x0d, - 0xaf, 0xe2, 0x1d, 0x2a, 0x9e, 0xcc, 0xaf, 0xe2, 0x3d, 0x02, 0x58, 0x05, 0xec, 0x9d, 0xb7, 0x26, - 0x01, 0xc3, 0xc2, 0xa5, 0x03, 0xb7, 0xc1, 0x91, 0x09, 0x07, 0xac, 0x3e, 0x18, 0x3f, 0x66, 0x94, - 0x91, 0x3b, 0xa7, 0xc4, 0x7a, 0x0d, 0x4d, 0xc5, 0x50, 0xa6, 0x7d, 0x02, 0xf5, 0x7c, 0x64, 0x24, - 0xaf, 0xa6, 0xfa, 0xdb, 0xe9, 0x4d, 0xdf, 0xed, 0xed, 0x53, 0x68, 0xec, 0x8e, 0x52, 0x3d, 0x54, - 0x73, 0x74, 0xfa, 0x18, 0xea, 0xdb, 0x7c, 0x21, 0x03, 0xea, 0xd3, 0xd9, 0x6c, 0xee, 0xcd, 0xae, - 0x97, 0xed, 0x7b, 0xe8, 0x08, 0x6a, 0xe2, 0x97, 0x73, 0xd5, 0xd6, 0x4e, 0x53, 0x68, 0xe4, 0xf1, - 0x42, 0x4d, 0x68, 0x38, 0x57, 0xce, 0xd2, 0x19, 0x2d, 0xed, 0x49, 0xfb, 0x1e, 0x7a, 0x00, 0x9d, - 0xb9, 0x6b, 0x3b, 0x97, 0xa3, 0x17, 0xb6, 0xe7, 0xda, 0x2f, 0xed, 0xd1, 0xd4, 0x9e, 0xb4, 0x35, - 0x84, 0xc0, 0xbc, 0x58, 0x4e, 0xc7, 0xde, 0xfc, 0xfa, 0xd9, 0xd4, 0x59, 0x5c, 0xd8, 0x93, 0xb6, - 0xce, 0x35, 0x17, 0xd7, 0xe3, 0xb1, 0xbd, 0x58, 0xb4, 0x2b, 0x08, 0xe0, 0xf0, 0xf9, 0xc8, 0xe1, - 0xe4, 0x2a, 0x3a, 0x86, 0x96, 0x73, 0xf5, 0x72, 0xe6, 0x8c, 0x6d, 0x6f, 0x61, 0x2f, 0x97, 0x1c, - 0x3c, 0x38, 0xff, 0xbd, 0x2a, 0x27, 0x68, 0x2c, 0x9e, 0x6f, 0xe4, 0x42, 0x4d, 0x3d, 0xc8, 0xe8, - 0x61, 0x1e, 0xfa, 0xf2, 0x13, 0xdd, 0x7b, 0x50, 0x9a, 0x86, 0xad, 0x79, 0xd6, 0xc3, 0x5f, 0xff, - 0xfe, 0xe7, 0x0f, 0xbd, 0x63, 0x19, 0xc3, 0x77, 0xdf, 0x0c, 0x39, 0x63, 0x48, 0x33, 0xf6, 0xbd, - 0x76, 0x8a, 0xbe, 0x85, 0x43, 0xf9, 0x5e, 0xa1, 0x93, 0x92, 0x64, 0xfe, 0x80, 0xdd, 0xa1, 0x88, - 0xbe, 0x83, 0x9a, 0x9a, 0xf7, 0x42, 0x31, 0xe5, 0x17, 0xa0, 0x77, 0xbc, 0x37, 0x9a, 0x59, 0xfa, - 0xb5, 0x86, 0x7e, 0x02, 0x43, 0x55, 0x2d, 0xc6, 0x02, 0x7d, 0x38, 0xa1, 0x38, 0x37, 0xbd, 0x93, - 0x5d, 0x58, 0xf5, 0xd2, 0x13, 0xbd, 0xdc, 0x47, 0xa8, 0xd8, 0xcb, 0x90, 0x09, 0x29, 0x2f, 0x97, - 0x16, 0xe1, 0x29, 0x48, 0x17, 0xe3, 0x56, 0x90, 0x2e, 0x65, 0xcc, 0xea, 0x0b, 0xe9, 0x1e, 0xea, - 0x96, 0xa4, 0xdf, 0x72, 0xce, 0xf0, 0x67, 0x1c, 0xb2, 0x5f, 0xd0, 0x0f, 0x60, 0xbe, 0x20, 0x4c, - 0x3a, 0xf4, 0x31, 0xd5, 0x97, 0x04, 0x3e, 0xa6, 0xc6, 0x57, 0x87, 0xe2, 0xef, 0xf9, 0xe9, 0x7f, - 0x01, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x2d, 0xd7, 0x0b, 0xd5, 0x07, 0x00, 0x00, +func init() { proto.RegisterFile("client.proto", fileDescriptor_client_cce8684ac06bdedc) } + +var fileDescriptor_client_cce8684ac06bdedc = []byte{ + // 992 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x4f, 0x73, 0xda, 0x46, + 0x1c, 0x0d, 0x02, 0x1b, 0xf8, 0x59, 0xc8, 0x78, 0x9d, 0x38, 0x94, 0x36, 0x53, 0xaa, 0x36, 0x29, + 0xe3, 0x83, 0x69, 0x9d, 0x43, 0xa7, 0xbd, 0x74, 0x08, 0x28, 0xb1, 0x66, 0xb0, 0xa1, 0x02, 0x67, + 0xa6, 0x27, 0xcd, 0x06, 0xd6, 0xb6, 0x66, 0xa4, 0x5d, 0x45, 0x5a, 0x39, 0x78, 0x3a, 0xbd, 0xf4, + 0x1b, 0xb4, 0xfd, 0x26, 0x9d, 0x7e, 0x93, 0xde, 0x7b, 0xea, 0x07, 0xe9, 0xec, 0x1f, 0x14, 0x04, + 0xf1, 0x25, 0x37, 0xfc, 0xf6, 0xed, 0xdb, 0xdf, 0xfe, 0x7e, 0xef, 0xad, 0x0c, 0xe6, 0x3c, 0x0c, + 0x08, 0xe5, 0x27, 0x71, 0xc2, 0x38, 0x43, 0xd5, 0x90, 0xb1, 0x38, 0x89, 0xe7, 0xed, 0xcf, 0xae, + 0x19, 0xbb, 0x0e, 0x49, 0x0f, 0xc7, 0x41, 0x0f, 0x53, 0xca, 0x38, 0xe6, 0x01, 0xa3, 0xa9, 0xa2, + 0xd9, 0x7f, 0x19, 0x60, 0x8d, 0x18, 0x8b, 0xc7, 0x19, 0xf7, 0xc8, 0xdb, 0x8c, 0xa4, 0x1c, 0x35, + 0xa1, 0x8c, 0x23, 0xde, 0x2a, 0x75, 0x4a, 0xdd, 0xb2, 0x27, 0x7e, 0x22, 0x04, 0x95, 0x05, 0x49, + 0x79, 0xcb, 0xe8, 0x94, 0xba, 0x75, 0x4f, 0xfe, 0x46, 0x3d, 0x78, 0x18, 0xe1, 0xa5, 0x9f, 0xbe, + 0xc3, 0xb1, 0x9f, 0xb0, 0x8c, 0x07, 0xf4, 0xda, 0xbf, 0x22, 0xa4, 0x55, 0x96, 0xdb, 0x0e, 0x22, + 0xbc, 0x9c, 0xbe, 0xc3, 0xb1, 0xa7, 0x56, 0x5e, 0x12, 0x82, 0x9e, 0xc3, 0x91, 0xd8, 0x10, 0x27, + 0x24, 0xc6, 0x77, 0x85, 0x2d, 0x15, 0xb9, 0xe5, 0x30, 0xc2, 0xcb, 0x89, 0x5c, 0x5c, 0xdb, 0xd4, + 0x01, 0x33, 0x3f, 0x45, 0x50, 0x77, 0x24, 0x15, 0xb4, 0xba, 0x60, 0x7c, 0x05, 0xd6, 0x9a, 0xac, + 0x28, 0x7c, 0x57, 0x72, 0xcc, 0x5c, 0xae, 0x1f, 0x71, 0x64, 0x43, 0x43, 0xb0, 0xa2, 0x80, 0x92, + 0x44, 0x0a, 0x55, 0x25, 0x69, 0x2f, 0xc2, 0xcb, 0x73, 0x81, 0x09, 0xa5, 0x2e, 0x34, 0x45, 0xcf, + 0x7c, 0x96, 0x71, 0x7f, 0x7e, 0x83, 0x29, 0x25, 0x61, 0xab, 0xd6, 0x29, 0x75, 0x2b, 0x9e, 0x15, + 0xaa, 0x0e, 0x0d, 0x14, 0x6a, 0xff, 0x5d, 0x82, 0x86, 0x68, 0x9a, 0x4b, 0xef, 0xef, 0xd9, 0x66, + 0xe5, 0xc6, 0x56, 0xe5, 0x5b, 0x35, 0x95, 0xb7, 0x6b, 0x7a, 0x06, 0xfb, 0xb2, 0xa6, 0x80, 0xe6, + 0x25, 0x55, 0x64, 0x49, 0x8d, 0x50, 0x9e, 0xaf, 0x2b, 0x42, 0x5f, 0x42, 0x83, 0x2c, 0x39, 0x49, + 0x28, 0x0e, 0xfd, 0x1b, 0x1e, 0xce, 0x65, 0xa3, 0x6a, 0x9e, 0xb9, 0x02, 0xcf, 0x78, 0x38, 0xb7, + 0xfb, 0x60, 0xca, 0x99, 0x90, 0x34, 0x66, 0x34, 0x25, 0xc8, 0x02, 0x23, 0x58, 0xc8, 0x9a, 0xeb, + 0x9e, 0x11, 0x2c, 0xd0, 0x17, 0x60, 0x8a, 0xbd, 0x3e, 0x5e, 0x2c, 0x12, 0x92, 0xa6, 0x7a, 0xdc, + 0x7b, 0x02, 0xeb, 0x2b, 0xc8, 0x6e, 0x82, 0x75, 0xce, 0x68, 0xc0, 0x59, 0xa2, 0x6f, 0x6e, 0xff, + 0x6b, 0x00, 0x08, 0xd5, 0x29, 0xc7, 0x3c, 0x4b, 0x3f, 0xd0, 0x08, 0x75, 0x8a, 0x91, 0x9f, 0xf2, + 0x14, 0x2a, 0xfc, 0x2e, 0x56, 0xb7, 0xb5, 0x4e, 0x0f, 0x4e, 0xb4, 0x4f, 0x4f, 0x84, 0xc8, 0xec, + 0x2e, 0x26, 0x9e, 0x5c, 0x46, 0x5d, 0xd8, 0x49, 0x39, 0xe6, 0xca, 0x1d, 0xd6, 0x29, 0x2a, 0xf0, + 0xc4, 0x61, 0xc4, 0x53, 0x04, 0xf4, 0x35, 0xec, 0x07, 0x34, 0xe0, 0x81, 0xf4, 0xb5, 0xcf, 0x83, + 0x68, 0x65, 0x13, 0xeb, 0x3d, 0x3c, 0x0b, 0x22, 0x35, 0x60, 0x9c, 0x72, 0x3f, 0x8b, 0x17, 0x98, + 0x13, 0xc5, 0x54, 0x66, 0xb1, 0x04, 0x7e, 0x29, 0x61, 0xc9, 0xdc, 0xec, 0x44, 0x75, 0xab, 0x13, + 0xe8, 0x73, 0xd8, 0x9b, 0xb3, 0x94, 0xfb, 0x29, 0x49, 0x6e, 0x49, 0x22, 0x8d, 0x52, 0xf6, 0x40, + 0x40, 0x53, 0x89, 0x08, 0x0d, 0x49, 0x60, 0x74, 0x7e, 0x83, 0x03, 0xda, 0xaa, 0xab, 0xe9, 0x0a, + 0x6c, 0xac, 0x20, 0x31, 0x35, 0x45, 0xb9, 0xba, 0x52, 0x1c, 0x50, 0xd6, 0x95, 0x1c, 0x8d, 0xd9, + 0x16, 0x98, 0x33, 0x92, 0x44, 0xe9, 0xaa, 0xe1, 0xbf, 0x1b, 0xd0, 0xd0, 0x80, 0x9e, 0xe3, 0x31, + 0x1c, 0x48, 0x9b, 0xc5, 0xf8, 0x2e, 0x22, 0x94, 0xfb, 0x32, 0xab, 0x6a, 0xac, 0xfb, 0x62, 0x61, + 0xa2, 0xf0, 0xa1, 0x30, 0xaa, 0x0d, 0x8d, 0x95, 0x25, 0xfd, 0x37, 0x38, 0x5d, 0xf9, 0x72, 0x2f, + 0x55, 0xa6, 0x7c, 0x81, 0x53, 0x52, 0xe0, 0x24, 0x62, 0x04, 0xe5, 0x02, 0xc7, 0x13, 0x4d, 0x7f, + 0x02, 0xb0, 0x16, 0x39, 0x95, 0xe0, 0x7a, 0x9c, 0xe7, 0xed, 0x19, 0xec, 0x47, 0x01, 0x55, 0xee, + 0xc7, 0x11, 0xcb, 0x28, 0xd7, 0x33, 0x69, 0x44, 0x01, 0x15, 0x13, 0xec, 0x4b, 0x50, 0xf2, 0x56, + 0x29, 0xd1, 0xbc, 0x5d, 0xcd, 0x53, 0x41, 0xd1, 0xbc, 0x27, 0x00, 0xf3, 0x90, 0xdf, 0xfa, 0x0b, + 0x12, 0x72, 0x2c, 0xc7, 0xb1, 0xe3, 0xd5, 0x05, 0x32, 0x14, 0x80, 0xdd, 0x01, 0xf3, 0xa7, 0x8c, + 0x71, 0x72, 0x6f, 0x1c, 0xed, 0x2b, 0x68, 0x68, 0x86, 0x6e, 0xda, 0x27, 0x50, 0xcb, 0xb3, 0xa9, + 0x78, 0x55, 0x7d, 0xbf, 0x8d, 0xbb, 0x19, 0x9b, 0x77, 0xfb, 0x14, 0xea, 0x9b, 0x99, 0xad, 0x45, + 0x3a, 0xb0, 0xc7, 0x4f, 0xa1, 0xb6, 0x32, 0x32, 0x32, 0xa1, 0x36, 0x1a, 0x8f, 0x27, 0xfe, 0xf8, + 0x72, 0xd6, 0x7c, 0x80, 0xf6, 0xa0, 0x2a, 0xff, 0x72, 0x2f, 0x9a, 0xa5, 0xe3, 0x14, 0xea, 0xb9, + 0x8f, 0x51, 0x03, 0xea, 0xee, 0x85, 0x3b, 0x73, 0xfb, 0x33, 0x67, 0xd8, 0x7c, 0x80, 0x1e, 0xc1, + 0xc1, 0xc4, 0x73, 0xdc, 0xf3, 0xfe, 0x2b, 0xc7, 0xf7, 0x9c, 0xd7, 0x4e, 0x7f, 0xe4, 0x0c, 0x9b, + 0x25, 0x84, 0xc0, 0x3a, 0x9b, 0x8d, 0x06, 0xfe, 0xe4, 0xf2, 0xc5, 0xc8, 0x9d, 0x9e, 0x39, 0xc3, + 0xa6, 0x21, 0x34, 0xa7, 0x97, 0x83, 0x81, 0x33, 0x9d, 0x36, 0xcb, 0x08, 0x60, 0xf7, 0x65, 0xdf, + 0x15, 0xe4, 0x0a, 0x3a, 0x84, 0x7d, 0xf7, 0xe2, 0xf5, 0xd8, 0x1d, 0x38, 0xfe, 0xd4, 0x99, 0xcd, + 0x04, 0xb8, 0x73, 0xfa, 0x47, 0x45, 0x45, 0x75, 0x20, 0xbf, 0x13, 0xc8, 0x83, 0xaa, 0x7e, 0xf9, + 0xd1, 0xe3, 0x3c, 0x5d, 0xc5, 0x6f, 0x41, 0xfb, 0x51, 0x21, 0x76, 0xab, 0xe6, 0xd9, 0x8f, 0x7f, + 0xfb, 0xe7, 0xbf, 0x3f, 0x8d, 0x03, 0xdb, 0xec, 0xdd, 0x7e, 0xdb, 0x13, 0x8c, 0x1e, 0xcb, 0xf8, + 0x0f, 0xa5, 0x63, 0xf4, 0x1d, 0xec, 0xaa, 0x87, 0x11, 0x1d, 0x15, 0x24, 0xf3, 0x97, 0xf2, 0x1e, + 0x45, 0xf4, 0x3d, 0x54, 0xf5, 0xc3, 0xb2, 0x56, 0x4c, 0xf1, 0xa9, 0x69, 0x1f, 0x6e, 0xbd, 0x01, + 0x59, 0xfa, 0x4d, 0x09, 0xfd, 0x0c, 0xa6, 0xae, 0x5a, 0xc6, 0x02, 0xbd, 0x3f, 0x61, 0x3d, 0x37, + 0xed, 0xa3, 0x4d, 0x58, 0xdf, 0xa5, 0x2d, 0xef, 0xf2, 0x10, 0xa1, 0xf5, 0xbb, 0xf4, 0xb8, 0x94, + 0xf2, 0x73, 0x69, 0x69, 0x9e, 0x35, 0xe9, 0x75, 0xbb, 0xad, 0x49, 0x17, 0x3c, 0x66, 0x77, 0xa4, + 0x74, 0x1b, 0xb5, 0x0a, 0xd2, 0x6f, 0x05, 0xa7, 0xf7, 0x0b, 0x8e, 0xf8, 0xaf, 0xe8, 0x47, 0xb0, + 0x5e, 0x11, 0xae, 0x3a, 0xf4, 0x31, 0xd5, 0x17, 0x04, 0x3e, 0xa6, 0xc6, 0x37, 0xbb, 0xf2, 0xff, + 0x80, 0xe7, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0xf8, 0xf2, 0xb9, 0x76, 0x3e, 0x08, 0x00, 0x00, } diff --git a/looprpc/client.proto b/looprpc/client.proto index 42f17b3..5665e86 100644 --- a/looprpc/client.proto +++ b/looprpc/client.proto @@ -221,6 +221,15 @@ message SwapStatus { Htlc address. */ string htlc_address = 7; + + /// Swap server cost + int64 cost_server = 8; + + // On-chain transaction cost + int64 cost_onchain = 9; + + // Off-chain routing fees + int64 cost_offchain = 10; } enum SwapType { diff --git a/looprpc/client.swagger.json b/looprpc/client.swagger.json index 1f13322..f80e5f9 100644 --- a/looprpc/client.swagger.json +++ b/looprpc/client.swagger.json @@ -210,6 +210,21 @@ "htlc_address": { "type": "string", "description": "*\nHtlc address." + }, + "cost_server": { + "type": "string", + "format": "int64", + "title": "/ Swap server cost" + }, + "cost_onchain": { + "type": "string", + "format": "int64", + "title": "On-chain transaction cost" + }, + "cost_offchain": { + "type": "string", + "format": "int64", + "title": "Off-chain routing fees" } } }, diff --git a/store_mock_test.go b/store_mock_test.go index 9b33014..70c53dd 100644 --- a/store_mock_test.go +++ b/store_mock_test.go @@ -13,14 +13,14 @@ import ( // storeMock implements a mock client swap store. type storeMock struct { loopOutSwaps map[lntypes.Hash]*loopdb.LoopOutContract - loopOutUpdates map[lntypes.Hash][]loopdb.SwapState + loopOutUpdates map[lntypes.Hash][]loopdb.SwapStateData loopOutStoreChan chan loopdb.LoopOutContract - loopOutUpdateChan chan loopdb.SwapState + loopOutUpdateChan chan loopdb.SwapStateData loopInSwaps map[lntypes.Hash]*loopdb.LoopInContract - loopInUpdates map[lntypes.Hash][]loopdb.SwapState + loopInUpdates map[lntypes.Hash][]loopdb.SwapStateData loopInStoreChan chan loopdb.LoopInContract - loopInUpdateChan chan loopdb.SwapState + loopInUpdateChan chan loopdb.SwapStateData t *testing.T } @@ -34,14 +34,14 @@ type finishData struct { func newStoreMock(t *testing.T) *storeMock { return &storeMock{ loopOutStoreChan: make(chan loopdb.LoopOutContract, 1), - loopOutUpdateChan: make(chan loopdb.SwapState, 1), + loopOutUpdateChan: make(chan loopdb.SwapStateData, 1), loopOutSwaps: make(map[lntypes.Hash]*loopdb.LoopOutContract), - loopOutUpdates: make(map[lntypes.Hash][]loopdb.SwapState), + loopOutUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData), loopInStoreChan: make(chan loopdb.LoopInContract, 1), - loopInUpdateChan: make(chan loopdb.SwapState, 1), + loopInUpdateChan: make(chan loopdb.SwapStateData, 1), loopInSwaps: make(map[lntypes.Hash]*loopdb.LoopInContract), - loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapState), + loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData), t: t, } } @@ -57,7 +57,7 @@ func (s *storeMock) FetchLoopOutSwaps() ([]*loopdb.LoopOut, error) { events := make([]*loopdb.LoopEvent, len(updates)) for i, u := range updates { events[i] = &loopdb.LoopEvent{ - State: u, + SwapStateData: u, } } @@ -86,7 +86,7 @@ func (s *storeMock) CreateLoopOut(hash lntypes.Hash, } s.loopOutSwaps[hash] = swap - s.loopOutUpdates[hash] = []loopdb.SwapState{} + s.loopOutUpdates[hash] = []loopdb.SwapStateData{} s.loopOutStoreChan <- *swap return nil @@ -101,7 +101,7 @@ func (s *storeMock) FetchLoopInSwaps() ([]*loopdb.LoopIn, error) { events := make([]*loopdb.LoopEvent, len(updates)) for i, u := range updates { events[i] = &loopdb.LoopEvent{ - State: u, + SwapStateData: u, } } @@ -130,7 +130,7 @@ func (s *storeMock) CreateLoopIn(hash lntypes.Hash, } s.loopInSwaps[hash] = swap - s.loopInUpdates[hash] = []loopdb.SwapState{} + s.loopInUpdates[hash] = []loopdb.SwapStateData{} s.loopInStoreChan <- *swap return nil @@ -142,7 +142,7 @@ func (s *storeMock) CreateLoopIn(hash lntypes.Hash, // // NOTE: Part of the loopdb.SwapStore interface. func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time, - state loopdb.SwapState) error { + state loopdb.SwapStateData) error { updates, ok := s.loopOutUpdates[hash] if !ok { @@ -162,7 +162,7 @@ func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time, // // NOTE: Part of the loopdb.SwapStore interface. func (s *storeMock) UpdateLoopIn(hash lntypes.Hash, time time.Time, - state loopdb.SwapState) error { + state loopdb.SwapStateData) error { updates, ok := s.loopInUpdates[hash] if !ok { @@ -215,7 +215,7 @@ func (s *storeMock) assertLoopInState(expectedState loopdb.SwapState) { s.t.Helper() state := <-s.loopOutUpdateChan - if state != expectedState { + if state.State != expectedState { s.t.Fatalf("unexpected state") } } @@ -226,7 +226,7 @@ func (s *storeMock) assertStorePreimageReveal() { select { case state := <-s.loopOutUpdateChan: - if state != loopdb.StatePreimageRevealed { + if state.State != loopdb.StatePreimageRevealed { s.t.Fatalf("unexpected state") } case <-time.After(test.Timeout): @@ -239,7 +239,7 @@ func (s *storeMock) assertStoreFinished(expectedResult loopdb.SwapState) { select { case state := <-s.loopOutUpdateChan: - if state != expectedResult { + if state.State != expectedResult { s.t.Fatalf("expected result %v, but got %v", expectedResult, state) } diff --git a/swap.go b/swap.go index 74a0276..95f6227 100644 --- a/swap.go +++ b/swap.go @@ -19,7 +19,7 @@ type swapKit struct { log *SwapLog lastUpdateTime time.Time - cost SwapCost + cost loopdb.SwapCost state loopdb.SwapState executeConfig swapConfig @@ -68,8 +68,11 @@ func (s *swapKit) sendUpdate(ctx context.Context) error { SwapHash: s.hash, SwapType: s.swapType, LastUpdate: s.lastUpdateTime, - State: s.state, - HtlcAddress: s.htlc.Address, + SwapStateData: loopdb.SwapStateData{ + State: s.state, + Cost: s.cost, + }, + HtlcAddress: s.htlc.Address, } s.log.Infof("state %v", info.State) diff --git a/testcontext_test.go b/testcontext_test.go index 9dca8ae..6e3ab7e 100644 --- a/testcontext_test.go +++ b/testcontext_test.go @@ -79,9 +79,9 @@ func createClientTestContext(t *testing.T, for _, s := range pendingSwaps { store.loopOutSwaps[s.Hash] = s.Contract - updates := []loopdb.SwapState{} + updates := []loopdb.SwapStateData{} for _, e := range s.Events { - updates = append(updates, e.State) + updates = append(updates, e.SwapStateData) } store.loopOutUpdates[s.Hash] = updates }