Browse Source

Added some basic start/stop helper methods.

Added some default peers to connect to randomly.
get-transaction-merkle
Corey Phillips 4 years ago
parent
commit
a3a1a9a36d
No known key found for this signature in database GPG Key ID: 80C0975F55D3A07B
  1. 32
      helpers/clients.js
  2. 244
      helpers/index.js
  3. 29
      helpers/peers.json

32
helpers/clients.js

@ -0,0 +1,32 @@
class Clients {
constructor() {
this.network = "bitcoin";
this.mainClient = {
bitcoin: false,
bitcoinTestnet: false
};
this.peer = {
bitcoin: { port: 0, host: "", protocol: "" },
bitcoinTestnet: { port: 0, host: "", protocol: "" }
};
this.peers = {
bitcoin: [],
bitcoinTestnet: []
};
}
updateNetwork(network) {
this.network = network;
}
updateMainClient(mainClient) {
this.mainClient = mainClient;
}
updatePeer(peer) {
this.peer = peer;
}
}
module.exports = new Clients();

244
helpers/index.js

@ -0,0 +1,244 @@
const ElectrumClient = require("../lib/electrum_client");
const clients = require("./clients");
let electrumKeepAlive = () => null;
let electrumKeepAliveInterval = 60000;
const getTimeout = ({ arr = undefined, timeout = 1000 } = {}) => {
try {
if (arr && Array.isArray(arr)) return arr.length * timeout;
return timeout;
} catch {
return timeout;
}
}
const promiseTimeout = (ms, promise) => {
let id;
let timeout = new Promise((resolve) => {
id = setTimeout(() => {
resolve({ error: true, data: "Timed Out." });
}, ms);
});
return Promise.race([
promise,
timeout
]).then((result) => {
clearTimeout(id);
try {if ("error" in result && "data" in result) return result;} catch {}
return { error: false, data: result };
});
};
const pauseExecution = (duration = 500) => {
return new Promise(async (resolve) => {
try {
const wait = () => resolve({error: false});
await setTimeout(wait, duration);
} catch (e) {
console.log(e);
resolve({error: true});
}
});
};
const getDefaultPeers = (network, protocol) => {
return require("./peers.json")[network].map(peer => {
try {
return { ...peer, protocol };
} catch {}
});
};
const pingServer = ({ id = Math.random() } = {}) => {
const method = "pingServer";
return new Promise(async (resolve) => {
try {
if (clients.mainClient[clients.network] === false) await connectToRandomPeer(clients.network, clients.peers[clients.network]);
const { error, data } = await promiseTimeout(getTimeout(), clients.mainClient[clients.network].server_ping());
resolve({ id, error, method, data });
} catch (e) {
resolve({ id, error: true, method, data: e });
}
});
};
//peers = A list of peers acquired from default electrum servers using the getPeers method.
//customPeers = A list of peers added by the user to connect to by default in lieu of the default peer list.
const start = ({ id = Math.random(), network = "", peers = [], customPeers = []} = {}) => {
const method = "connectToPeer";
return new Promise(async (resolve) => {
try {
if (!network) resolve({error: true, data: {}});
//Clear/Remove any previous keep-alive message.
try {clearInterval(electrumKeepAlive);} catch {}
clients.network = network;
let customPeersLength = 0;
try {customPeersLength = customPeers.length;} catch {}
//Attempt to connect to specified peer
let connectionResponse = { error: true, data: "" };
if (customPeersLength > 0) {
const { host = "", port = "", protocol = "ssl" } = customPeers[0];
connectionResponse = await connectToPeer({ host, port, protocol, network });
} else {
//Attempt to connect to random peer if none specified
connectionResponse = await connectToRandomPeer(network, peers);
}
resolve({
...connectionResponse,
id,
method: "connectToPeer",
customPeers,
network
});
} catch (e) {
console.log(e);
resolve({ error: true, method, data: e });
}
});
};
const connectToPeer = ({ port = 50002, host = "", protocol = "ssl", network = "bitcoin" } = {}) => {
return new Promise(async (resolve) => {
try {
clients.network = network;
let needToConnect = clients.mainClient[network] === false;
let connectionResponse = { error: false, data: clients.peer[network] };
if (!needToConnect) {
//Ensure the server is still alive
const pingResponse = await pingServer();
if (pingResponse.error) {
await disconnectFromPeer({ network });
needToConnect = true;
}
}
if (needToConnect) {
clients.mainClient[network] = new ElectrumClient(port, host, protocol);
connectionResponse = await promiseTimeout(1000, clients.mainClient[network].connect());
if (!connectionResponse.error) {
try {
//Clear/Remove Electrum's keep-alive message.
clearInterval(electrumKeepAlive);
//Start Electrum's keep-alive function. It’s sent every minute as a keep-alive message.
electrumKeepAlive = setInterval(async () => {
try {pingServer({ id: Math.random() });} catch {}
}, electrumKeepAliveInterval);
} catch (e) {}
clients.peer[network] = { port, host, protocol };
}
}
await pauseExecution();
resolve(connectionResponse);
} catch (e) {resolve({ error: true, data: e });}
});
};
const connectToRandomPeer = async (network, peers = [], protocol = "ssl") => {
//Peers can be found in peers.json.
//Additional Peers can be located here in servers.json & servers_testnet.json for reference: https://github.com/spesmilo/electrum/tree/master/electrum
let hasPeers = false;
try {
hasPeers = (Array.isArray(peers) && peers.length) || (Array.isArray(clients.peers[network]) && clients.peers[network].length);
} catch {}
if (hasPeers) {
if (Array.isArray(peers) && peers.length) {
//Update peer list
clients.peers[network] = peers;
} else {
//Set the saved peer list
peers = clients.peers[network];
}
} else {
//Use the default peer list for a connection if no other peers were passed down and no saved peer list is present.
peers = getDefaultPeers(network, protocol);
}
const initialPeerLength = peers.length; //Acquire length of our default peers.
//Attempt to connect to a random default peer. Continue to iterate through default peers at random if unable to connect.
for (let i = 0; i <= initialPeerLength; i++) {
try {
const randomIndex = peers.length * Math.random() | 0;
const peer = peers[randomIndex];
let port = "50002";
let host = "";
if (hasPeers) {
port = peer.port;
host = peer.host;
protocol = peer.protocol;
} else {
port = peer[peer.protocol];
host = peer.host;
protocol = peer.protocol;
}
const connectionResponse = await connectToPeer({ port, host, protocol, network });
if (connectionResponse.error === false && connectionResponse.data) {
return {
error: connectionResponse.error,
method: "connectToRandomPeer",
data: connectionResponse.data,
network
};
} else {
//clients.mainClient[network].close && clients.mainClient[network].close();
clients.mainClient[network] = false;
if (peers.length === 1) {
return {
error: true,
method: "connectToRandomPeer",
data: connectionResponse.data,
network
};
}
peers.splice(randomIndex, 1);
}
} catch (e) {console.log(e);}
}
return { error: true, method: "connectToRandomPeer", data: "Unable to connect to any peer." };
};
const stop = async ({ network = "" } = {}) => {
return new Promise(async (resolve) => {
try {
//Clear/Remove Electrum's keep-alive message.
clearInterval(electrumKeepAlive);
//Disconnect from peer
const response = await disconnectFromPeer({ network });
resolve(response);
} catch (e) {
resolve({ error: true, data: e });
}
});
};
const disconnectFromPeer = async ({ id = Math.random(), network = "" } = {}) => {
const failure = (data = {}) => {
return { error: true, id, method: "disconnectFromPeer", data };
};
try {
//console.log("Disconnecting from any previous peer...");
if (clients.mainClient[network] === false) {
//No peer to disconnect from...
return {
error: false,
data: "No peer to disconnect from.",
id,
network,
method: "disconnectFromPeer"
};
}
//Attempt to disconnect from peer...
clients.mainClient[network].close();
clients.mainClient[network] = false;
clients.network = "";
await pauseExecution();
return { error: false, id, method: "disconnectFromPeer", network, data: "Disconnected..." };
} catch (e) {
failure(e);
}
};
module.exports = {
start,
stop
};

