Browse Source

poc, balance, utxo, listtransactions

insight-spv
pbca26 7 years ago
parent
commit
ed827c7bf1
  1. 4
      package.json
  2. 9
      routes/electrumjs/electrumServers.js
  3. 12
      routes/electrumjs/electrumjs.networks.js
  4. 1
      routes/shepherd.js
  5. 12
      routes/shepherd/electrum/balance.js
  6. 2
      routes/shepherd/electrum/btcFees.js
  7. 201
      routes/shepherd/electrum/insight.js
  8. 4
      routes/shepherd/electrum/listunspent.js
  9. 4
      routes/shepherd/electrum/network.js
  10. 42
      routes/shepherd/electrum/transactions.js
  11. 6
      version
  12. 2
      version_build

4
package.json

@ -24,7 +24,7 @@
"author": "SuperNET Team",
"license": "MIT",
"devDependencies": {
"electron": "1.8.3"
"electron": "1.8.4"
},
"dependencies": {
"adm-zip": "^0.4.7",
@ -40,7 +40,7 @@
"body-parser": "^1.15.2",
"buffer-reverse": "^1.0.1",
"coinselect": "github:bitcoinjs/coinselect",
"electron": "1.8.3",
"electron": "1.8.4",
"express": "^4.14.0",
"fix-path": "^2.1.0",
"fs-extra": "^4.0.2",

9
routes/electrumjs/electrumServers.js

@ -548,6 +548,15 @@ let electrumServers = {
's2.qtum.info:50001'
],
},
aby: {
address: 'http://explorer.artbyte.me',
port: 'none',
proto: 'insight',
insightRawApi: false,
txfee: 100000,
abbr: 'ABY',
serverList: 'none',
},
};
electrumServers.crw = electrumServers.crown;

12
routes/electrumjs/electrumjs.networks.js

@ -374,6 +374,18 @@ networks.grs = { // fails to gen a proper addr
dustThreshold: 1000,
};
networks.aby = {
messagePrefix: '\x19Crown Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x17,
scriptHash: 0x5,
wif: 0x97,
dustThreshold: 1000,
};
networks.btc = networks.bitcoin;
networks.crw = networks.crown;
networks.dgb = networks.digibyte;

1
routes/shepherd.js

@ -104,6 +104,7 @@ shepherd = require('./shepherd/electrum/interest.js')(shepherd);
shepherd = require('./shepherd/electrum/listunspent.js')(shepherd);
shepherd = require('./shepherd/electrum/estimate.js')(shepherd);
shepherd = require('./shepherd/electrum/btcFees.js')(shepherd);
shepherd = require('./shepherd/electrum/insight.js')(shepherd);
// dex
shepherd = require('./shepherd/dex/coind.js')(shepherd);

12
routes/shepherd/electrum/balance.js

