Skip to content

Commit 1fed617

Browse files
committed
fix(swapclients): check capacity up front
This fixes a bug where the capacity for swap clients is thought to be 0 upon initialization. The checks to update the capacity happen on an interval but not right away. This adds logic to check the capacity immediately. Fixes #900.
1 parent 082d059 commit 1fed617

File tree

7 files changed

+43
-41
lines changed

7 files changed

+43
-41
lines changed

lib/BaseClient.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ abstract class BaseClient extends EventEmitter {
3030
public maximumOutboundCapacity = 0;
3131
protected status: ClientStatus = ClientStatus.NotInitialized;
3232
protected reconnectionTimer?: NodeJS.Timer;
33-
3433
/** Time in milliseconds between attempts to recheck connectivity to the client. */
3534
protected static readonly RECONNECT_TIMER = 5000;
35+
3636
private updateCapacityTimer?: NodeJS.Timer;
3737
/** Time in milliseconds between updating the maximum outbound capacity */
38-
private CAPACITY_REFRESH_INTERVAL = 60000;
38+
private static CAPACITY_REFRESH_INTERVAL = 60000;
3939

4040
constructor(protected logger: Logger) {
4141
super();
@@ -45,28 +45,33 @@ abstract class BaseClient extends EventEmitter {
4545
* Returns the total balance available across all channels.
4646
*/
4747
public abstract channelBalance(): Promise<ChannelBalance>;
48-
protected setStatus(status: ClientStatus): void {
48+
49+
protected setStatus = async (status: ClientStatus): Promise<void> => {
4950
this.logger.info(`${this.constructor.name} status: ${ClientStatus[status]}`);
5051
this.status = status;
51-
this.checkTimers();
52+
await this.setTimers();
5253
}
53-
private checkTimers() {
54+
55+
private setTimers = async () => {
5456
if (this.status === ClientStatus.ConnectionVerified) {
55-
this.updateCapacityTimer = setInterval(async () => {
56-
try {
57-
this.maximumOutboundCapacity = (await this.channelBalance()).balance;
58-
} catch (e) {
59-
// TODO: Mark client as disconnected
60-
this.logger.error(`failed to fetch channelbalance from client: ${e}`);
61-
}
62-
}, this.CAPACITY_REFRESH_INTERVAL);
57+
await this.updateCapacity();
58+
this.updateCapacityTimer = setInterval(this.updateCapacity, BaseClient.CAPACITY_REFRESH_INTERVAL);
6359
} else {
6460
if (this.updateCapacityTimer) {
6561
clearInterval(this.updateCapacityTimer);
6662
}
6763
}
6864
}
6965

66+
private updateCapacity = async () => {
67+
try {
68+
this.maximumOutboundCapacity = (await this.channelBalance()).balance;
69+
} catch (e) {
70+
// TODO: Mark client as disconnected
71+
this.logger.error(`failed to fetch channelbalance from client: ${e}`);
72+
}
73+
}
74+
7075
/**
7176
* Sends payment according to the terms of a swap deal.
7277
* @returns the preimage for the swap

lib/lndclient/LndClient.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class LndClient extends BaseClient {
7979
shouldDisable = true;
8080
}
8181
if (shouldDisable) {
82-
this.setStatus(ClientStatus.Disabled);
82+
await this.setStatus(ClientStatus.Disabled);
8383
return;
8484
}
8585

@@ -96,8 +96,8 @@ class LndClient extends BaseClient {
9696
this.logger.info(`macaroons are disabled for lnd for ${this.currency}`);
9797
}
9898
// set status as disconnected until we can verify the connection
99-
this.setStatus(ClientStatus.Disconnected);
100-
return this.verifyConnection();
99+
await this.setStatus(ClientStatus.Disconnected);
100+
await this.verifyConnection();
101101
}
102102

103103
public get pubKey() {
@@ -178,7 +178,7 @@ class LndClient extends BaseClient {
178178
const getInfoResponse = await this.getInfo();
179179
if (getInfoResponse.getSyncedToChain()) {
180180
// mark connection as active
181-
this.setStatus(ClientStatus.ConnectionVerified);
181+
await this.setStatus(ClientStatus.ConnectionVerified);
182182
if (this.reconnectionTimer) {
183183
clearTimeout(this.reconnectionTimer);
184184
this.reconnectionTimer = undefined;
@@ -193,12 +193,12 @@ class LndClient extends BaseClient {
193193
this.emit('connectionVerified', newPubKey);
194194
this.subscribeInvoices();
195195
} else {
196-
this.setStatus(ClientStatus.OutOfSync);
196+
await this.setStatus(ClientStatus.OutOfSync);
197197
this.logger.error(`lnd for ${this.currency} is out of sync with chain, retrying in ${LndClient.RECONNECT_TIMER} ms`);
198198
this.reconnectionTimer = setTimeout(this.verifyConnection, LndClient.RECHECK_SYNC_TIMER);
199199
}
200200
} catch (err) {
201-
this.setStatus(ClientStatus.Disconnected);
201+
await this.setStatus(ClientStatus.Disconnected);
202202
this.logger.error(`could not verify connection to lnd for ${this.currency} at ${this.uri}, error: ${JSON.stringify(err)},
203203
retrying in ${LndClient.RECONNECT_TIMER} ms`);
204204
this.reconnectionTimer = setTimeout(this.verifyConnection, LndClient.RECONNECT_TIMER);
@@ -382,9 +382,9 @@ class LndClient extends BaseClient {
382382
}
383383

384384
this.invoiceSubscription = this.lightning.subscribeInvoices(new lndrpc.InvoiceSubscription(), this.meta)
385-
.on('error', (error) => {
385+
.on('error', async (error) => {
386386
this.invoiceSubscription = undefined;
387-
this.setStatus(ClientStatus.Disconnected);
387+
await this.setStatus(ClientStatus.Disconnected);
388388
this.logger.error(`lnd for ${this.currency} has been disconnected, error: ${error}`);
389389
this.reconnectionTimer = setTimeout(this.verifyConnection, LndClient.RECONNECT_TIMER);
390390
});

lib/orderbook/OrderBook.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ class OrderBook extends EventEmitter {
311311
throw errors.SWAP_CLIENT_NOT_FOUND(makerCurrency);
312312
}
313313
if (makerAmount > swapClient.maximumOutboundCapacity) {
314-
throw errors.INSUFFICIENT_OUTBOUND_BALANCE(makerCurrency, makerAmount);
314+
throw errors.INSUFFICIENT_OUTBOUND_BALANCE(makerCurrency, makerAmount, swapClient.maximumOutboundCapacity);
315315
}
316316
}
317317

lib/orderbook/errors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ const errors = {
6666
message: `unable to find swap client for currency ${currency}`,
6767
code: errorCodes.SWAP_CLIENT_NOT_FOUND,
6868
}),
69-
INSUFFICIENT_OUTBOUND_BALANCE: (currency: string, amount: number) => ({
70-
message: `${currency} does not have sufficient outbound balance of: ${amount}`,
69+
INSUFFICIENT_OUTBOUND_BALANCE: (currency: string, amount: number, availableAmount: number) => ({
70+
message: `${currency} outbound balance of ${availableAmount} is not sufficient for order amount of ${amount}`,
7171
code: errorCodes.INSUFFICIENT_OUTBOUND_BALANCE,
7272
}),
7373
};

lib/raidenclient/RaidenClient.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class RaidenClient extends BaseClient {
8585
public tokenAddresses = new Map<string, string>();
8686
private port: number;
8787
private host: string;
88+
private disable: boolean;
8889
private repository: OrderBookRepository;
8990

9091
/**
@@ -96,26 +97,21 @@ class RaidenClient extends BaseClient {
9697

9798
this.port = port;
9899
this.host = host;
100+
this.disable = disable;
99101

100102
this.repository = new OrderBookRepository(logger, models);
101-
102-
if (disable) {
103-
this.setStatus(ClientStatus.Disabled);
104-
}
105103
}
106104

107105
/**
108106
* Checks for connectivity and gets our Raiden account address
109107
*/
110108
public init = async () => {
111-
if (this.isDisabled()) {
112-
this.logger.error(`can't init raiden. raiden is disabled`);
109+
if (this.disable) {
110+
await this.setStatus(ClientStatus.Disabled);
113111
return;
114112
}
115113
// associate the client with all currencies that have a contract address
116114
await this.setCurrencies();
117-
// set status as disconnected until we can verify the connection
118-
this.setStatus(ClientStatus.Disconnected);
119115
await this.verifyConnection();
120116
}
121117

@@ -152,7 +148,7 @@ class RaidenClient extends BaseClient {
152148
}
153149

154150
this.emit('connectionVerified', newAddress);
155-
this.setStatus(ClientStatus.ConnectionVerified);
151+
await this.setStatus(ClientStatus.ConnectionVerified);
156152
} catch (err) {
157153
this.logger.error(
158154
`could not verify connection to raiden at ${this.host}:${this.port}, retrying in ${RaidenClient.RECONNECT_TIMER} ms`,
@@ -321,6 +317,7 @@ class RaidenClient extends BaseClient {
321317
* Returns the total balance available across all channels.
322318
*/
323319
public channelBalance = async (): Promise<ChannelBalance> => {
320+
// TODO: refine logic to determine balance per token rather than all combined
324321
const channels = await this.getChannels();
325322
const balance = channels.filter(channel => channel.state === 'opened')
326323
.map(channel => channel.balance)

test/simulation/xud_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func testOrderMatchingAndSwap(net *xudtest.NetworkHarness, ht *harnessTest) {
132132
func testOrderBroadcastAndInvalidation(net *xudtest.NetworkHarness, ht *harnessTest) {
133133
req := &xudrpc.PlaceOrderRequest{
134134
Price: 10,
135-
Quantity: 1000000000,
135+
Quantity: 1000000,
136136
PairId: "LTC/BTC",
137137
OrderId: "random_order_id",
138138
Side: xudrpc.OrderSide_BUY,

test/simulation/xudtest/node.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ package xudtest
33
import (
44
"bytes"
55
"fmt"
6-
"github.com/ExchangeUnion/xud-simulation/lntest"
7-
"github.com/ExchangeUnion/xud-simulation/xudrpc"
8-
"github.com/go-errors/errors"
9-
"golang.org/x/net/context"
10-
"google.golang.org/grpc"
11-
"google.golang.org/grpc/credentials"
126
"net"
137
"os"
148
"os/exec"
@@ -17,6 +11,13 @@ import (
1711
"sync"
1812
"sync/atomic"
1913
"time"
14+
15+
"github.com/ExchangeUnion/xud-simulation/lntest"
16+
"github.com/ExchangeUnion/xud-simulation/xudrpc"
17+
"github.com/go-errors/errors"
18+
"golang.org/x/net/context"
19+
"google.golang.org/grpc"
20+
"google.golang.org/grpc/credentials"
2021
)
2122

2223
var (
@@ -50,7 +51,6 @@ func (cfg nodeConfig) genArgs() []string {
5051
var args []string
5152

5253
args = append(args, "--initdb=false")
53-
args = append(args, "--nosanitychecks=true")
5454
args = append(args, "--loglevel=debug")
5555
args = append(args, "--raiden.disable")
5656

0 commit comments

Comments
 (0)