mirror of https://github.com/lukechilds/Agama.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
4.6 KiB
145 lines
4.6 KiB
module.exports = (shepherd) => {
|
|
// get merkle root
|
|
shepherd.getMerkleRoot = (txid, proof, pos) => {
|
|
const reverse = require('buffer-reverse');
|
|
const _sha256 = (data) => {
|
|
return shepherd.crypto.createHash('sha256').update(data).digest();
|
|
}
|
|
let hash = txid;
|
|
let serialized;
|
|
|
|
shepherd.log(`getMerkleRoot txid ${txid}`, true);
|
|
shepherd.log(`getMerkleRoot pos ${pos}`, true);
|
|
shepherd.log('getMerkleRoot proof', true);
|
|
shepherd.log(`getMerkleRoot ${proof}`, true);
|
|
|
|
for (i = 0; i < proof.length; i++) {
|
|
const _hashBuff = new Buffer(hash, 'hex');
|
|
const _proofBuff = new Buffer(proof[i], 'hex');
|
|
|
|
if ((pos & 1) == 0) {
|
|
serialized = Buffer.concat([reverse(_hashBuff), reverse(_proofBuff)]);
|
|
} else {
|
|
serialized = Buffer.concat([reverse(_proofBuff), reverse(_hashBuff)]);
|
|
}
|
|
|
|
hash = reverse(_sha256(_sha256(serialized))).toString('hex');
|
|
pos /= 2;
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
shepherd.verifyMerkle = (txid, height, serverList, mainServer) => {
|
|
// select random server
|
|
const getRandomIntInclusive = (min, max) => {
|
|
min = Math.ceil(min);
|
|
max = Math.floor(max);
|
|
|
|
return Math.floor(Math.random() * (max - min + 1)) + min; // the maximum is inclusive and the minimum is inclusive
|
|
}
|
|
|
|
const _rnd = getRandomIntInclusive(0, serverList.length - 1);
|
|
const randomServer = serverList[_rnd];
|
|
const _randomServer = randomServer.split(':');
|
|
const _mainServer = mainServer.split(':');
|
|
|
|
let ecl = new shepherd.electrumJSCore(_mainServer[1], _mainServer[0], 'tcp'); // tcp or tls
|
|
|
|
return new shepherd.Promise((resolve, reject) => {
|
|
shepherd.log(`main server: ${mainServer}`, true);
|
|
shepherd.log(`verification server: ${randomServer}`, true);
|
|
|
|
ecl.connect();
|
|
ecl.blockchainTransactionGetMerkle(txid, height)
|
|
.then((merkleData) => {
|
|
if (merkleData &&
|
|
merkleData.merkle &&
|
|
merkleData.pos) {
|
|
shepherd.log('electrum getmerkle =>', true);
|
|
shepherd.log(merkleData, true);
|
|
ecl.close();
|
|
|
|
const _res = shepherd.getMerkleRoot(txid, merkleData.merkle, merkleData.pos);
|
|
shepherd.log(_res, true);
|
|
|
|
ecl = new shepherd.electrumJSCore(_randomServer[1], _randomServer[0], 'tcp');
|
|
ecl.connect();
|
|
|
|
ecl.blockchainBlockGetHeader(height)
|
|
.then((blockInfo) => {
|
|
if (blockInfo &&
|
|
blockInfo['merkle_root']) {
|
|
ecl.close();
|
|
shepherd.log('blockinfo =>', true);
|
|
shepherd.log(blockInfo, true);
|
|
shepherd.log(blockInfo['merkle_root'], true);
|
|
|
|
if (blockInfo &&
|
|
blockInfo['merkle_root']) {
|
|
if (_res === blockInfo['merkle_root']) {
|
|
resolve(true);
|
|
} else {
|
|
resolve(false);
|
|
}
|
|
} else {
|
|
resolve(shepherd.CONNECTION_ERROR_OR_INCOMPLETE_DATA);
|
|
}
|
|
} else {
|
|
resolve(shepherd.CONNECTION_ERROR_OR_INCOMPLETE_DATA);
|
|
}
|
|
});
|
|
} else {
|
|
resolve(shepherd.CONNECTION_ERROR_OR_INCOMPLETE_DATA);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
shepherd.verifyMerkleByCoin = (coin, txid, height) => {
|
|
const _serverList = shepherd.electrumCoins[coin].serverList;
|
|
|
|
shepherd.log(`verifyMerkleByCoin`, true);
|
|
shepherd.log(shepherd.electrumCoins[coin].server, true);
|
|
shepherd.log(shepherd.electrumCoins[coin].serverList, true);
|
|
|
|
return new shepherd.Promise((resolve, reject) => {
|
|
if (_serverList !== 'none') {
|
|
let _filteredServerList = [];
|
|
|
|
for (let i = 0; i < _serverList.length; i++) {
|
|
if (_serverList[i] !== shepherd.electrumCoins[coin].server.ip + ':' + shepherd.electrumCoins[coin].server.port) {
|
|
_filteredServerList.push(_serverList[i]);
|
|
}
|
|
}
|
|
|
|
shepherd.verifyMerkle(
|
|
txid,
|
|
height,
|
|
_filteredServerList,
|
|
shepherd.electrumCoins[coin].server.ip + ':' + shepherd.electrumCoins[coin].server.port
|
|
).then((proof) => {
|
|
resolve(proof);
|
|
});
|
|
} else {
|
|
resolve(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
shepherd.get('/electrum/merkle/verify', (req, res, next) => {
|
|
shepherd.verifyMerkleByCoin(req.query.coin, req.query.txid, req.query.height)
|
|
.then((verifyMerkleRes) => {
|
|
const successObj = {
|
|
msg: 'success',
|
|
result: {
|
|
merkleProof: verifyMerkleRes,
|
|
},
|
|
};
|
|
|
|
res.end(JSON.stringify(successObj));
|
|
});
|
|
});
|
|
|
|
return shepherd;
|
|
};
|
|
|