Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lock file #2011

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions lib/Xud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ class Xud extends EventEmitter {
public service!: Service;
private logger!: Logger;
private config: Config;
private db!: DB;
private pool!: Pool;
private orderBook!: OrderBook;
private db?: DB;
private pool?: Pool;
private orderBook?: OrderBook;
private rpcServer?: GrpcServer;
private httpServer?: HttpServer;
private grpcAPIProxy?: GrpcWebProxyServer;
Expand All @@ -46,6 +46,7 @@ class Xud extends EventEmitter {
private swapClientManager?: SwapClientManager;
private unitConverter?: UnitConverter;
private simnetChannels$?: Subscription;
private lockFilePath?: string;

/**
* Create an Exchange Union daemon.
Expand Down Expand Up @@ -88,6 +89,24 @@ class Xud extends EventEmitter {
}

try {
if (this.config.instanceid === 0) {
// if we're not running with multiple instances as indicated by an instance id of 0
// create a lock file to prevent multiple xud instances from trying to run
// with the same node key and/or database
const lockFilePath = path.join(this.config.xudir, `${this.config.network}.lock`);
try {
await (await fs.open(lockFilePath, 'wx')).close();
this.lockFilePath = lockFilePath;
} catch (err) {
if (err.code === 'EEXIST') {
this.logger.error(`A lock file exists at ${lockFilePath}. Another xud process is running or a previous process exited ungracefully.`);
return;
} else {
throw err;
}
}
}

if (!this.config.rpc.disable) {
// start rpc server first, it will respond with UNAVAILABLE error
// indicating xud is starting until xud finishes initializing
Expand Down Expand Up @@ -296,6 +315,10 @@ class Xud extends EventEmitter {
// TODO: ensure we are not in the middle of executing any trades
const closePromises: Promise<void>[] = [];

if (this.lockFilePath) {
closePromises.push(fs.unlink(this.lockFilePath).catch(this.logger.error));
}

this.simnetChannels$?.unsubscribe();

if (this.swapClientManager) {
Expand All @@ -318,7 +341,7 @@ class Xud extends EventEmitter {
}
await Promise.all(closePromises);

await this.db.close();
await this.db?.close();
this.logger.info('XUD shutdown gracefully');

this.emit('shutdown');
Expand Down
2 changes: 1 addition & 1 deletion lib/service/Service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ProvidePreimageEvent, TransferReceivedEvent } from '../connextclient/ty
import { OrderSide, Owner, SwapClientType, SwapRole } from '../constants/enums';
import { OrderAttributes, TradeInstance } from '../db/types';
import Logger, { Level, LevelPriority } from '../Logger';
import NodeKey from '../nodekey/NodeKey';
import OrderBook from '../orderbook/OrderBook';
import { Currency, isOwnOrder, Order, OrderPortion, OwnLimitOrder, OwnMarketOrder, OwnOrder, PeerOrder, PlaceOrderEvent } from '../orderbook/types';
import Pool from '../p2p/Pool';
Expand All @@ -19,7 +20,6 @@ import { checkDecimalPlaces, sortOrders, toEip55Address } from '../utils/utils';
import commitHash from '../Version';
import errors from './errors';
import { NodeIdentifier, ServiceComponents, ServiceOrder, ServiceOrderSidesArrays, ServicePlaceOrderEvent, ServiceTrade, XudInfo } from './types';
import NodeKey from 'lib/nodekey/NodeKey';

/** Functions to check argument validity and throw [[INVALID_ARGUMENT]] when invalid. */
const argChecks = {
Expand Down
2 changes: 1 addition & 1 deletion test/integration/Service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ describe('API Service', () => {
});

it('should remove an order', () => {
const tp = xud['orderBook'].tradingPairs.get('LTC/BTC')!;
const tp = xud['orderBook']!.tradingPairs.get('LTC/BTC')!;
expect(tp.ownOrders.buyMap.has(orderId!)).to.be.true;
const args = {
orderId: '1',
Expand Down
10 changes: 5 additions & 5 deletions test/p2p/networks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ describe('P2P Networks Tests', () => {
await Promise.all([srcNode.start(srcNodeConfig), destNode.start(destNodeConfig)]);

const host = 'localhost';
const port = destNode['pool']['listenPort']!;
const nodePubKey = destNode['pool'].nodePubKey;
const port = destNode['pool']!['listenPort']!;
const nodePubKey = destNode['pool']!.nodePubKey;
const nodeTwoUri = toUri({ host, port, nodePubKey });

const rejectionMsg = `Peer ${nodePubKey}@${host}:${port} closed due to WireProtocolErr framer: incompatible msg origin network (expected: ${srcNodeNetwork}, found: ${destNodeNetwork})`;
Expand All @@ -39,11 +39,11 @@ describe('P2P Networks Tests', () => {
const srcNode = new Xud();
const destNode = new Xud();
await Promise.all([srcNode.start(srcNodeConfig), destNode.start(destNodeConfig)]);
const srcNodePubKey = srcNode['pool'].nodePubKey;
const destNodePubKey = destNode['pool'].nodePubKey;
const srcNodePubKey = srcNode['pool']!.nodePubKey;
const destNodePubKey = destNode['pool']!.nodePubKey;

const host = 'localhost';
const port = destNode['pool']['listenPort']!;
const port = destNode['pool']!['listenPort']!;
const nodeTwoUri = toUri({ host, port, nodePubKey: destNodePubKey });

await expect(srcNode.service.connect({ nodeUri: nodeTwoUri, retryConnecting: false })).to.be.fulfilled;
Expand Down
14 changes: 7 additions & 7 deletions test/p2p/sanity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ describe('P2P Sanity Tests', () => {

await Promise.all([nodeOne.start(nodeOneConfig), nodeTwo.start(nodeTwoConfig)]);

nodeOnePubKey = nodeOne['pool'].nodePubKey;
nodeTwoPubKey = nodeTwo['pool'].nodePubKey;
nodeOnePubKey = nodeOne['pool']!.nodePubKey;
nodeTwoPubKey = nodeTwo['pool']!.nodePubKey;

nodeTwoPort = nodeTwo['pool']['listenPort']!;
nodeOneUri = toUri({ nodePubKey: nodeOnePubKey, host: 'localhost', port: nodeOne['pool']['listenPort']! });
nodeTwoPort = nodeTwo['pool']!['listenPort']!;
nodeOneUri = toUri({ nodePubKey: nodeOnePubKey, host: 'localhost', port: nodeOne['pool']!['listenPort']! });
nodeTwoUri = toUri({ nodePubKey: nodeTwoPubKey, host: 'localhost', port: nodeTwoPort });

unusedPort = await getUnusedPort();
Expand All @@ -82,13 +82,13 @@ describe('P2P Sanity Tests', () => {

it('should update the node state', (done) => {
const btcPubKey = '0395033b252c6f40e3756984162d68174e2bd8060a129c0d3462a9370471c6d28f';
const nodeTwoPeer = nodeOne['pool'].getPeer(nodeTwoPubKey);
const nodeTwoPeer = nodeOne['pool']!.getPeer(nodeTwoPubKey);
nodeTwoPeer.on('nodeStateUpdate', () => {
expect(nodeTwoPeer['nodeState']!.lndPubKeys['BTC']).to.equal(btcPubKey);
done();
});

nodeTwo['pool'].updateLndState({
nodeTwo['pool']!.updateLndState({
currency: 'BTC',
pubKey: btcPubKey,
});
Expand All @@ -100,7 +100,7 @@ describe('P2P Sanity Tests', () => {
});

it('should disconnect successfully', async () => {
await nodeOne['pool']['closePeer'](nodeTwoPubKey, DisconnectionReason.NotAcceptingConnections);
await nodeOne['pool']!['closePeer'](nodeTwoPubKey, DisconnectionReason.NotAcceptingConnections);

const listPeersResult = nodeOne.service.listPeers();
expect(listPeersResult).to.be.empty;
Expand Down
30 changes: 15 additions & 15 deletions test/simulation/custom-xud.patch
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
diff --git a/lib/Xud.ts b/lib/Xud.ts
index 489a50a4..f9391527 100644
index d83880e0..1b95a77a 100644
--- a/lib/Xud.ts
+++ b/lib/Xud.ts
@@ -87,6 +87,11 @@ class Xud extends EventEmitter {
@@ -88,6 +88,11 @@ class Xud extends EventEmitter {
this.logger.info('config file loaded');
}

Expand All @@ -12,8 +12,8 @@ index 489a50a4..f9391527 100644
+ }
+
try {
if (!this.config.rpc.disable) {
// start rpc server first, it will respond with UNAVAILABLE error
if (this.config.instanceid === 0) {
// if we're not running with multiple instances as indicated by an instance id of 0
diff --git a/lib/swaps/SwapRecovery.ts b/lib/swaps/SwapRecovery.ts
index 3759f6a3..4089dc94 100644
--- a/lib/swaps/SwapRecovery.ts
Expand All @@ -39,10 +39,10 @@ index 3759f6a3..4089dc94 100644
}

diff --git a/lib/swaps/Swaps.ts b/lib/swaps/Swaps.ts
index 9648e02b..0e850119 100644
index c6946347..730cf781 100644
--- a/lib/swaps/Swaps.ts
+++ b/lib/swaps/Swaps.ts
@@ -730,6 +730,24 @@ class Swaps extends EventEmitter {
@@ -699,6 +699,24 @@ class Swaps extends EventEmitter {
} else if (deal.state === SwapState.Active) {
// we check that the deal is still active before we try to settle the invoice
try {
Expand All @@ -67,7 +67,7 @@ index 9648e02b..0e850119 100644
await swapClient.settleInvoice(rHash, rPreimage, currency);
} catch (err) {
this.logger.error(`could not settle invoice for deal ${rHash}`, err);
@@ -750,7 +768,9 @@ class Swaps extends EventEmitter {
@@ -719,7 +737,9 @@ class Swaps extends EventEmitter {
} catch (err) {
this.logger.error(`could not settle invoice for deal ${rHash}`, err);
}
Expand All @@ -78,7 +78,7 @@ index 9648e02b..0e850119 100644
});
await settleRetryPromise;
} else {
@@ -774,6 +794,16 @@ class Swaps extends EventEmitter {
@@ -743,6 +763,16 @@ class Swaps extends EventEmitter {
* accepted, initiates the swap.
*/
private handleSwapAccepted = async (responsePacket: packets.SwapAcceptedPacket, peer: Peer) => {
Expand All @@ -95,7 +95,7 @@ index 9648e02b..0e850119 100644
assert(responsePacket.body, 'SwapAcceptedPacket does not contain a body');
const { quantity, rHash, makerCltvDelta } = responsePacket.body;
const deal = this.getDeal(rHash);
@@ -861,6 +891,11 @@ class Swaps extends EventEmitter {
@@ -830,6 +860,11 @@ class Swaps extends EventEmitter {

try {
await makerSwapClient.sendPayment(deal);
Expand All @@ -107,7 +107,7 @@ index 9648e02b..0e850119 100644
} catch (err) {
// first we must handle the edge case where the maker has paid us but failed to claim our payment
// in this case, we've already marked the swap as having been paid and completed
@@ -1042,6 +1077,18 @@ class Swaps extends EventEmitter {
@@ -1011,6 +1046,18 @@ class Swaps extends EventEmitter {

this.logger.debug('Executing maker code to resolve hash');

Expand All @@ -126,7 +126,7 @@ index 9648e02b..0e850119 100644
const swapClient = this.swapClientManager.get(deal.takerCurrency)!;

// we update the phase persist the deal to the database before we attempt to send payment
@@ -1052,6 +1099,13 @@ class Swaps extends EventEmitter {
@@ -1021,6 +1068,13 @@ class Swaps extends EventEmitter {
assert(deal.state !== SwapState.Error, `cannot send payment for failed swap ${deal.rHash}`);

try {
Expand All @@ -140,7 +140,7 @@ index 9648e02b..0e850119 100644
deal.rPreimage = await swapClient.sendPayment(deal);
} catch (err) {
this.logger.debug(`sendPayment in resolveHash for swap ${deal.rHash} failed due to ${err.message}`);
@@ -1129,10 +1183,22 @@ class Swaps extends EventEmitter {
@@ -1098,10 +1152,22 @@ class Swaps extends EventEmitter {
}
}

Expand All @@ -164,7 +164,7 @@ index 9648e02b..0e850119 100644
return deal.rPreimage;
} else {
// If we are here we are the taker
@@ -1140,6 +1206,16 @@ class Swaps extends EventEmitter {
@@ -1109,6 +1175,16 @@ class Swaps extends EventEmitter {
assert(htlcCurrency === undefined || htlcCurrency === deal.takerCurrency, 'incoming htlc does not match expected deal currency');
this.logger.debug('Executing taker code to resolve hash');

Expand All @@ -181,7 +181,7 @@ index 9648e02b..0e850119 100644
return deal.rPreimage;
}
}
@@ -1308,8 +1384,11 @@ class Swaps extends EventEmitter {
@@ -1277,8 +1353,11 @@ class Swaps extends EventEmitter {
swapClient.removeInvoice(deal.rHash).catch(this.logger.error); // we don't need to await the remove invoice call
}
} else if (deal.phase === SwapPhase.SendingPayment) {
Expand All @@ -195,7 +195,7 @@ index 9648e02b..0e850119 100644
}

this.logger.trace(`emitting swap.failed event for ${deal.rHash}`);
@@ -1373,9 +1452,14 @@ class Swaps extends EventEmitter {
@@ -1343,9 +1422,14 @@ class Swaps extends EventEmitter {

if (deal.role === SwapRole.Maker) {
// the maker begins execution of the swap upon accepting the deal
Expand Down