multi: store swap cost in database

pull/55/head
Joost Jager 5 years ago
parent 24a1b8d642
commit 6efa62347b
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7

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

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

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

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

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

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

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

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

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