Browse Source

multi: store swap cost in database

pull/55/head
Joost Jager 2 years ago
parent
commit
6efa62347b
No known key found for this signature in database GPG Key ID: A61B9D4C393C59C7
9 changed files with 146 additions and 15 deletions
  1. +12
    -1
      cmd/loopd/view.go
  2. +0
    -9
      interface.go
  3. +25
    -1
      loopdb/loop.go
  4. +1
    -1
      loopdb/meta.go
  5. +78
    -0
      loopdb/migration_01_costs.go
  6. +18
    -0
      loopdb/swapstate.go
  7. +3
    -1
      loopin.go
  8. +7
    -1
      loopout.go
  9. +2
    -1
      swap.go

+ 12
- 1
cmd/loopd/view.go View File

@ -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()
}

+ 0
- 9
interface.go View File

@ -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 {

+ 25
- 1
loopdb/loop.go View File

@ -94,7 +94,19 @@ func serializeLoopEvent(time time.Time, state SwapStateData) (
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
}
@ -118,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
}

+ 1
- 1
loopdb/meta.go View File

@ -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))
)

+ 78
- 0
loopdb/migration_01_costs.go View File

@ -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
})
}

+ 18
- 0
loopdb/swapstate.go View File

@ -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.
@ -126,7 +128,23 @@ func (s SwapState) String() string {
}
}
// 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
}

+ 3
- 1
loopin.go View File

@ -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
@ -620,6 +621,7 @@ func (s *loopInSwap) persistState(ctx context.Context) error {
s.hash, s.lastUpdateTime,
loopdb.SwapStateData{
State: s.state,
Cost: s.cost,
},
)
if err != nil {

+ 7
- 1
loopout.go View File

@ -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)
@ -346,6 +349,7 @@ func (s *loopOutSwap) persistState(ctx context.Context) error {
s.hash, updateTime,
loopdb.SwapStateData{
State: s.state,
Cost: s.cost,
},
)
if err != nil {
@ -446,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
@ -460,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.

+ 2
- 1
swap.go View File

@ -19,7 +19,7 @@ type swapKit struct {
log *SwapLog
lastUpdateTime time.Time
cost SwapCost
cost loopdb.SwapCost
state loopdb.SwapState
executeConfig
swapConfig
@ -70,6 +70,7 @@ func (s *swapKit) sendUpdate(ctx context.Context) error {
LastUpdate: s.lastUpdateTime,
SwapStateData: loopdb.SwapStateData{
State: s.state,
Cost: s.cost,
},
HtlcAddress: s.htlc.Address,
}

Loading…
Cancel
Save