@ -2,7 +2,7 @@ module.exports = (shepherd) => {
shepherd.get('/electrum/getbalance', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const network = req.query.network || shepherd.findNetworkObj(req.query.coin);
const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
const ecl = shepherd.electrumServers[network].proto === 'insight' ? shepherd.insightJSCore(shepherd.electrumServers[network]) : new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
shepherd.log('electrum getbalance =>', true);
@ -14,7 +14,7 @@ module.exports = (shepherd) => {
json.hasOwnProperty('unconfirmed')) {
if (network === 'komodo') {
ecl.blockchainAddressListunspent(req.query.address)
.then((utxoList) => {
.then((utxoList) => {
if (utxoList &&
utxoList.length) {
// filter out < 10 KMD amounts
@ -45,7 +45,7 @@ module.exports = (shepherd) => {
// decode tx
const _network = shepherd.getNetworkData(network);
const decodedTx = shepherd.electrumJSTxDecoder(_rawtxJSON, network, _network);
const decodedTx = shepherd.electrumJSTxDecoder(_rawtxJSON, network, _network, shepherd.electrumServers[network].proto === 'insight');
if (decodedTx &&
decodedTx.format &&
@ -81,7 +81,7 @@ module.exports = (shepherd) => {
});
} else {
ecl.close();
const successObj = {
msg: 'success',
result: {
@ -100,7 +100,7 @@ module.exports = (shepherd) => {
}
} else {
ecl.close();
const successObj = {
msg: 'success',
result: {
@ -137,7 +137,7 @@ module.exports = (shepherd) => {
}
} else {
ecl.close();
const successObj = {
msg: 'error',
result: shepherd.CONNECTION_ERROR_OR_INCOMPLETE_DATA,

2
routes/shepherd/electrum/btcFees.js

@ -92,7 +92,7 @@ module.exports = (shepherd) => {
});
});
} else {
console.log(`btcfees, use cache`);
shepherd.log('btcfees, use cache', true);
const successObj = {
msg: 'success',

201
routes/shepherd/electrum/insight.js

@ -0,0 +1,201 @@
const request = require('request');
// abstraction layer to communicate with insight explorers
module.exports = (shepherd) => {
/*shepherd.httpReq = (url, type) => {
};*/
shepherd.insightJSCoreActiveCoin = {};
shepherd.insightJSCore = (electrumServer) => {
shepherd.log('insight =>');
shepherd.log(electrumServer, true);
if (electrumServer) {
shepherd.insightJSCoreActiveCoin = electrumServer;
}
return {
insight: true,
connect: () => {
shepherd.log('insight fake connect', true);
},
close: () => {
shepherd.log('insight fake close', true);
},
blockchainAddressGetBalance: (address) => {
shepherd.log('insight blockchainAddressGetBalance', true);
return new shepherd.Promise((resolve, reject) => {
let options = {
url: `${shepherd.insightJSCoreActiveCoin.address}/api/addr/${address}/utxo`,
method: 'GET',
};
console.log(`${shepherd.insightJSCoreActiveCoin.address}/api/addr/${address}/utxo`);
// send back body on both success and error
// this bit replicates iguana core's behaviour
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
try {
const _parsedBody = JSON.parse(body);
console.log(_parsedBody);
if (_parsedBody) {
let _balance = 0;
for (let i = 0; i < _parsedBody.length; i++) {
_balance += Number(_parsedBody[i].amount);
}
resolve({
confirmed: _balance * 100000000,
unconfirmed: 0,
});
}
shepherd.log(`insight blockchainAddressGetBalance ${address}`);
} catch (e) {
shepherd.log(`parse error insight blockchainAddressGetBalance ${address}`, true);
}
} else {
shepherd.log(`req error insight blockchainAddressGetBalance ${address}`, true);
}
});
});
},
blockchainAddressListunspent: (address) => {
shepherd.log('insight blockchainAddressListunspent', true);
return new shepherd.Promise((resolve, reject) => {
let options = {
url: `${shepherd.insightJSCoreActiveCoin.address}/api/addr/${address}/utxo`,
method: 'GET',
};
console.log(`${shepherd.insightJSCoreActiveCoin.address}/api/addr/${address}/utxo`);
// send back body on both success and error
// this bit replicates iguana core's behaviour
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
try {
const _parsedBody = JSON.parse(body);
console.log(_parsedBody);
if (_parsedBody) {
let _utxos = [];
for (let i = 0; i < _parsedBody.length; i++) {
_utxos.push({
txid: _parsedBody[i].txid,
vout: _parsedBody[i].vout,
address: _parsedBody[i].address,
amount: Number(_parsedBody[i].amount),
amountSats: Number(_parsedBody[i].amount) * 100000000,
confirmations: _parsedBody[i].confirmations,
spendable: true,
verified: false,
});
}
resolve(_utxos);
}
shepherd.log(`insight blockchainAddressListunspent ${address}`);
} catch (e) {
shepherd.log(`parse error insight blockchainAddressListunspent ${address}`, true);
}
} else {
shepherd.log(`req error insight blockchainAddressListunspent ${address}`, true);
}
});
});
},
blockchainAddressGetHistory: (address) => {
shepherd.log('insight blockchainAddressGetHistory', true);
return new shepherd.Promise((resolve, reject) => {
let options = {
url: `${shepherd.insightJSCoreActiveCoin.address}/api/txs/?address=${address}`,
method: 'GET',
};
console.log(`${shepherd.insightJSCoreActiveCoin.address}/api/txs/?address=${address}`);
// send back body on both success and error
// this bit replicates iguana core's behaviour
request(options, (error, response, body) => {
if (response &&
response.statusCode &&
response.statusCode === 200) {
try {
const _parsedBody = JSON.parse(body);
console.log(_parsedBody.txs);
if (_parsedBody &&
_parsedBody.txs) {
const _txs = _parsedBody.txs;
let txs = [];
for (let i = 0; i < _txs.length; i++) {
const _parsedTx = {
format: {
txid: _txs[i].txid,
version: _txs[i].version,
locktime: _txs[i].locktime,
},
inputs: _txs[i].vin,
outputs: _txs[i].vout,
timestamp: _txs[i].time,
confirmations: _txs[i].confirmations,
};
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, address, shepherd.insightJSCoreActiveCoin.abbr.toLowerCase());
if (formattedTx.type) {
formattedTx.blocktime = _parsedTx.timestamp;
formattedTx.timereceived = _parsedTx.timestamp;
formattedTx.hex = 'N/A';
formattedTx.inputs = _parsedTx.inputs;
formattedTx.outputs = _parsedTx.outputs;
formattedTx.locktime = _parsedTx.format.locktime;
txs.push(formattedTx);
} else {
formattedTx[0].blocktime = _parsedTx.timestamp;
formattedTx[0].timereceived = _parsedTx.timestamp;
formattedTx[0].hex = 'N/A';
formattedTx[0].inputs = _parsedTx.inputs;
formattedTx[0].outputs = _parsedTx.outputs;
formattedTx[0].locktime = _parsedTx.format.locktime;
formattedTx[1].blocktime = _parsedTx.timestamp;
formattedTx[1].timereceived = _parsedTx.timestamp;
formattedTx[1].hex = 'N/A';
formattedTx[1].inputs = _parsedTx.inputs;
formattedTx[1].outputs = _parsedTx.outputs;
formattedTx[1].locktime = _parsedTx.format.locktime;
txs.push(formattedTx[0]);
txs.push(formattedTx[1]);
}
}
resolve(txs);
}
shepherd.log(`insight blockchainAddressGetHistory ${address}`);
} catch (e) {
shepherd.log(`parse error insight blockchainAddressGetHistory ${address}`, true);
}
} else {
shepherd.log(`req error insight blockchainAddressGetHistory ${address}`, true);
}
});
});
},
};
};
return shepherd;
}

4
routes/shepherd/electrum/listunspent.js

@ -4,7 +4,7 @@ module.exports = (shepherd) => {
shepherd.listunspent = (ecl, address, network, full, verify) => {
let _atLeastOneDecodeTxFailed = false;
if (full) {
if (full && !ecl.insight) {
return new shepherd.Promise((resolve, reject) => {
ecl.connect();
ecl.blockchainAddressListunspent(address)
@ -161,7 +161,7 @@ module.exports = (shepherd) => {
shepherd.get('/electrum/listunspent', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const network = req.query.network || shepherd.findNetworkObj(req.query.coin);
const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
const ecl = shepherd.electrumServers[network].proto === 'insight' ? shepherd.insightJSCore(shepherd.electrumServers[network]) : new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
if (req.query.full &&
req.query.full === 'true') {

4
routes/shepherd/electrum/network.js

@ -31,11 +31,13 @@ module.exports = (shepherd) => {
}
};
shepherd.electrumJSTxDecoder = (rawtx, networkName, network) => {
shepherd.electrumJSTxDecoder = (rawtx, networkName, network, insight) => {
if (shepherd.isZcash(networkName)) {
return txDecoder.zcash(rawtx, network);
} else if (shepherd.isPos(networkName)) {
return txDecoder.pos(rawtx, network);
} else if (insight) {
console.log('insight decoder');
} else {
return txDecoder.default(rawtx, network);
}

42
routes/shepherd/electrum/transactions.js

@ -1,39 +1,39 @@
const async = require('async');
module.exports = (shepherd) => {
shepherd.sortTransactions = (transactions) => {
shepherd.sortTransactions = (transactions, sortBy) => {
return transactions.sort((b, a) => {
if (a.height < b.height) {
if (a[sortBy ? sortBy : 'height'] < b[sortBy ? sortBy : 'height']) {
return -1;
}
if (a.height > b.height) {
if (a[sortBy ? sortBy : 'height'] > b[sortBy ? sortBy : 'height']) {
return 1;
}
return 0;
});
}
shepherd.getTransaction = (txid, network, ecl) => {
return new shepherd.Promise((resolve, reject) => {
if (!shepherd.electrumCache[network]) {
shepherd.electrumCache[network] = {};
}
if (!shepherd.electrumCache[network].tx) {
shepherd.electrumCache[network]['tx'] = {};
shepherd.electrumCache[network]['tx'] = {};
}
if (!shepherd.electrumCache[network].tx[txid]) {
shepherd.log(`electrum raw input tx ${txid}`, true);
ecl.blockchainTransactionGet(txid)
.then((_rawtxJSON) => {
shepherd.electrumCache[network].tx[txid] = _rawtxJSON;
resolve(_rawtxJSON);
});
} else {
shepherd.log(`electrum cached raw input tx ${txid}`, true);
shepherd.log(`electrum cached raw input tx ${txid}`, true);
resolve(shepherd.electrumCache[network].tx[txid]);
}
});
@ -45,19 +45,19 @@ module.exports = (shepherd) => {
shepherd.electrumCache[network] = {};
}
if (!shepherd.electrumCache[network].blockHeader) {
shepherd.electrumCache[network]['blockHeader'] = {};
shepherd.electrumCache[network]['blockHeader'] = {};
}
if (!shepherd.electrumCache[network].blockHeader[height]) {
shepherd.log(`electrum raw block ${height}`, true);
ecl.blockchainBlockGetHeader(height)
.then((_rawtxJSON) => {
shepherd.electrumCache[network].blockHeader[height] = _rawtxJSON;
resolve(_rawtxJSON);
});
} else {
shepherd.log(`electrum cached raw block ${height}`, true);
shepherd.log(`electrum cached raw block ${height}`, true);
resolve(shepherd.electrumCache[network].blockHeader[height]);
}
});
@ -66,18 +66,18 @@ module.exports = (shepherd) => {
shepherd.get('/electrum/listtransactions', (req, res, next) => {
if (shepherd.checkToken(req.query.token)) {
const network = req.query.network || shepherd.findNetworkObj(req.query.coin);
const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
const ecl = shepherd.electrumServers[network].proto === 'insight' ? shepherd.insightJSCore(shepherd.electrumServers[network]) : new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls
shepherd.log('electrum listtransactions ==>', true);
if (!req.query.full) {
if (!req.query.full || ecl.insight) {
ecl.connect();
ecl.blockchainAddressGetHistory(req.query.address)
.then((json) => {
ecl.close();
shepherd.log(json, true);
json = shepherd.sortTransactions(json);
json = shepherd.sortTransactions(json, 'timestamp');
const successObj = {
msg: 'success',
@ -136,7 +136,7 @@ module.exports = (shepherd) => {
async.eachOfSeries(decodedTx.inputs, (_decodedInput, ind2, callback2) => {
function checkLoop() {
index2++;
if (index2 === decodedTx.inputs.length) {
shepherd.log(`tx history decode inputs ${decodedTx.inputs.length} | ${index2} => main callback`, true);
const _parsedTx = {
@ -182,7 +182,7 @@ module.exports = (shepherd) => {
if (index === json.length) {
ecl.close();
const successObj = {
msg: 'success',
result: _rawtx,
@ -194,7 +194,7 @@ module.exports = (shepherd) => {
callback();
shepherd.log(`tx history main loop ${json.length} | ${index}`, true);
}
callback2();
callback2();
}
if (_decodedInput.txid !== '0000000000000000000000000000000000000000000000000000000000000000') {
@ -229,15 +229,15 @@ module.exports = (shepherd) => {
if (index === json.length) {
ecl.close();
const successObj = {
msg: 'success',
result: _rawtx,
};
res.end(JSON.stringify(successObj));
} else {
callback();
callback();
}
}
});
@ -257,12 +257,12 @@ module.exports = (shepherd) => {
if (index === json.length) {
ecl.close();
const successObj = {
msg: 'success',
result: _rawtx,
};
res.end(JSON.stringify(successObj));
} else {
callback();

6
version

@ -1,3 +1,3 @@
version=0.2.30c
type=c-beta
minversion=0.2.30
version=0.2.31
type=beta
minversion=0.2.31

2
version_build

@ -1 +1 @@
0.2.30c-beta
0.2.31-beta
Loading…
Cancel
Save