mirror of https://github.com/lukechilds/Agama.git
pbca26
7 years ago
5 changed files with 1511 additions and 76 deletions
@ -0,0 +1,355 @@ |
|||||
|
/* |
||||
|
MIT License |
||||
|
|
||||
|
Copyright (c) 2017 Yuki Akiyama, SuperNET |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
const tls = require('tls'); |
||||
|
const net = require('net'); |
||||
|
const EventEmitter = require('events').EventEmitter; |
||||
|
|
||||
|
const makeRequest = function(method, params, id) { |
||||
|
return JSON.stringify({ |
||||
|
jsonrpc : '2.0', |
||||
|
method : method, |
||||
|
params : params, |
||||
|
id : id, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
const createRecursiveParser = function(maxDepth, delimiter) { |
||||
|
const MAX_DEPTH = maxDepth; |
||||
|
const DELIMITER = delimiter; |
||||
|
const recursiveParser = function(n, buffer, callback) { |
||||
|
if (buffer.length === 0) { |
||||
|
return { |
||||
|
code: 0, |
||||
|
buffer: buffer, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
if (n > MAX_DEPTH) { |
||||
|
return { |
||||
|
code: 1, |
||||
|
buffer: buffer, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
const xs = buffer.split(DELIMITER); |
||||
|
|
||||
|
if (xs.length === 1) { |
||||
|
return { |
||||
|
code: 0, |
||||
|
buffer: buffer, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
callback(xs.shift(), n); |
||||
|
|
||||
|
return recursiveParser(n + 1, xs.join(DELIMITER), callback); |
||||
|
} |
||||
|
|
||||
|
return recursiveParser; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
const createPromiseResult = function(resolve, reject) { |
||||
|
return (err, result) => { |
||||
|
if (err) { |
||||
|
console.log('electrum error:'); |
||||
|
console.log(err); |
||||
|
reject(err); |
||||
|
} else { |
||||
|
resolve(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class MessageParser { |
||||
|
constructor(callback) { |
||||
|
this.buffer = ''; |
||||
|
this.callback = callback; |
||||
|
this.recursiveParser = createRecursiveParser(20, '\n'); |
||||
|
} |
||||
|
|
||||
|
run(chunk) { |
||||
|
this.buffer += chunk; |
||||
|
|
||||
|
while (true) { |
||||
|
const res = this.recursiveParser(0, this.buffer, this.callback); |
||||
|
|
||||
|
this.buffer = res.buffer; |
||||
|
|
||||
|
if(res.code === 0) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const util = { |
||||
|
makeRequest, |
||||
|
createRecursiveParser, |
||||
|
createPromiseResult, |
||||
|
MessageParser, |
||||
|
}; |
||||
|
|
||||
|
const getSocket = function(protocol, options) { |
||||
|
switch (protocol) { |
||||
|
case 'tcp': |
||||
|
return new net.Socket(); |
||||
|
case 'tls': |
||||
|
// todo
|
||||
|
case 'ssl': |
||||
|
return new tls.TLSSocket(options); |
||||
|
} |
||||
|
|
||||
|
throw new Error('unknown protocol'); |
||||
|
} |
||||
|
|
||||
|
const initSocket = function(self, protocol, options) { |
||||
|
const conn = getSocket(protocol, options); |
||||
|
|
||||
|
conn.setEncoding('utf8'); |
||||
|
conn.setKeepAlive(true, 0); |
||||
|
conn.setNoDelay(true); |
||||
|
conn.on('connect', () => { |
||||
|
self.onConnect(); |
||||
|
}); |
||||
|
conn.on('close', (e) => { |
||||
|
self.onClose(e); |
||||
|
}); |
||||
|
conn.on('data', (chunk) => { |
||||
|
self.onReceive(chunk); |
||||
|
}); |
||||
|
conn.on('end', (e) => { |
||||
|
self.onEnd(e); |
||||
|
}); |
||||
|
conn.on('error', (e) => { |
||||
|
self.onError(e); |
||||
|
}); |
||||
|
|
||||
|
return conn; |
||||
|
} |
||||
|
|
||||
|
class Client { |
||||
|
constructor(port, host, protocol = 'tcp', options = void 0) { |
||||
|
this.id = 0; |
||||
|
this.port = port; |
||||
|
this.host = host; |
||||
|
this.callbackMessageQueue = {}; |
||||
|
this.subscribe = new EventEmitter(); |
||||
|
this.conn = initSocket(this, protocol, options); |
||||
|
this.mp = new util.MessageParser((body, n) => { |
||||
|
this.onMessage(body, n); |
||||
|
}); |
||||
|
this.status = 0; |
||||
|
} |
||||
|
|
||||
|
connect() { |
||||
|
if (this.status) { |
||||
|
return Promise.resolve(); |
||||
|
} |
||||
|
|
||||
|
this.status = 1; |
||||
|
|
||||
|
return new Promise((resolve, reject) => { |
||||
|
const errorHandler = (e) => reject(e) |
||||
|
|
||||
|
this.conn.connect(this.port, this.host, () => { |
||||
|
this.conn.removeListener('error', errorHandler); |
||||
|
resolve(); |
||||
|
}); |
||||
|
this.conn.on('error', errorHandler); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
close() { |
||||
|
if (!this.status) { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
this.conn.end(); |
||||
|
this.conn.destroy(); |
||||
|
this.status = 0; |
||||
|
} |
||||
|
|
||||
|
request(method, params) { |
||||
|
if (!this.status) { |
||||
|
return Promise.reject(new Error('ESOCKET')); |
||||
|
} |
||||
|
|
||||
|
return new Promise((resolve, reject) => { |
||||
|
const id = ++this.id; |
||||
|
const content = util.makeRequest(method, params, id); |
||||
|
|
||||
|
this.callbackMessageQueue[id] = util.createPromiseResult(resolve, reject); |
||||
|
this.conn.write(`${content}\n`); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
response(msg) { |
||||
|
const callback = this.callbackMessageQueue[msg.id]; |
||||
|
|
||||
|
if (callback) { |
||||
|
delete this.callbackMessageQueue[msg.id]; |
||||
|
|
||||
|
if (msg.error) { |
||||
|
callback(msg.error); |
||||
|
} else { |
||||
|
callback(null, msg.result); |
||||
|
} |
||||
|
} else { |
||||
|
// can't get callback
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMessage(body, n) { |
||||
|
const msg = JSON.parse(body); |
||||
|
|
||||
|
if (msg instanceof Array) { |
||||
|
// don't support batch request
|
||||
|
} else { |
||||
|
if (msg.id !== void 0) { |
||||
|
this.response(msg); |
||||
|
} else { |
||||
|
this.subscribe.emit(msg.method, msg.params); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onConnect() { |
||||
|
} |
||||
|
|
||||
|
onClose() { |
||||
|
Object.keys(this.callbackMessageQueue).forEach((key) => { |
||||
|
this.callbackMessageQueue[key](new Error('close connect')); |
||||
|
delete this.callbackMessageQueue[key]; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
onReceive(chunk) { |
||||
|
this.mp.run(chunk); |
||||
|
} |
||||
|
|
||||
|
onEnd() { |
||||
|
} |
||||
|
|
||||
|
onError(e) { |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class ElectrumJSCore extends Client { |
||||
|
constructor(protocol, port, host, options) { |
||||
|
super(protocol, port, host, options); |
||||
|
} |
||||
|
|
||||
|
onClose() { |
||||
|
super.onClose(); |
||||
|
const list = [ |
||||
|
'server.peers.subscribe', |
||||
|
'blockchain.numblocks.subscribe', |
||||
|
'blockchain.headers.subscribe', |
||||
|
'blockchain.address.subscribe' |
||||
|
]; |
||||
|
|
||||
|
list.forEach(event => this.subscribe.removeAllListeners(event)); |
||||
|
} |
||||
|
|
||||
|
// ref: http://docs.electrum.org/en/latest/protocol.html
|
||||
|
serverVersion(client_name, protocol_version) { |
||||
|
return this.request('server.version', [client_name, protocol_version]); |
||||
|
} |
||||
|
|
||||
|
serverBanner() { |
||||
|
return this.request('server.banner', []); |
||||
|
} |
||||
|
|
||||
|
serverDonationAddress() { |
||||
|
return this.request('server.donation_address', []); |
||||
|
} |
||||
|
|
||||
|
serverPeersSubscribe() { |
||||
|
return this.request('server.peers.subscribe', []); |
||||
|
} |
||||
|
|
||||
|
blockchainAddressGetBalance(address) { |
||||
|
return this.request('blockchain.address.get_balance', [address]); |
||||
|
} |
||||
|
|
||||
|
blockchainAddressGetHistory(address) { |
||||
|
return this.request('blockchain.address.get_history', [address]); |
||||
|
} |
||||
|
|
||||
|
blockchainAddressGetMempool(address) { |
||||
|
return this.request('blockchain.address.get_mempool', [address]); |
||||
|
} |
||||
|
|
||||
|
blockchainAddressGetProof(address) { |
||||
|
return this.request('blockchain.address.get_proof', [address]); |
||||
|
} |
||||
|
|
||||
|
blockchainAddressListunspent(address) { |
||||
|
return this.request('blockchain.address.listunspent', [address]); |
||||
|
} |
||||
|
|
||||
|
blockchainBlockGetHeader(height) { |
||||
|
return this.request('blockchain.block.get_header', [height]); |
||||
|
} |
||||
|
|
||||
|
blockchainBlockGetChunk(index) { |
||||
|
return this.request('blockchain.block.get_chunk', [index]); |
||||
|
} |
||||
|
|
||||
|
blockchainEstimatefee(number) { |
||||
|
return this.request('blockchain.estimatefee', [number]); |
||||
|
} |
||||
|
|
||||
|
blockchainHeadersSubscribe() { |
||||
|
return this.request('blockchain.headers.subscribe', []); |
||||
|
} |
||||
|
|
||||
|
blockchainNumblocksSubscribe() { |
||||
|
return this.request('blockchain.numblocks.subscribe', []); |
||||
|
} |
||||
|
|
||||
|
blockchainRelayfee() { |
||||
|
return this.request('blockchain.relayfee', []); |
||||
|
} |
||||
|
|
||||
|
blockchainTransactionBroadcast(rawtx) { |
||||
|
return this.request('blockchain.transaction.broadcast', [rawtx]); |
||||
|
} |
||||
|
|
||||
|
blockchainTransactionGet(tx_hash, height) { |
||||
|
return this.request('blockchain.transaction.get', [tx_hash, height]); |
||||
|
} |
||||
|
|
||||
|
blockchainTransactionGetMerkle(tx_hash, height) { |
||||
|
return this.request('blockchain.transaction.get_merkle', [tx_hash, height]); |
||||
|
} |
||||
|
|
||||
|
blockchainUtxoGetAddress(tx_hash, index) { |
||||
|
return this.request('blockchain.utxo.get_address', [tx_hash, index]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
module.exports = ElectrumJSCore; |
@ -0,0 +1,205 @@ |
|||||
|
'use strict' |
||||
|
var bitcoin = require('bitcoinjs-lib'); |
||||
|
|
||||
|
var networks = exports; |
||||
|
Object.keys(bitcoin.networks).forEach(function(key){ |
||||
|
networks[key] = bitcoin.networks[key] |
||||
|
}); |
||||
|
|
||||
|
networks.litecoin = { |
||||
|
messagePrefix: '\x19Litecoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x019da462, |
||||
|
private: 0x019d9cfe |
||||
|
}, |
||||
|
pubKeyHash: 0x30, |
||||
|
scriptHash: 0x32, |
||||
|
wif: 0xb0, |
||||
|
dustThreshold: 0, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L360-L365
|
||||
|
} |
||||
|
|
||||
|
networks.dogecoin = { |
||||
|
messagePrefix: '\x19Dogecoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x02facafd, |
||||
|
private: 0x02fac398, |
||||
|
}, |
||||
|
pubKeyHash: 0x1e, |
||||
|
scriptHash: 0x16, |
||||
|
wif: 0x9e, |
||||
|
dustThreshold: 0 // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160
|
||||
|
}; |
||||
|
|
||||
|
// https://github.com/monacoinproject/monacoin/blob/master-0.10/src/chainparams.cpp#L161
|
||||
|
networks.monacoin = { |
||||
|
messagePrefix: '\x19Monacoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x32, |
||||
|
scriptHash: 0x05, |
||||
|
wif: 0xB2, |
||||
|
dustThreshold: 546, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// https://github.com/gamecredits-project/GameCredits/blob/master/src/chainparams.cpp#L136
|
||||
|
networks.game = { |
||||
|
messagePrefix: '\x19GameCredits Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x043587cf, |
||||
|
private: 0x04358394, |
||||
|
}, |
||||
|
pubKeyHash: 0x6f, |
||||
|
scriptHash: 0xc4, |
||||
|
wif: 0xef, |
||||
|
dustThreshold: 546, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162
|
||||
|
}; |
||||
|
|
||||
|
// https://github.com/dashpay/dash/blob/master/src/chainparams.cpp#L171
|
||||
|
networks.dash = { |
||||
|
messagePrefix: '\x19DarkCoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x02fe52f8, |
||||
|
private: 0x02fe52cc, |
||||
|
}, |
||||
|
pubKeyHash: 0x4c, |
||||
|
scriptHash: 0x10, |
||||
|
wif: 0xcc, |
||||
|
dustThreshold: 5460, // https://github.com/dashpay/dash/blob/v0.12.0.x/src/primitives/transaction.h#L144-L155
|
||||
|
}; |
||||
|
|
||||
|
// https://github.com/zcoinofficial/zcoin/blob/c93eccb39b07a6132cb3d787ac18be406b24c3fa/src/base58.h#L275
|
||||
|
networks.zcoin = { |
||||
|
messagePrefix: '\x19ZCoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, // todo
|
||||
|
private: 0x0488ade4, // todo
|
||||
|
}, |
||||
|
pubKeyHash: 0x52, |
||||
|
scriptHash: 0x07, |
||||
|
wif: 0x52 + 128, |
||||
|
dustThreshold: 1000, // https://github.com/zcoinofficial/zcoin/blob/f755f95a036eedfef7c96bcfb6769cb79278939f/src/main.h#L59
|
||||
|
}; |
||||
|
|
||||
|
// https://raw.githubusercontent.com/jl777/komodo/beta/src/chainparams.cpp
|
||||
|
networks.komodo = { |
||||
|
messagePrefix: '\x19Komodo Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x3c, |
||||
|
scriptHash: 0x55, |
||||
|
wif: 0xbc, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
networks.viacoin = { |
||||
|
messagePrefix: '\x19Viacoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x47, |
||||
|
scriptHash: 0x21, |
||||
|
wif: 0xc7, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
networks.vertcoin = { |
||||
|
messagePrefix: '\x19Vertcoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x47, |
||||
|
scriptHash: 0x5, |
||||
|
wif: 0x80, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
networks.namecoin = { |
||||
|
messagePrefix: '\x19Namecoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x34, |
||||
|
scriptHash: 0xd, |
||||
|
wif: 0xb4, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
networks.faircoin = { |
||||
|
messagePrefix: '\x19Faircoin Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x5f, |
||||
|
scriptHash: 0x24, |
||||
|
wif: 0xdf, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
networks.digibyte = { |
||||
|
messagePrefix: '\x19Digibyte Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x1e, |
||||
|
scriptHash: 0x5, |
||||
|
wif: 0x80, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
networks.crown = { |
||||
|
messagePrefix: '\x19Crown Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x0, |
||||
|
scriptHash: 0x1c, |
||||
|
wif: 0x80, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
networks.argentum = { |
||||
|
messagePrefix: '\x19Argentum Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x17, |
||||
|
scriptHash: 0x5, |
||||
|
wif: 0x97, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
networks.chips = { |
||||
|
messagePrefix: '\x19Chips Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x3c, |
||||
|
scriptHash: 0x55, |
||||
|
wif: 0xbc, |
||||
|
dustThreshold: 1000, |
||||
|
}; |
||||
|
|
||||
|
/*networks.zcash = { |
||||
|
messagePrefix: '\x19Zcash Signed Message:\n', |
||||
|
bip32: { |
||||
|
public: 0x0488b21e, |
||||
|
private: 0x0488ade4, |
||||
|
}, |
||||
|
pubKeyHash: 0x1cb8, |
||||
|
scriptHash: 0x1cbd, |
||||
|
wif: 0x80, |
||||
|
dustThreshold: 1000, |
||||
|
};*/ |
@ -0,0 +1,110 @@ |
|||||
|
/* |
||||
|
MIT License |
||||
|
|
||||
|
Copyright (c) 2017 Yuki Akiyama, SuperNET |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
var bitcoin = require('bitcoinjs-lib'); |
||||
|
|
||||
|
var decodeFormat = function(tx) { |
||||
|
var result = { |
||||
|
txid: tx.getId(), |
||||
|
version: tx.version, |
||||
|
locktime: tx.locktime, |
||||
|
}; |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
var decodeInput = function(tx) { |
||||
|
var result = []; |
||||
|
|
||||
|
tx.ins.forEach(function(input, n) { |
||||
|
var vin = { |
||||
|
txid: input.hash.reverse().toString('hex'), |
||||
|
n: input.index, |
||||
|
script: bitcoin.script.toASM(input.script), |
||||
|
sequence: input.sequence, |
||||
|
}; |
||||
|
|
||||
|
result.push(vin); |
||||
|
}); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
var decodeOutput = function(tx, network) { |
||||
|
var format = function(out, n, network) { |
||||
|
var vout = { |
||||
|
satoshi: out.value, |
||||
|
value: (1e-8 * out.value).toFixed(8), |
||||
|
n: n, |
||||
|
scriptPubKey: { |
||||
|
asm: bitcoin.script.toASM(out.script), |
||||
|
hex: out.script.toString('hex'), |
||||
|
type: bitcoin.script.classifyOutput(out.script), |
||||
|
addresses: [], |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
switch(vout.scriptPubKey.type) { |
||||
|
case 'pubkeyhash': |
||||
|
case 'scripthash': |
||||
|
vout.scriptPubKey.addresses.push(bitcoin.address.fromOutputScript(out.script, network)); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
return vout; |
||||
|
} |
||||
|
|
||||
|
var result = []; |
||||
|
|
||||
|
tx.outs.forEach(function(out, n) { |
||||
|
result.push(format(out, n, network)); |
||||
|
}); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
var TxDecoder = module.exports = function(rawtx, network) { |
||||
|
const _tx = bitcoin.Transaction.fromHex(rawtx); |
||||
|
|
||||
|
return { |
||||
|
tx: _tx, |
||||
|
network: network, |
||||
|
format: decodeFormat(_tx), |
||||
|
inputs: decodeInput(_tx), |
||||
|
outputs: decodeOutput(_tx, network), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
TxDecoder.prototype.decode = function() { |
||||
|
var result = {}; |
||||
|
var self = this; |
||||
|
|
||||
|
Object.keys(self.format).forEach(function(key) { |
||||
|
result[key] = self.format[key]; |
||||
|
}); |
||||
|
|
||||
|
result.outputs = self.outputs; |
||||
|
|
||||
|
return result; |
||||
|
} |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue