mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
multi: store swap cost in database
This commit is contained in:
parent
24a1b8d642
commit
6efa62347b
9 changed files with 146 additions and 15 deletions
|
|
@ -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))
|
||||
)
|
||||
|
|
|
|||
78
loopdb/migration_01_costs.go
Normal file
78
loopdb/migration_01_costs.go
Normal 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
|
||||
})
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
3
swap.go
3
swap.go
|
|
@ -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…
Add table
Add a link
Reference in a new issue