Merge pull request #55 from joostjager/report-cost

multi: persist swap cost and report over rpc
pull/56/head
Olaoluwa Osuntokun 5 years ago committed by GitHub
commit 7fd2f1176e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -138,12 +138,12 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
} }
swaps = append(swaps, &SwapInfo{ swaps = append(swaps, &SwapInfo{
SwapType: TypeOut, SwapType: TypeOut,
SwapContract: swp.Contract.SwapContract, SwapContract: swp.Contract.SwapContract,
State: swp.State(), SwapStateData: swp.State(),
SwapHash: swp.Hash, SwapHash: swp.Hash,
LastUpdate: swp.LastUpdateTime(), LastUpdate: swp.LastUpdateTime(),
HtlcAddress: htlc.Address, HtlcAddress: htlc.Address,
}) })
} }
@ -158,12 +158,12 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
} }
swaps = append(swaps, &SwapInfo{ swaps = append(swaps, &SwapInfo{
SwapType: TypeIn, SwapType: TypeIn,
SwapContract: swp.Contract.SwapContract, SwapContract: swp.Contract.SwapContract,
State: swp.State(), SwapStateData: swp.State(),
SwapHash: swp.Hash, SwapHash: swp.Hash,
LastUpdate: swp.LastUpdateTime(), LastUpdate: swp.LastUpdateTime(),
HtlcAddress: htlc.Address, HtlcAddress: htlc.Address,
}) })
} }
@ -259,7 +259,7 @@ func (s *Client) resumeSwaps(ctx context.Context,
} }
for _, pend := range loopOutSwaps { for _, pend := range loopOutSwaps {
if pend.State().Type() != loopdb.StateTypePending { if pend.State().State.Type() != loopdb.StateTypePending {
continue continue
} }
swap, err := resumeLoopOutSwap(ctx, swapCfg, pend) swap, err := resumeLoopOutSwap(ctx, swapCfg, pend)
@ -272,7 +272,7 @@ func (s *Client) resumeSwaps(ctx context.Context,
} }
for _, pend := range loopInSwaps { for _, pend := range loopInSwaps {
if pend.State().Type() != loopdb.StateTypePending { if pend.State().State.Type() != loopdb.StateTypePending {
continue continue
} }
swap, err := resumeLoopInSwap(ctx, swapCfg, pend) swap, err := resumeLoopInSwap(ctx, swapCfg, pend)

@ -202,7 +202,9 @@ func testResume(t *testing.T, expired, preimageRevealed, expectSuccess bool) {
Loop: loopdb.Loop{ Loop: loopdb.Loop{
Events: []*loopdb.LoopEvent{ Events: []*loopdb.LoopEvent{
{ {
State: state, SwapStateData: loopdb.SwapStateData{
State: state,
},
}, },
}, },
Hash: hash, Hash: hash,

@ -176,11 +176,22 @@ func parseAmt(text string) (btcutil.Amount, error) {
} }
func logSwap(swap *looprpc.SwapStatus) { 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), time.Unix(0, swap.LastUpdateTime).Format(time.RFC3339),
swap.Type, swap.State, btcutil.Amount(swap.Amt), swap.Type, swap.State, btcutil.Amount(swap.Amt),
swap.HtlcAddress, 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) { func getClientConn(address string) (*grpc.ClientConn, error) {

@ -28,6 +28,9 @@ func monitor(ctx *cli.Context) error {
return err return err
} }
fmt.Printf("Note: offchain cost may report as 0 after loopd restart " +
"during swap\n")
for { for {
swap, err := stream.Recv() swap, err := stream.Recv()
if err != nil { if err != nil {

@ -121,6 +121,9 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
LastUpdateTime: loopSwap.LastUpdate.UnixNano(), LastUpdateTime: loopSwap.LastUpdate.UnixNano(),
HtlcAddress: loopSwap.HtlcAddress.EncodeAddress(), HtlcAddress: loopSwap.HtlcAddress.EncodeAddress(),
Type: swapType, Type: swapType,
CostServer: int64(loopSwap.Cost.Server),
CostOnchain: int64(loopSwap.Cost.Onchain),
CostOffchain: int64(loopSwap.Cost.Offchain),
}, nil }, nil
} }

@ -6,6 +6,7 @@ import (
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lightninglabs/loop" "github.com/lightninglabs/loop"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap" "github.com/lightninglabs/loop/swap"
) )
@ -77,9 +78,19 @@ func viewOut(swapClient *loop.Client, chainParams *chaincfg.Params) error {
s.Contract.AmountRequested, s.Contract.CltvExpiry, s.Contract.AmountRequested, s.Contract.CltvExpiry,
) )
for i, e := range s.Events { 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, 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() fmt.Println()
} }

@ -83,15 +83,6 @@ type Out struct {
SwapInfoKit 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 // LoopOutQuoteRequest specifies the swap parameters for which a quote is
// requested. // requested.
type LoopOutQuoteRequest struct { type LoopOutQuoteRequest struct {
@ -280,12 +271,12 @@ func (t Type) String() string {
// SwapInfo exposes common info fields for loop in and loop out swaps. // SwapInfo exposes common info fields for loop in and loop out swaps.
type SwapInfo struct { type SwapInfo struct {
loopdb.SwapStateData
LastUpdate time.Time LastUpdate time.Time
SwapHash lntypes.Hash SwapHash lntypes.Hash
State loopdb.SwapState
SwapType Type SwapType Type
loopdb.SwapContract loopdb.SwapContract

@ -18,7 +18,8 @@ type SwapStore interface {
// UpdateLoopOut stores a new event for a target loop out swap. This // 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 // appends to the event log for a particular swap as it goes through
// the various stages in its lifetime. // 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 returns all swaps currently in the store.
FetchLoopInSwaps() ([]*LoopIn, error) FetchLoopInSwaps() ([]*LoopIn, error)
@ -29,7 +30,8 @@ type SwapStore interface {
// UpdateLoopIn stores a new event for a target loop in swap. This // 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 // appends to the event log for a particular swap as it goes through
// the various stages in its lifetime. // 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 closes the underlying database.
Close() error Close() error

@ -1,44 +1,21 @@
package loopdb package loopdb
import ( import (
"os"
"github.com/btcsuite/btclog" "github.com/btcsuite/btclog"
) )
// log is a logger that is initialized with no output filters. This means var (
// the package will not perform any logging by default until the caller backendLog = btclog.NewBackend(logWriter{})
// requests it. log = backendLog.Logger("STORE")
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
// String invokes the underlying function and returns the result. // logWriter implements an io.Writer that outputs to both standard output and
func (c logClosure) String() string { // the write-end pipe of an initialized log rotator.
return c() type logWriter struct{}
}
// newLogClosure returns a new closure over a function that returns a string func (logWriter) Write(p []byte) (n int, err error) {
// which itself provides a Stringer interface so that it can be used with the os.Stdout.Write(p)
// logging system. return len(p), nil
func newLogClosure(c func() string) logClosure {
return logClosure(c)
} }

@ -53,21 +53,22 @@ type Loop struct {
// LoopEvent contains the dynamic data of a swap. // LoopEvent contains the dynamic data of a swap.
type LoopEvent struct { type LoopEvent struct {
// State is the new state for this swap as a result of this event. SwapStateData
State SwapState
// Time is the time that this swap had its state changed. // Time is the time that this swap had its state changed.
Time time.Time Time time.Time
} }
// State returns the most recent state of this swap. // State returns the most recent state of this swap.
func (s *Loop) State() SwapState { func (s *Loop) State() SwapStateData {
lastUpdate := s.LastUpdate() lastUpdate := s.LastUpdate()
if lastUpdate == nil { if lastUpdate == nil {
return StateInitiated return SwapStateData{
State: StateInitiated,
}
} }
return lastUpdate.State return lastUpdate.SwapStateData
} }
// LastUpdate returns the most recent update of this swap. // 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 // serializeLoopEvent serializes a state update of a swap. This is used for both
// in and out swaps. // in and out swaps.
func serializeLoopEvent(time time.Time, state SwapState) ( func serializeLoopEvent(time time.Time, state SwapStateData) (
[]byte, error) { []byte, error) {
var b bytes.Buffer var b bytes.Buffer
@ -93,7 +94,19 @@ func serializeLoopEvent(time time.Time, state SwapState) (
return nil, err 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 return nil, err
} }
@ -117,5 +130,17 @@ func deserializeLoopEvent(value []byte) (*LoopEvent, error) {
return nil, err 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 return update, nil
} }

@ -10,7 +10,7 @@ import (
var ( var (
// metaBucket stores all the meta information concerning the state of // metaBucket stores all the meta information concerning the state of
// the database. // the database.
metaBucket = []byte("metadata") metaBucketKey = []byte("metadata")
// dbVersionKey is a boltdb key and it's used for storing/retrieving // dbVersionKey is a boltdb key and it's used for storing/retrieving
// current database version. // current database version.
@ -31,7 +31,7 @@ var (
// of database don't match with latest version this list will be used // 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 // for retrieving all migration function that are need to apply to the
// current db. // current db.
migrations = []migration{} migrations = []migration{migrateCosts}
latestDBVersion = uint32(len(migrations)) latestDBVersion = uint32(len(migrations))
) )
@ -41,7 +41,7 @@ func getDBVersion(db *bbolt.DB) (uint32, error) {
var version uint32 var version uint32
err := db.View(func(tx *bbolt.Tx) error { err := db.View(func(tx *bbolt.Tx) error {
metaBucket := tx.Bucket(metaBucket) metaBucket := tx.Bucket(metaBucketKey)
if metaBucket == nil { if metaBucket == nil {
return errors.New("bucket does not exist") return errors.New("bucket does not exist")
} }
@ -61,11 +61,11 @@ func getDBVersion(db *bbolt.DB) (uint32, error) {
return version, nil return version, nil
} }
// getDBVersion updates the current db version. // setDBVersion updates the current db version.
func setDBVersion(tx *bbolt.Tx, version uint32) error { func setDBVersion(tx *bbolt.Tx, version uint32) error {
metaBucket := tx.Bucket(metaBucket) metaBucket, err := tx.CreateBucketIfNotExists(metaBucketKey)
if metaBucket == nil { if err != nil {
return errors.New("bucket does not exist") return fmt.Errorf("set db version: %v", err)
} }
scratch := make([]byte, 4) scratch := make([]byte, 4)

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

@ -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 // 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. // starting up. If they already exist, then these calls will be noops.
err = bdb.Update(func(tx *bbolt.Tx) error { err = bdb.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(loopOutBucketKey) // Check if the meta bucket exists. If it exists, we consider
if err != nil { // the database as initialized and assume the meta bucket
return err // 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 { if err != nil {
return err return err
} }
_, err = tx.CreateBucketIfNotExists(metaBucket)
_, err = tx.CreateBucketIfNotExists(loopInBucketKey)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
}) })
if err != 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 // 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. // bucket key so that this function can be used for both in and out swaps.
func (s *boltSwapStore) updateLoop(bucketKey []byte, hash lntypes.Hash, 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 { return s.db.Update(func(tx *bbolt.Tx) error {
// Starting from the root bucket, we'll traverse the bucket // 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. // NOTE: Part of the loopdb.SwapStore interface.
func (s *boltSwapStore) UpdateLoopOut(hash lntypes.Hash, time time.Time, func (s *boltSwapStore) UpdateLoopOut(hash lntypes.Hash, time time.Time,
state SwapState) error { state SwapStateData) error {
return s.updateLoop(loopOutBucketKey, hash, time, state) 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. // NOTE: Part of the loopdb.SwapStore interface.
func (s *boltSwapStore) UpdateLoopIn(hash lntypes.Hash, time time.Time, func (s *boltSwapStore) UpdateLoopIn(hash lntypes.Hash, time time.Time,
state SwapState) error { state SwapStateData) error {
return s.updateLoop(loopInBucketKey, hash, time, state) return s.updateLoop(loopInBucketKey, hash, time, state)
} }

@ -4,11 +4,13 @@ import (
"crypto/sha256" "crypto/sha256"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"reflect" "reflect"
"testing" "testing"
"time" "time"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/coreos/bbolt"
"github.com/lightninglabs/loop/test" "github.com/lightninglabs/loop/test"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
) )
@ -107,7 +109,7 @@ func TestLoopOutStore(t *testing.T) {
t.Fatal("invalid pending swap data") 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", t.Fatalf("expected state %v, but got %v",
expectedState, swaps[0].State(), 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 // Next, we'll update to the next state of the pre-image being
// revealed. The state should be reflected here again. // revealed. The state should be reflected here again.
err = store.UpdateLoopOut( err = store.UpdateLoopOut(
hash, testTime, StatePreimageRevealed, hash, testTime,
SwapStateData{
State: StatePreimageRevealed,
},
) )
if err != nil { if err != nil {
t.Fatal(err) 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 // Next, we'll update to the final state to ensure that the state is
// properly updated. // properly updated.
err = store.UpdateLoopOut( err = store.UpdateLoopOut(
hash, testTime, StateFailInsufficientValue, hash, testTime,
SwapStateData{
State: StateFailInsufficientValue,
},
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -229,7 +237,7 @@ func TestLoopInStore(t *testing.T) {
t.Fatal("invalid pending swap data") 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", t.Fatalf("expected state %v, but got %v",
expectedState, swaps[0].State(), 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 // Next, we'll update to the next state of the pre-image being
// revealed. The state should be reflected here again. // revealed. The state should be reflected here again.
err = store.UpdateLoopIn( err = store.UpdateLoopIn(
hash, testTime, StatePreimageRevealed, hash, testTime,
SwapStateData{
State: StatePreimageRevealed,
},
) )
if err != nil { if err != nil {
t.Fatal(err) 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 // Next, we'll update to the final state to ensure that the state is
// properly updated. // properly updated.
err = store.UpdateLoopIn( err = store.UpdateLoopIn(
hash, testTime, StateFailInsufficientValue, hash, testTime,
SwapStateData{
State: StateFailInsufficientValue,
},
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -281,3 +295,72 @@ func TestLoopInStore(t *testing.T) {
} }
checkSwap(StateFailInsufficientValue) 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)
}
}

@ -1,5 +1,7 @@
package loopdb package loopdb
import "github.com/btcsuite/btcutil"
// SwapState indicates the current state of a swap. This enumeration is the // 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 // 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. // types to be able to reduce code duplication that would otherwise be required.
@ -125,3 +127,24 @@ func (s SwapState) String() string {
return "Unknown" 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
}

@ -261,10 +261,11 @@ func (s *loopInSwap) execute(mainCtx context.Context,
} }
s.log.Infof("Loop in swap completed: %v "+ 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.state,
s.cost.Server, s.cost.Server,
s.cost.Onchain, s.cost.Onchain,
s.cost.Offchain,
) )
return nil return nil
@ -616,7 +617,13 @@ func (s *loopInSwap) publishTimeoutTx(ctx context.Context,
// persistState updates the swap state and sends out an update notification. // persistState updates the swap state and sends out an update notification.
func (s *loopInSwap) persistState(ctx context.Context) error { func (s *loopInSwap) persistState(ctx context.Context) error {
// Update state in store. // 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 { if err != nil {
return err return err
} }

@ -248,7 +248,9 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool) {
Loop: loopdb.Loop{ Loop: loopdb.Loop{
Events: []*loopdb.LoopEvent{ Events: []*loopdb.LoopEvent{
{ {
State: state, SwapStateData: loopdb.SwapStateData{
State: state,
},
}, },
}, },
Hash: testPreimage.Hash(), Hash: testPreimage.Hash(),

@ -224,6 +224,7 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
continue continue
} }
s.cost.Server += result.PaidAmt s.cost.Server += result.PaidAmt
s.cost.Offchain += result.PaidFee
case result := <-s.prePaymentChan: case result := <-s.prePaymentChan:
s.prePaymentChan = nil s.prePaymentChan = nil
@ -235,6 +236,7 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
continue continue
} }
s.cost.Server += result.PaidAmt s.cost.Server += result.PaidAmt
s.cost.Offchain += result.PaidFee
case <-globalCtx.Done(): case <-globalCtx.Done():
return globalCtx.Err() return globalCtx.Err()
@ -243,10 +245,11 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
// Mark swap completed in store. // Mark swap completed in store.
s.log.Infof("Swap completed: %v "+ s.log.Infof("Swap completed: %v "+
"(final cost: server %v, onchain %v)", "(final cost: server %v, onchain %v, offchain %v)",
s.state, s.state,
s.cost.Server, s.cost.Server,
s.cost.Onchain, s.cost.Onchain,
s.cost.Offchain,
) )
return s.persistState(globalCtx) return s.persistState(globalCtx)
@ -342,7 +345,13 @@ func (s *loopOutSwap) persistState(ctx context.Context) error {
s.lastUpdateTime = updateTime s.lastUpdateTime = updateTime
// Update state in store. // 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 { if err != nil {
return err return err
} }
@ -441,6 +450,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
return nil, nil return nil, nil
} }
s.cost.Server += result.PaidAmt s.cost.Server += result.PaidAmt
s.cost.Offchain += result.PaidFee
// If the prepay fails, abandon the swap. Because we // If the prepay fails, abandon the swap. Because we
// didn't reveal the preimage, the swap payment will be // didn't reveal the preimage, the swap payment will be
@ -455,6 +465,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
return nil, nil return nil, nil
} }
s.cost.Server += result.PaidAmt s.cost.Server += result.PaidAmt
s.cost.Offchain += result.PaidFee
// Unexpected error on the confirm channel happened, // Unexpected error on the confirm channel happened,
// abandon the swap. // abandon the swap.

@ -46,7 +46,7 @@ func (x SwapType) String() string {
return proto.EnumName(SwapType_name, int32(x)) return proto.EnumName(SwapType_name, int32(x))
} }
func (SwapType) EnumDescriptor() ([]byte, []int) { func (SwapType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_client_ba4b73c10b9bbc2a, []int{0} return fileDescriptor_client_cce8684ac06bdedc, []int{0}
} }
type SwapState int32 type SwapState int32
@ -103,7 +103,7 @@ func (x SwapState) String() string {
return proto.EnumName(SwapState_name, int32(x)) return proto.EnumName(SwapState_name, int32(x))
} }
func (SwapState) EnumDescriptor() ([]byte, []int) { func (SwapState) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_client_ba4b73c10b9bbc2a, []int{1} return fileDescriptor_client_cce8684ac06bdedc, []int{1}
} }
type LoopOutRequest struct { type LoopOutRequest struct {
@ -161,7 +161,7 @@ func (m *LoopOutRequest) Reset() { *m = LoopOutRequest{} }
func (m *LoopOutRequest) String() string { return proto.CompactTextString(m) } func (m *LoopOutRequest) String() string { return proto.CompactTextString(m) }
func (*LoopOutRequest) ProtoMessage() {} func (*LoopOutRequest) ProtoMessage() {}
func (*LoopOutRequest) Descriptor() ([]byte, []int) { 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 { func (m *LoopOutRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LoopOutRequest.Unmarshal(m, b) 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 (m *LoopInRequest) String() string { return proto.CompactTextString(m) }
func (*LoopInRequest) ProtoMessage() {} func (*LoopInRequest) ProtoMessage() {}
func (*LoopInRequest) Descriptor() ([]byte, []int) { 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 { func (m *LoopInRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LoopInRequest.Unmarshal(m, b) 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 (m *SwapResponse) String() string { return proto.CompactTextString(m) }
func (*SwapResponse) ProtoMessage() {} func (*SwapResponse) ProtoMessage() {}
func (*SwapResponse) Descriptor() ([]byte, []int) { 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 { func (m *SwapResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SwapResponse.Unmarshal(m, b) 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 (m *MonitorRequest) String() string { return proto.CompactTextString(m) }
func (*MonitorRequest) ProtoMessage() {} func (*MonitorRequest) ProtoMessage() {}
func (*MonitorRequest) Descriptor() ([]byte, []int) { 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 { func (m *MonitorRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MonitorRequest.Unmarshal(m, b) 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"` LastUpdateTime int64 `protobuf:"varint,6,opt,name=last_update_time,json=lastUpdateTime,proto3" json:"last_update_time,omitempty"`
// * // *
// Htlc address. // 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_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `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 (m *SwapStatus) String() string { return proto.CompactTextString(m) }
func (*SwapStatus) ProtoMessage() {} func (*SwapStatus) ProtoMessage() {}
func (*SwapStatus) Descriptor() ([]byte, []int) { 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 { func (m *SwapStatus) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SwapStatus.Unmarshal(m, b) return xxx_messageInfo_SwapStatus.Unmarshal(m, b)
@ -512,6 +518,27 @@ func (m *SwapStatus) GetHtlcAddress() string {
return "" 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 { type TermsRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `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 (m *TermsRequest) String() string { return proto.CompactTextString(m) }
func (*TermsRequest) ProtoMessage() {} func (*TermsRequest) ProtoMessage() {}
func (*TermsRequest) Descriptor() ([]byte, []int) { 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 { func (m *TermsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TermsRequest.Unmarshal(m, b) 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 (m *TermsResponse) String() string { return proto.CompactTextString(m) }
func (*TermsResponse) ProtoMessage() {} func (*TermsResponse) ProtoMessage() {}
func (*TermsResponse) Descriptor() ([]byte, []int) { 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 { func (m *TermsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TermsResponse.Unmarshal(m, b) 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 (m *QuoteRequest) String() string { return proto.CompactTextString(m) }
func (*QuoteRequest) ProtoMessage() {} func (*QuoteRequest) ProtoMessage() {}
func (*QuoteRequest) Descriptor() ([]byte, []int) { 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 { func (m *QuoteRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_QuoteRequest.Unmarshal(m, b) 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 (m *QuoteResponse) String() string { return proto.CompactTextString(m) }
func (*QuoteResponse) ProtoMessage() {} func (*QuoteResponse) ProtoMessage() {}
func (*QuoteResponse) Descriptor() ([]byte, []int) { 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 { func (m *QuoteResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_QuoteResponse.Unmarshal(m, b) return xxx_messageInfo_QuoteResponse.Unmarshal(m, b)
@ -1099,67 +1126,70 @@ var _SwapClient_serviceDesc = grpc.ServiceDesc{
Metadata: "client.proto", Metadata: "client.proto",
} }
func init() { proto.RegisterFile("client.proto", fileDescriptor_client_ba4b73c10b9bbc2a) } func init() { proto.RegisterFile("client.proto", fileDescriptor_client_cce8684ac06bdedc) }
var fileDescriptor_client_ba4b73c10b9bbc2a = []byte{ var fileDescriptor_client_cce8684ac06bdedc = []byte{
// 941 bytes of a gzipped FileDescriptorProto // 992 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xdd, 0x8e, 0xda, 0x46, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x4f, 0x73, 0xda, 0x46,
0x18, 0x8d, 0x0d, 0xbb, 0xc0, 0xb7, 0xc6, 0xc0, 0x6c, 0xb2, 0xa1, 0xb4, 0x91, 0xa8, 0xdb, 0xa4, 0x1c, 0x0d, 0x02, 0x1b, 0xf8, 0x59, 0xc8, 0x78, 0x9d, 0x38, 0x94, 0x36, 0x53, 0xaa, 0x36, 0x29,
0x68, 0x2f, 0x96, 0x76, 0x73, 0x51, 0xb5, 0x37, 0x15, 0x01, 0x27, 0x6b, 0x89, 0x5d, 0xa8, 0x61, 0xe3, 0x83, 0x69, 0x9d, 0x43, 0xa7, 0xbd, 0x74, 0x08, 0x28, 0xb1, 0x66, 0xb0, 0xa1, 0x02, 0x67,
0x23, 0xf5, 0xca, 0x9a, 0xc0, 0x64, 0x63, 0xc9, 0xf6, 0x38, 0xf6, 0x38, 0x61, 0x55, 0xf5, 0xa6, 0xa6, 0x27, 0xcd, 0x06, 0xd6, 0xb6, 0x66, 0xa4, 0x5d, 0x45, 0x5a, 0x39, 0x78, 0x3a, 0xbd, 0xf4,
0x6f, 0xd0, 0xf6, 0x4d, 0xaa, 0xbe, 0x49, 0x5f, 0xa1, 0xaf, 0xd0, 0xfb, 0x6a, 0x7e, 0x70, 0x6c, 0x1b, 0xb4, 0xfd, 0x26, 0x9d, 0x7e, 0x93, 0xde, 0x7b, 0xea, 0x07, 0xe9, 0xec, 0x1f, 0x14, 0x04,
0xe8, 0xde, 0xe4, 0xce, 0x9c, 0x39, 0x73, 0xe6, 0xfb, 0xce, 0x9c, 0x6f, 0x00, 0x63, 0x15, 0xf8, 0xf1, 0x25, 0x37, 0xfc, 0xf6, 0xed, 0xdb, 0xdf, 0xfe, 0x7e, 0xef, 0xad, 0x0c, 0xe6, 0x3c, 0x0c,
0x24, 0x62, 0x67, 0x71, 0x42, 0x19, 0x45, 0xb5, 0x80, 0xd2, 0x38, 0x89, 0x57, 0xbd, 0xcf, 0x6e, 0x08, 0xe5, 0x27, 0x71, 0xc2, 0x38, 0x43, 0xd5, 0x90, 0xb1, 0x38, 0x89, 0xe7, 0xed, 0xcf, 0xae,
0x28, 0xbd, 0x09, 0xc8, 0x10, 0xc7, 0xfe, 0x10, 0x47, 0x11, 0x65, 0x98, 0xf9, 0x34, 0x4a, 0x25, 0x19, 0xbb, 0x0e, 0x49, 0x0f, 0xc7, 0x41, 0x0f, 0x53, 0xca, 0x38, 0xe6, 0x01, 0xa3, 0xa9, 0xa2,
0xcd, 0xfa, 0x53, 0x07, 0x73, 0x4a, 0x69, 0x3c, 0xcb, 0x98, 0x4b, 0xde, 0x66, 0x24, 0x65, 0xa8, 0xd9, 0x7f, 0x19, 0x60, 0x8d, 0x18, 0x8b, 0xc7, 0x19, 0xf7, 0xc8, 0xdb, 0x8c, 0xa4, 0x1c, 0x35,
0x0d, 0x15, 0x1c, 0xb2, 0xae, 0xd6, 0xd7, 0x06, 0x15, 0x97, 0x7f, 0x22, 0x04, 0xd5, 0x35, 0x49, 0xa1, 0x8c, 0x23, 0xde, 0x2a, 0x75, 0x4a, 0xdd, 0xb2, 0x27, 0x7e, 0x22, 0x04, 0x95, 0x05, 0x49,
0x59, 0x57, 0xef, 0x6b, 0x83, 0x86, 0x2b, 0xbe, 0xd1, 0x10, 0xee, 0x87, 0x78, 0xe3, 0xa5, 0xef, 0x79, 0xcb, 0xe8, 0x94, 0xba, 0x75, 0x4f, 0xfe, 0x46, 0x3d, 0x78, 0x18, 0xe1, 0xa5, 0x9f, 0xbe,
0x71, 0xec, 0x25, 0x34, 0x63, 0x7e, 0x74, 0xe3, 0xbd, 0x26, 0xa4, 0x5b, 0x11, 0xdb, 0x3a, 0x21, 0xc3, 0xb1, 0x9f, 0xb0, 0x8c, 0x07, 0xf4, 0xda, 0xbf, 0x22, 0xa4, 0x55, 0x96, 0xdb, 0x0e, 0x22,
0xde, 0x2c, 0xde, 0xe3, 0xd8, 0x95, 0x2b, 0xcf, 0x09, 0x41, 0x4f, 0xe1, 0x84, 0x6f, 0x88, 0x13, 0xbc, 0x9c, 0xbe, 0xc3, 0xb1, 0xa7, 0x56, 0x5e, 0x12, 0x82, 0x9e, 0xc3, 0x91, 0xd8, 0x10, 0x27,
0x12, 0xe3, 0xdb, 0xd2, 0x96, 0xaa, 0xd8, 0x72, 0x1c, 0xe2, 0xcd, 0x5c, 0x2c, 0x16, 0x36, 0xf5, 0x24, 0xc6, 0x77, 0x85, 0x2d, 0x15, 0xb9, 0xe5, 0x30, 0xc2, 0xcb, 0x89, 0x5c, 0x5c, 0xdb, 0xd4,
0xc1, 0xc8, 0x4f, 0xe1, 0xd4, 0x03, 0x41, 0x05, 0xa5, 0xce, 0x19, 0x5f, 0x82, 0x59, 0x90, 0xe5, 0x01, 0x33, 0x3f, 0x45, 0x50, 0x77, 0x24, 0x15, 0xb4, 0xba, 0x60, 0x7c, 0x05, 0xd6, 0x9a, 0xac,
0x85, 0x1f, 0x0a, 0x8e, 0x91, 0xcb, 0x8d, 0x42, 0x86, 0x2c, 0x68, 0x72, 0x56, 0xe8, 0x47, 0x24, 0x28, 0x7c, 0x57, 0x72, 0xcc, 0x5c, 0xae, 0x1f, 0x71, 0x64, 0x43, 0x43, 0xb0, 0xa2, 0x80, 0x92,
0x11, 0x42, 0x35, 0x41, 0x3a, 0x0a, 0xf1, 0xe6, 0x92, 0x63, 0x5c, 0x69, 0x00, 0x6d, 0xee, 0x99, 0x44, 0x0a, 0x55, 0x25, 0x69, 0x2f, 0xc2, 0xcb, 0x73, 0x81, 0x09, 0xa5, 0x2e, 0x34, 0x45, 0xcf,
0x47, 0x33, 0xe6, 0xad, 0xde, 0xe0, 0x28, 0x22, 0x41, 0xb7, 0xde, 0xd7, 0x06, 0x55, 0xd7, 0x0c, 0x7c, 0x96, 0x71, 0x7f, 0x7e, 0x83, 0x29, 0x25, 0x61, 0xab, 0xd6, 0x29, 0x75, 0x2b, 0x9e, 0x15,
0xa4, 0x43, 0x63, 0x89, 0x5a, 0x7f, 0x69, 0xd0, 0xe4, 0xa6, 0x39, 0xd1, 0xdd, 0x9e, 0xed, 0x56, 0xaa, 0x0e, 0x0d, 0x14, 0x6a, 0xff, 0x5d, 0x82, 0x86, 0x68, 0x9a, 0x4b, 0xef, 0xef, 0xd9, 0x66,
0xae, 0xef, 0x55, 0xbe, 0x57, 0x53, 0x65, 0xbf, 0xa6, 0x27, 0xd0, 0x12, 0x35, 0xf9, 0x51, 0x5e, 0xe5, 0xc6, 0x56, 0xe5, 0x5b, 0x35, 0x95, 0xb7, 0x6b, 0x7a, 0x06, 0xfb, 0xb2, 0xa6, 0x80, 0xe6,
0x52, 0x55, 0x94, 0xd4, 0x0c, 0xc4, 0xf9, 0xaa, 0x22, 0xf4, 0x05, 0x34, 0xc9, 0x86, 0x91, 0x24, 0x25, 0x55, 0x64, 0x49, 0x8d, 0x50, 0x9e, 0xaf, 0x2b, 0x42, 0x5f, 0x42, 0x83, 0x2c, 0x39, 0x49,
0xc2, 0x81, 0xf7, 0x86, 0x05, 0x2b, 0x61, 0x54, 0xdd, 0x35, 0xb6, 0xe0, 0x05, 0x0b, 0x56, 0xd6, 0x28, 0x0e, 0xfd, 0x1b, 0x1e, 0xce, 0x65, 0xa3, 0x6a, 0x9e, 0xb9, 0x02, 0xcf, 0x78, 0x38, 0xb7,
0x08, 0x0c, 0x71, 0x27, 0x24, 0x8d, 0x69, 0x94, 0x12, 0x64, 0x82, 0xee, 0xaf, 0x45, 0xcd, 0x0d, 0xfb, 0x60, 0xca, 0x99, 0x90, 0x34, 0x66, 0x34, 0x25, 0xc8, 0x02, 0x23, 0x58, 0xc8, 0x9a, 0xeb,
0x57, 0xf7, 0xd7, 0xe8, 0x73, 0x30, 0xf8, 0x5e, 0x0f, 0xaf, 0xd7, 0x09, 0x49, 0x53, 0x75, 0xdd, 0x9e, 0x11, 0x2c, 0xd0, 0x17, 0x60, 0x8a, 0xbd, 0x3e, 0x5e, 0x2c, 0x12, 0x92, 0xa6, 0x7a, 0xdc,
0x47, 0x1c, 0x1b, 0x49, 0xc8, 0x6a, 0x83, 0x79, 0x49, 0x23, 0x9f, 0xd1, 0x44, 0x75, 0x6e, 0xfd, 0x7b, 0x02, 0xeb, 0x2b, 0xc8, 0x6e, 0x82, 0x75, 0xce, 0x68, 0xc0, 0x59, 0xa2, 0x6f, 0x6e, 0xff,
0xab, 0x01, 0x70, 0xd5, 0x05, 0xc3, 0x2c, 0x4b, 0xff, 0xc7, 0x08, 0x79, 0x8a, 0x9e, 0x9f, 0xf2, 0x6b, 0x00, 0x08, 0xd5, 0x29, 0xc7, 0x3c, 0x4b, 0x3f, 0xd0, 0x08, 0x75, 0x8a, 0x91, 0x9f, 0xf2,
0x18, 0xaa, 0xec, 0x36, 0x96, 0xdd, 0x9a, 0xe7, 0x9d, 0x33, 0x95, 0xd3, 0x33, 0x2e, 0xb2, 0xbc, 0x14, 0x2a, 0xfc, 0x2e, 0x56, 0xb7, 0xb5, 0x4e, 0x0f, 0x4e, 0xb4, 0x4f, 0x4f, 0x84, 0xc8, 0xec,
0x8d, 0x89, 0x2b, 0x96, 0xd1, 0x00, 0x0e, 0x52, 0x86, 0x99, 0x4c, 0x87, 0x79, 0x8e, 0x4a, 0x3c, 0x2e, 0x26, 0x9e, 0x5c, 0x46, 0x5d, 0xd8, 0x49, 0x39, 0xe6, 0xca, 0x1d, 0xd6, 0x29, 0x2a, 0xf0,
0x7e, 0x18, 0x71, 0x25, 0x01, 0x7d, 0x05, 0x2d, 0x3f, 0xf2, 0x99, 0x2f, 0x72, 0xed, 0x31, 0x3f, 0xc4, 0x61, 0xc4, 0x53, 0x04, 0xf4, 0x35, 0xec, 0x07, 0x34, 0xe0, 0x81, 0xf4, 0xb5, 0xcf, 0x83,
0xdc, 0xc6, 0xc4, 0xfc, 0x00, 0x2f, 0xfd, 0x50, 0x5e, 0x30, 0x4e, 0x99, 0x97, 0xc5, 0x6b, 0xcc, 0x68, 0x65, 0x13, 0xeb, 0x3d, 0x3c, 0x0b, 0x22, 0x35, 0x60, 0x9c, 0x72, 0x3f, 0x8b, 0x17, 0x98,
0x88, 0x64, 0xca, 0xb0, 0x98, 0x1c, 0xbf, 0x16, 0xb0, 0x60, 0xee, 0x3a, 0x51, 0xdb, 0x77, 0xc2, 0x13, 0xc5, 0x54, 0x66, 0xb1, 0x04, 0x7e, 0x29, 0x61, 0xc9, 0xdc, 0xec, 0x44, 0x75, 0xab, 0x13,
0x04, 0x63, 0x49, 0x92, 0x30, 0xdd, 0xfa, 0xf0, 0x9b, 0x0e, 0x4d, 0x05, 0x28, 0x7b, 0x4f, 0xa1, 0xe8, 0x73, 0xd8, 0x9b, 0xb3, 0x94, 0xfb, 0x29, 0x49, 0x6e, 0x49, 0x22, 0x8d, 0x52, 0xf6, 0x40,
0x23, 0x6e, 0x3f, 0xc6, 0xb7, 0x21, 0x89, 0x98, 0x27, 0x46, 0x48, 0xba, 0xdd, 0xe2, 0x0b, 0x73, 0x40, 0x53, 0x89, 0x08, 0x0d, 0x49, 0x60, 0x74, 0x7e, 0x83, 0x03, 0xda, 0xaa, 0xab, 0xe9, 0x0a,
0x89, 0x4f, 0x78, 0x7e, 0x2c, 0x68, 0x6e, 0x93, 0xe2, 0xbd, 0xc2, 0xe9, 0x36, 0x2e, 0x47, 0xa9, 0x6c, 0xac, 0x20, 0x31, 0x35, 0x45, 0xb9, 0xba, 0x52, 0x1c, 0x50, 0xd6, 0x95, 0x1c, 0x8d, 0xd9,
0xcc, 0xca, 0x33, 0x9c, 0x92, 0x12, 0x27, 0xe1, 0xce, 0x54, 0x4a, 0x1c, 0x97, 0x7b, 0xf1, 0x08, 0x16, 0x98, 0x33, 0x92, 0x44, 0xe9, 0xaa, 0xe1, 0xbf, 0x1b, 0xd0, 0xd0, 0x80, 0x9e, 0xe3, 0x31,
0xa0, 0x30, 0x09, 0x72, 0xb0, 0x1a, 0x71, 0x3e, 0x06, 0x4f, 0xa0, 0x15, 0xfa, 0x91, 0x0c, 0x25, 0x1c, 0x48, 0x9b, 0xc5, 0xf8, 0x2e, 0x22, 0x94, 0xfb, 0x32, 0xab, 0x6a, 0xac, 0xfb, 0x62, 0x61,
0x0e, 0x69, 0x16, 0x31, 0x65, 0x55, 0x33, 0xf4, 0x23, 0x6e, 0xec, 0x48, 0x80, 0x82, 0xb7, 0x0d, 0xa2, 0xf0, 0xa1, 0x30, 0xaa, 0x0d, 0x8d, 0x95, 0x25, 0xfd, 0x37, 0x38, 0x5d, 0xf9, 0x72, 0x2f,
0xaf, 0xe2, 0x1d, 0x2a, 0x9e, 0xcc, 0xaf, 0xe2, 0x3d, 0x02, 0x58, 0x05, 0xec, 0x9d, 0xb7, 0x26, 0x55, 0xa6, 0x7c, 0x81, 0x53, 0x52, 0xe0, 0x24, 0x62, 0x04, 0xe5, 0x02, 0xc7, 0x13, 0x4d, 0x7f,
0x01, 0xc3, 0xc2, 0xa5, 0x03, 0xb7, 0xc1, 0x91, 0x09, 0x07, 0xac, 0x3e, 0x18, 0x3f, 0x66, 0x94, 0x02, 0xb0, 0x16, 0x39, 0x95, 0xe0, 0x7a, 0x9c, 0xe7, 0xed, 0x19, 0xec, 0x47, 0x01, 0x55, 0xee,
0x91, 0x3b, 0xa7, 0xc4, 0x7a, 0x0d, 0x4d, 0xc5, 0x50, 0xa6, 0x7d, 0x02, 0xf5, 0x7c, 0x64, 0x24, 0xc7, 0x11, 0xcb, 0x28, 0xd7, 0x33, 0x69, 0x44, 0x01, 0x15, 0x13, 0xec, 0x4b, 0x50, 0xf2, 0x56,
0xaf, 0xa6, 0xfa, 0xdb, 0xe9, 0x4d, 0xdf, 0xed, 0xed, 0x53, 0x68, 0xec, 0x8e, 0x52, 0x3d, 0x54, 0x29, 0xd1, 0xbc, 0x5d, 0xcd, 0x53, 0x41, 0xd1, 0xbc, 0x27, 0x00, 0xf3, 0x90, 0xdf, 0xfa, 0x0b,
0x73, 0x74, 0xfa, 0x18, 0xea, 0xdb, 0x7c, 0x21, 0x03, 0xea, 0xd3, 0xd9, 0x6c, 0xee, 0xcd, 0xae, 0x12, 0x72, 0x2c, 0xc7, 0xb1, 0xe3, 0xd5, 0x05, 0x32, 0x14, 0x80, 0xdd, 0x01, 0xf3, 0xa7, 0x8c,
0x97, 0xed, 0x7b, 0xe8, 0x08, 0x6a, 0xe2, 0x97, 0x73, 0xd5, 0xd6, 0x4e, 0x53, 0x68, 0xe4, 0xf1, 0x71, 0x72, 0x6f, 0x1c, 0xed, 0x2b, 0x68, 0x68, 0x86, 0x6e, 0xda, 0x27, 0x50, 0xcb, 0xb3, 0xa9,
0x42, 0x4d, 0x68, 0x38, 0x57, 0xce, 0xd2, 0x19, 0x2d, 0xed, 0x49, 0xfb, 0x1e, 0x7a, 0x00, 0x9d, 0x78, 0x55, 0x7d, 0xbf, 0x8d, 0xbb, 0x19, 0x9b, 0x77, 0xfb, 0x14, 0xea, 0x9b, 0x99, 0xad, 0x45,
0xb9, 0x6b, 0x3b, 0x97, 0xa3, 0x17, 0xb6, 0xe7, 0xda, 0x2f, 0xed, 0xd1, 0xd4, 0x9e, 0xb4, 0x35, 0x3a, 0xb0, 0xc7, 0x4f, 0xa1, 0xb6, 0x32, 0x32, 0x32, 0xa1, 0x36, 0x1a, 0x8f, 0x27, 0xfe, 0xf8,
0x84, 0xc0, 0xbc, 0x58, 0x4e, 0xc7, 0xde, 0xfc, 0xfa, 0xd9, 0xd4, 0x59, 0x5c, 0xd8, 0x93, 0xb6, 0x72, 0xd6, 0x7c, 0x80, 0xf6, 0xa0, 0x2a, 0xff, 0x72, 0x2f, 0x9a, 0xa5, 0xe3, 0x14, 0xea, 0xb9,
0xce, 0x35, 0x17, 0xd7, 0xe3, 0xb1, 0xbd, 0x58, 0xb4, 0x2b, 0x08, 0xe0, 0xf0, 0xf9, 0xc8, 0xe1, 0x8f, 0x51, 0x03, 0xea, 0xee, 0x85, 0x3b, 0x73, 0xfb, 0x33, 0x67, 0xd8, 0x7c, 0x80, 0x1e, 0xc1,
0xe4, 0x2a, 0x3a, 0x86, 0x96, 0x73, 0xf5, 0x72, 0xe6, 0x8c, 0x6d, 0x6f, 0x61, 0x2f, 0x97, 0x1c, 0xc1, 0xc4, 0x73, 0xdc, 0xf3, 0xfe, 0x2b, 0xc7, 0xf7, 0x9c, 0xd7, 0x4e, 0x7f, 0xe4, 0x0c, 0x9b,
0x3c, 0x38, 0xff, 0xbd, 0x2a, 0x27, 0x68, 0x2c, 0x9e, 0x6f, 0xe4, 0x42, 0x4d, 0x3d, 0xc8, 0xe8, 0x25, 0x84, 0xc0, 0x3a, 0x9b, 0x8d, 0x06, 0xfe, 0xe4, 0xf2, 0xc5, 0xc8, 0x9d, 0x9e, 0x39, 0xc3,
0x61, 0x1e, 0xfa, 0xf2, 0x13, 0xdd, 0x7b, 0x50, 0x9a, 0x86, 0xad, 0x79, 0xd6, 0xc3, 0x5f, 0xff, 0xa6, 0x21, 0x34, 0xa7, 0x97, 0x83, 0x81, 0x33, 0x9d, 0x36, 0xcb, 0x08, 0x60, 0xf7, 0x65, 0xdf,
0xfe, 0xe7, 0x0f, 0xbd, 0x63, 0x19, 0xc3, 0x77, 0xdf, 0x0c, 0x39, 0x63, 0x48, 0x33, 0xf6, 0xbd, 0x15, 0xe4, 0x0a, 0x3a, 0x84, 0x7d, 0xf7, 0xe2, 0xf5, 0xd8, 0x1d, 0x38, 0xfe, 0xd4, 0x99, 0xcd,
0x76, 0x8a, 0xbe, 0x85, 0x43, 0xf9, 0x5e, 0xa1, 0x93, 0x92, 0x64, 0xfe, 0x80, 0xdd, 0xa1, 0x88, 0x04, 0xb8, 0x73, 0xfa, 0x47, 0x45, 0x45, 0x75, 0x20, 0xbf, 0x13, 0xc8, 0x83, 0xaa, 0x7e, 0xf9,
0xbe, 0x83, 0x9a, 0x9a, 0xf7, 0x42, 0x31, 0xe5, 0x17, 0xa0, 0x77, 0xbc, 0x37, 0x9a, 0x59, 0xfa, 0xd1, 0xe3, 0x3c, 0x5d, 0xc5, 0x6f, 0x41, 0xfb, 0x51, 0x21, 0x76, 0xab, 0xe6, 0xd9, 0x8f, 0x7f,
0xb5, 0x86, 0x7e, 0x02, 0x43, 0x55, 0x2d, 0xc6, 0x02, 0x7d, 0x38, 0xa1, 0x38, 0x37, 0xbd, 0x93, 0xfb, 0xe7, 0xbf, 0x3f, 0x8d, 0x03, 0xdb, 0xec, 0xdd, 0x7e, 0xdb, 0x13, 0x8c, 0x1e, 0xcb, 0xf8,
0x5d, 0x58, 0xf5, 0xd2, 0x13, 0xbd, 0xdc, 0x47, 0xa8, 0xd8, 0xcb, 0x90, 0x09, 0x29, 0x2f, 0x97, 0x0f, 0xa5, 0x63, 0xf4, 0x1d, 0xec, 0xaa, 0x87, 0x11, 0x1d, 0x15, 0x24, 0xf3, 0x97, 0xf2, 0x1e,
0x16, 0xe1, 0x29, 0x48, 0x17, 0xe3, 0x56, 0x90, 0x2e, 0x65, 0xcc, 0xea, 0x0b, 0xe9, 0x1e, 0xea, 0x45, 0xf4, 0x3d, 0x54, 0xf5, 0xc3, 0xb2, 0x56, 0x4c, 0xf1, 0xa9, 0x69, 0x1f, 0x6e, 0xbd, 0x01,
0x96, 0xa4, 0xdf, 0x72, 0xce, 0xf0, 0x67, 0x1c, 0xb2, 0x5f, 0xd0, 0x0f, 0x60, 0xbe, 0x20, 0x4c, 0x59, 0xfa, 0x4d, 0x09, 0xfd, 0x0c, 0xa6, 0xae, 0x5a, 0xc6, 0x02, 0xbd, 0x3f, 0x61, 0x3d, 0x37,
0x3a, 0xf4, 0x31, 0xd5, 0x97, 0x04, 0x3e, 0xa6, 0xc6, 0x57, 0x87, 0xe2, 0xef, 0xf9, 0xe9, 0x7f, 0xed, 0xa3, 0x4d, 0x58, 0xdf, 0xa5, 0x2d, 0xef, 0xf2, 0x10, 0xa1, 0xf5, 0xbb, 0xf4, 0xb8, 0x94,
0x01, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x2d, 0xd7, 0x0b, 0xd5, 0x07, 0x00, 0x00, 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,
} }

@ -221,6 +221,15 @@ message SwapStatus {
Htlc address. Htlc address.
*/ */
string htlc_address = 7; 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 { enum SwapType {

@ -210,6 +210,21 @@
"htlc_address": { "htlc_address": {
"type": "string", "type": "string",
"description": "*\nHtlc address." "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"
} }
} }
}, },

@ -13,14 +13,14 @@ import (
// storeMock implements a mock client swap store. // storeMock implements a mock client swap store.
type storeMock struct { type storeMock struct {
loopOutSwaps map[lntypes.Hash]*loopdb.LoopOutContract loopOutSwaps map[lntypes.Hash]*loopdb.LoopOutContract
loopOutUpdates map[lntypes.Hash][]loopdb.SwapState loopOutUpdates map[lntypes.Hash][]loopdb.SwapStateData
loopOutStoreChan chan loopdb.LoopOutContract loopOutStoreChan chan loopdb.LoopOutContract
loopOutUpdateChan chan loopdb.SwapState loopOutUpdateChan chan loopdb.SwapStateData
loopInSwaps map[lntypes.Hash]*loopdb.LoopInContract loopInSwaps map[lntypes.Hash]*loopdb.LoopInContract
loopInUpdates map[lntypes.Hash][]loopdb.SwapState loopInUpdates map[lntypes.Hash][]loopdb.SwapStateData
loopInStoreChan chan loopdb.LoopInContract loopInStoreChan chan loopdb.LoopInContract
loopInUpdateChan chan loopdb.SwapState loopInUpdateChan chan loopdb.SwapStateData
t *testing.T t *testing.T
} }
@ -34,14 +34,14 @@ type finishData struct {
func newStoreMock(t *testing.T) *storeMock { func newStoreMock(t *testing.T) *storeMock {
return &storeMock{ return &storeMock{
loopOutStoreChan: make(chan loopdb.LoopOutContract, 1), 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), 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), 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), loopInSwaps: make(map[lntypes.Hash]*loopdb.LoopInContract),
loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapState), loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData),
t: t, t: t,
} }
} }
@ -57,7 +57,7 @@ func (s *storeMock) FetchLoopOutSwaps() ([]*loopdb.LoopOut, error) {
events := make([]*loopdb.LoopEvent, len(updates)) events := make([]*loopdb.LoopEvent, len(updates))
for i, u := range updates { for i, u := range updates {
events[i] = &loopdb.LoopEvent{ events[i] = &loopdb.LoopEvent{
State: u, SwapStateData: u,
} }
} }
@ -86,7 +86,7 @@ func (s *storeMock) CreateLoopOut(hash lntypes.Hash,
} }
s.loopOutSwaps[hash] = swap s.loopOutSwaps[hash] = swap
s.loopOutUpdates[hash] = []loopdb.SwapState{} s.loopOutUpdates[hash] = []loopdb.SwapStateData{}
s.loopOutStoreChan <- *swap s.loopOutStoreChan <- *swap
return nil return nil
@ -101,7 +101,7 @@ func (s *storeMock) FetchLoopInSwaps() ([]*loopdb.LoopIn, error) {
events := make([]*loopdb.LoopEvent, len(updates)) events := make([]*loopdb.LoopEvent, len(updates))
for i, u := range updates { for i, u := range updates {
events[i] = &loopdb.LoopEvent{ events[i] = &loopdb.LoopEvent{
State: u, SwapStateData: u,
} }
} }
@ -130,7 +130,7 @@ func (s *storeMock) CreateLoopIn(hash lntypes.Hash,
} }
s.loopInSwaps[hash] = swap s.loopInSwaps[hash] = swap
s.loopInUpdates[hash] = []loopdb.SwapState{} s.loopInUpdates[hash] = []loopdb.SwapStateData{}
s.loopInStoreChan <- *swap s.loopInStoreChan <- *swap
return nil return nil
@ -142,7 +142,7 @@ func (s *storeMock) CreateLoopIn(hash lntypes.Hash,
// //
// NOTE: Part of the loopdb.SwapStore interface. // NOTE: Part of the loopdb.SwapStore interface.
func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time, func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time,
state loopdb.SwapState) error { state loopdb.SwapStateData) error {
updates, ok := s.loopOutUpdates[hash] updates, ok := s.loopOutUpdates[hash]
if !ok { if !ok {
@ -162,7 +162,7 @@ func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time,
// //
// NOTE: Part of the loopdb.SwapStore interface. // NOTE: Part of the loopdb.SwapStore interface.
func (s *storeMock) UpdateLoopIn(hash lntypes.Hash, time time.Time, func (s *storeMock) UpdateLoopIn(hash lntypes.Hash, time time.Time,
state loopdb.SwapState) error { state loopdb.SwapStateData) error {
updates, ok := s.loopInUpdates[hash] updates, ok := s.loopInUpdates[hash]
if !ok { if !ok {
@ -215,7 +215,7 @@ func (s *storeMock) assertLoopInState(expectedState loopdb.SwapState) {
s.t.Helper() s.t.Helper()
state := <-s.loopOutUpdateChan state := <-s.loopOutUpdateChan
if state != expectedState { if state.State != expectedState {
s.t.Fatalf("unexpected state") s.t.Fatalf("unexpected state")
} }
} }
@ -226,7 +226,7 @@ func (s *storeMock) assertStorePreimageReveal() {
select { select {
case state := <-s.loopOutUpdateChan: case state := <-s.loopOutUpdateChan:
if state != loopdb.StatePreimageRevealed { if state.State != loopdb.StatePreimageRevealed {
s.t.Fatalf("unexpected state") s.t.Fatalf("unexpected state")
} }
case <-time.After(test.Timeout): case <-time.After(test.Timeout):
@ -239,7 +239,7 @@ func (s *storeMock) assertStoreFinished(expectedResult loopdb.SwapState) {
select { select {
case state := <-s.loopOutUpdateChan: case state := <-s.loopOutUpdateChan:
if state != expectedResult { if state.State != expectedResult {
s.t.Fatalf("expected result %v, but got %v", s.t.Fatalf("expected result %v, but got %v",
expectedResult, state) expectedResult, state)
} }

@ -19,7 +19,7 @@ type swapKit struct {
log *SwapLog log *SwapLog
lastUpdateTime time.Time lastUpdateTime time.Time
cost SwapCost cost loopdb.SwapCost
state loopdb.SwapState state loopdb.SwapState
executeConfig executeConfig
swapConfig swapConfig
@ -68,8 +68,11 @@ func (s *swapKit) sendUpdate(ctx context.Context) error {
SwapHash: s.hash, SwapHash: s.hash,
SwapType: s.swapType, SwapType: s.swapType,
LastUpdate: s.lastUpdateTime, LastUpdate: s.lastUpdateTime,
State: s.state, SwapStateData: loopdb.SwapStateData{
HtlcAddress: s.htlc.Address, State: s.state,
Cost: s.cost,
},
HtlcAddress: s.htlc.Address,
} }
s.log.Infof("state %v", info.State) s.log.Infof("state %v", info.State)

@ -79,9 +79,9 @@ func createClientTestContext(t *testing.T,
for _, s := range pendingSwaps { for _, s := range pendingSwaps {
store.loopOutSwaps[s.Hash] = s.Contract store.loopOutSwaps[s.Hash] = s.Contract
updates := []loopdb.SwapState{} updates := []loopdb.SwapStateData{}
for _, e := range s.Events { for _, e := range s.Events {
updates = append(updates, e.State) updates = append(updates, e.SwapStateData)
} }
store.loopOutUpdates[s.Hash] = updates store.loopOutUpdates[s.Hash] = updates
} }

Loading…
Cancel
Save