29
helpers/peers.json

@ -0,0 +1,29 @@
{
"bitcoin": [
{"host": "bitcoin.lukechilds.co", "ssl": 50002, "tcp": 50001},
{"host": "electrumx.nmdps", "ssl": 50002, "tcp": 50001},
{"host": "oneweek.duckdns.org", "ssl": 50002, "tcp": 50001},
{"host": "electrum.vom-stausee.de", "ssl": 50002, "tcp": 50001},
{"host": "electrum.hsmiths.com", "ssl": 50002, "tcp": 50001},
{"host": "electrum.hodlister.co", "ssl": 50002, "tcp": 50001},
{"host": "electrum3.hodlister.co", "ssl": 50002, "tcp": 50001},
{"host": "btc.usebsv.com", "ssl": 50006, "tcp": 50001},
{"host": "fortress.qtornado.com", "ssl": 443, "tcp": 50001},
{"host": "ecdsa.net", "ssl": 110, "tcp": 50001},
{"host": "electrum.be", "ssl": 50002, "tcp": 50001},
{"host": "elex01.blackpole.online", "ssl": 50002, "tcp": 50001},
{"host": "kirsche.emzy.de", "ssl": 50002, "tcp": 50001},
{"host": "Electrum.hsmiths.com", "ssl": 50002, "tcp": 50001},
{"host": "elec.luggs.co", "ssl": 443, "tcp": 50001},
{"host": "btc.smsys.me", "ssl": 995, "tcp": 110}
],
"bitcoinTestnet": [
{"host": "testnet.hsmiths.com", "ssl": 53012, "tcp": 53011},
{"host": "testnet1.bauerj.eu", "ssl": 50002, "tcp": 50001},
{"host": "tn.not.fyi", "ssl": 55002, "tcp": 55001},
{"host": "bitcoin.cluelessperson.com", "ssl": 51002, "tcp": 51001},
{"host": "electrum.blockstream.info", "ssl": 60002, "tcp": 60001},
{"host": "testnet.aranguren.org", "ssl": 51002, "tcp": 51001},
{"host": "blockstream.info", "ssl": 993, "tcp": 143}
]
}
Loading…
Cancel
Save