From 002718206a0ce8b102b5f242e193e2da4b054ef0 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 12 Jan 2017 12:41:33 -0800 Subject: [PATCH] rpc: some refactoring. --- lib/http/rpc.js | 182 ++++++++++++++++++++++++++------------------- lib/http/server.js | 2 +- 2 files changed, 108 insertions(+), 76 deletions(-) diff --git a/lib/http/rpc.js b/lib/http/rpc.js index e0388293..90688325 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -71,6 +71,8 @@ function RPC(node) { util.inherits(RPC, EventEmitter); +RPC.magic = 'Bitcoin Signed Message:\n'; + RPC.prototype.execute = function execute(json) { switch (json.method) { case 'stop': @@ -502,12 +504,17 @@ RPC.prototype.getnettotals = co(function* getnettotals(args) { RPC.prototype.getpeerinfo = co(function* getpeerinfo(args) { var peers = []; var id = 0; - var peer; + var peer, offset; if (args.help || args.length !== 0) throw new RPCError('getpeerinfo'); for (peer = this.pool.peers.head(); peer; peer = peer.next) { + offset = this.network.time.known[peer.hostname]; + + if (offset == null) + offset = 0; + peers.push({ id: id++, addr: peer.hostname, @@ -518,15 +525,17 @@ RPC.prototype.getpeerinfo = co(function* getpeerinfo(args) { bytessent: peer.socket.bytesWritten, bytesrecv: peer.socket.bytesRead, conntime: peer.ts !== 0 ? util.now() - peer.ts : 0, - timeoffset: peer.version ? peer.version.ts - util.now() : 0, - pingtime: peer.lastPing !== -1 ? peer.lastPing / 1000 : 0, - minping: peer.minPing !== -1 ? peer.minPing / 1000 : 0, + timeoffset: offset, + pingtime: peer.lastPong !== -1 + ? (peer.lastPong - peer.lastPing) / 1000 + : -1, + minping: peer.minPing !== -1 ? peer.minPing / 1000 : -1, version: peer.version ? peer.version.version : 0, subver: peer.version ? peer.version.agent : '', inbound: !peer.outbound, startingheight: peer.version ? peer.version.height : -1, banscore: peer.banScore, - inflight: [], + inflight: peer.requestMap.keys().map(util.revHex), whitelisted: false }); } @@ -667,8 +676,8 @@ RPC.prototype.getblockchaininfo = co(function* getblockchaininfo(args) { return { chain: 'main', blocks: this.chain.height, - headers: this.chain.bestHeight, - bestblockhash: util.revHex(this.chain.tip.hash), + headers: this.chain.height, + bestblockhash: this.chain.tip.rhash(), difficulty: this._getDifficulty(), mediantime: yield this.chain.tip.getMedianTimeAsync(), verificationprogress: this.chain.getProgress(), @@ -780,7 +789,7 @@ RPC.prototype._txToJSON = function _txToJSON(tx, entry) { if (tx.isCoinbase()) { out.coinbase = input.script.toJSON(); } else { - out.txid = util.revHex(input.prevout.hash); + out.txid = input.prevout.rhash(); out.vout = input.prevout.index; out.scriptSig = { asm: input.script.toASM(), @@ -805,27 +814,34 @@ RPC.prototype._txToJSON = function _txToJSON(tx, entry) { blockhash: entry ? entry.rhash() : null, confirmations: conf, time: entry ? entry.ts : 0, - blocktime: entry ? entry.ts : 0 + blocktime: entry ? entry.ts : 0, + hex: undefined }; }; RPC.prototype._scriptToJSON = function scriptToJSON(script, hex) { - var out = {}; - var type, address; + var type = script.getType(); + var address = script.getAddress(); + var out; - out.asm = script.toASM(); + out = { + asm: script.toASM(), + hex: undefined, + type: Script.typesByVal[type], + reqSigs: 1, + addresses: [] + }; if (hex) out.hex = script.toJSON(); - type = script.getType(); - out.type = Script.typesByVal[type]; + if (script.isMultisig()) + out.reqSigs = script.getSmall(0); - out.reqSigs = script.isMultisig() ? script.getSmall(0) : 1; - - address = script.getAddress(); - - out.addresses = address ? [address.toBase58(this.network)] : []; + if (address) { + address = address.toBase58(this.network); + out.addresses.push(address); + } return out; }; @@ -881,7 +897,7 @@ RPC.prototype._headerToJSON = co(function* _headerToJSON(entry) { var nextHash = yield this.chain.db.getNextHash(entry.hash); return { - hash: util.revHex(entry.hash), + hash: entry.rhash(), confirmations: this.chain.height - entry.height + 1, height: entry.height, version: entry.version, @@ -904,7 +920,7 @@ RPC.prototype._blockToJSON = co(function* _blockToJSON(entry, block, txDetails) var nextHash = yield this.chain.db.getNextHash(entry.hash); return { - hash: util.revHex(entry.hash), + hash: entry.rhash(), confirmations: this.chain.height - entry.height + 1, strippedsize: block.getBaseSize(), size: block.getSize(), @@ -990,6 +1006,7 @@ RPC.prototype.getmempoolinfo = co(function* getmempoolinfo(args) { }); RPC.prototype.getmempoolancestors = co(function* getmempoolancestors(args) { + var out = []; var i, hash, verbose, entry, entries; if (args.help || args.length < 1 || args.length > 2) @@ -1014,17 +1031,22 @@ RPC.prototype.getmempoolancestors = co(function* getmempoolancestors(args) { entries = this.mempool.getAncestors(entry.tx); if (verbose) { - for (i = 0; i < entries.length; i++) - entries[i] = this._entryToJSON(entries[i]); + for (i = 0; i < entries.length; i++) { + entry = entries[i]; + out.push(this._entryToJSON(entry)); + } } else { - for (i = 0; i < entries.length; i++) - entries[i] = entries[i].tx.txid(); + for (i = 0; i < entries.length; i++) { + entry = entries[i]; + out.push(entry.tx.txid()); + } } - return entries; + return out; }); RPC.prototype.getmempooldescendants = co(function* getmempooldescendants(args) { + var out = []; var i, hash, verbose, entry, entries; if (args.help || args.length < 1 || args.length > 2) @@ -1049,14 +1071,18 @@ RPC.prototype.getmempooldescendants = co(function* getmempooldescendants(args) { entries = this.mempool.getDescendants(entry.tx); if (verbose) { - for (i = 0; i < entries.length; i++) - entries[i] = this._entryToJSON(entries[i]); + for (i = 0; i < entries.length; i++) { + entry = entries[i]; + out.push(this._entryToJSON(entry)); + } } else { - for (i = 0; i < entries.length; i++) - entries[i] = entries[i].tx.txid(); + for (i = 0; i < entries.length; i++) { + entry = entries[i]; + out.push(entry.tx.txid()); + } } - return entries; + return out; }); RPC.prototype.getmempoolentry = co(function* getmempoolentry(args) { @@ -1237,7 +1263,8 @@ RPC.prototype.gettxoutproof = co(function* gettxoutproof(args) { throw new RPCError('Block not found.'); for (i = 0; i < txids.length; i++) { - if (!block.hasTX(txids[i])) + txid = txids[i]; + if (!block.hasTX(txid)) throw new RPCError('Block does not contain all txids.'); } @@ -1247,7 +1274,7 @@ RPC.prototype.gettxoutproof = co(function* gettxoutproof(args) { }); RPC.prototype.verifytxoutproof = co(function* verifytxoutproof(args) { - var res = []; + var out = []; var i, block, hash, entry; if (args.help || args.length !== 1) @@ -1256,7 +1283,7 @@ RPC.prototype.verifytxoutproof = co(function* verifytxoutproof(args) { block = MerkleBlock.fromRaw(toString(args[0]), 'hex'); if (!block.verify()) - return res; + return out; entry = yield this.chain.db.getEntry(block.hash('hex')); @@ -1265,10 +1292,10 @@ RPC.prototype.verifytxoutproof = co(function* verifytxoutproof(args) { for (i = 0; i < block.matches.length; i++) { hash = block.matches[i]; - res.push(util.revHex(hash)); + out.push(util.revHex(hash)); } - return res; + return out; }); RPC.prototype.gettxoutsetinfo = co(function* gettxoutsetinfo(args) { @@ -1768,22 +1795,25 @@ RPC.prototype._bindChain = function _bindChain() { RPC.prototype._getAttempt = co(function* _getAttempt(update) { var attempt = this.attempt; + var block; this._bindChain(); if (attempt) { + block = attempt.block; if (update) { attempt.updateNonce(); - this.coinbase[attempt.block.merkleRoot] = attempt.coinbase.clone(); + this.coinbase[block.merkleRoot] = attempt.coinbase.clone(); } return attempt; } attempt = yield this.miner.createBlock(); + block = attempt.block; this.attempt = attempt; this.start = util.now(); - this.coinbase[attempt.block.merkleRoot] = attempt.coinbase.clone(); + this.coinbase[block.merkleRoot] = attempt.coinbase.clone(); return attempt; }); @@ -2042,13 +2072,10 @@ RPC.prototype.createrawtransaction = co(function* createrawtransaction(args) { throw new RPCError('Invalid parameter'); } - input = new Input({ - prevout: { - hash: util.revHex(hash), - index: index - }, - sequence: sequence - }); + input = new Input(); + input.prevout.hash = hash; + input.prevout.index = index; + input.sequence = sequence; tx.inputs.push(input); } @@ -2062,10 +2089,9 @@ RPC.prototype.createrawtransaction = co(function* createrawtransaction(args) { if (key === 'data') { value = new Buffer(value, 'hex'); - output = new Output({ - value: 0, - script: Script.fromNulldata(value) - }); + output = new Output(); + output.value = 0; + output.script.fromNulldata(value); tx.outputs.push(output); continue; } @@ -2078,10 +2104,9 @@ RPC.prototype.createrawtransaction = co(function* createrawtransaction(args) { addrs[b58] = true; - output = new Output({ - value: toSatoshi(value), - address: address - }); + output = new Output(); + output.value = toSatoshi(value); + output.script.fromAddress(address); tx.outputs.push(output); } @@ -2101,7 +2126,7 @@ RPC.prototype.decoderawtransaction = co(function* decoderawtransaction(args) { }); RPC.prototype.decodescript = co(function* decodescript(args) { - var data, script, hash, address; + var data, script, address; if (args.help || args.length !== 1) throw new RPCError('decodescript "hex"'); @@ -2112,8 +2137,7 @@ RPC.prototype.decodescript = co(function* decodescript(args) { if (data.length > 0) script.fromRaw(new Buffer(data, 'hex')); - hash = crypto.hash160(script.toRaw()); - address = Address.fromHash(hash, Script.types.SCRIPTHASH); + address = Address.fromScripthash(script.hash160()); script = this._scriptToJSON(script); script.p2sh = address.toBase58(this.network); @@ -2217,7 +2241,7 @@ RPC.prototype._signrawtransaction = co(function* signrawtransaction(wallet, tx, for (i = 0; i < prevout.length; i++) { prev = prevout[i]; - if (!(prev && typeof prev === 'object')) + if (!prev || typeof prev !== 'object') throw new RPCError('Invalid parameter'); hash = toHash(prev.txid); @@ -2255,6 +2279,7 @@ RPC.prototype._signrawtransaction = co(function* signrawtransaction(wallet, tx, if (key) { key.script = redeem; key.witness = script.isWitnessScripthash(); + key.refresh(); break; } } @@ -2386,21 +2411,22 @@ RPC.prototype._createRedeem = co(function* _createRedeem(args) { */ RPC.prototype.createmultisig = co(function* createmultisig(args) { - var script; + var script, address; if (args.help || args.length < 2 || args.length > 2) throw new RPCError('createmultisig nrequired ["key",...]'); script = yield this._createRedeem(args); + address = script.getAddress(); return { - address: script.getAddress().toBase58(this.network), + address: adddress.toBase58(this.network), redeemScript: script.toJSON() }; }); RPC.prototype.createwitnessaddress = co(function* createwitnessaddress(args) { - var raw, script, program; + var raw, script, program, address; if (args.help || args.length !== 1) throw new RPCError('createwitnessaddress "script"'); @@ -2408,16 +2434,17 @@ RPC.prototype.createwitnessaddress = co(function* createwitnessaddress(args) { raw = toString(args[1]); script = Script.fromRaw(raw, 'hex'); program = script.forWitness(); + address = program.getAddress(); return { - address: program.getAddress().toBase58(this.network), + address: address.toBase58(this.network), witnessScript: program.toJSON() }; }); RPC.prototype.validateaddress = co(function* validateaddress(args) { var wallet = this.wallet; - var b58, address, json, path; + var b58, address, json, path, script; if (args.help || args.length !== 1) throw new RPCError('validateaddress "bitcoinaddress"'); @@ -2433,13 +2460,16 @@ RPC.prototype.validateaddress = co(function* validateaddress(args) { } path = yield wallet.getPath(address); + script = Script.fromAddress(address); json = { isvalid: true, address: address.toBase58(this.network), - scriptPubKey: Script.fromAddress(address).toJSON(), + scriptPubKey: script.toJSON(), ismine: path ? true : false, - iswatchonly: path ? wallet.watchOnly : false + iswatchonly: path ? wallet.watchOnly : false, + account: undefined, + hdkeypath: undefined }; if (!path) @@ -2451,10 +2481,8 @@ RPC.prototype.validateaddress = co(function* validateaddress(args) { return json; }); -RPC.magic = 'Bitcoin Signed Message:\n'; - RPC.prototype.verifymessage = co(function* verifymessage(args) { - var address, sig, msg, key; + var address, sig, msg, hash, key; if (args.help || args.length !== 3) throw new RPCError('verifymessage "bitcoinaddress" "signature" "message"'); @@ -2463,9 +2491,9 @@ RPC.prototype.verifymessage = co(function* verifymessage(args) { sig = toString(args[1]); msg = toString(args[2]); - address = Address.getHash(address); + hash = Address.getHash(address); - if (!address) + if (!hash) throw new RPCError('Invalid address.'); sig = new Buffer(sig, 'base64'); @@ -2479,7 +2507,7 @@ RPC.prototype.verifymessage = co(function* verifymessage(args) { key = crypto.hash160(key); - return crypto.ccmp(key, address); + return crypto.ccmp(key, hash); }); RPC.prototype.signmessagewithprivkey = co(function* signmessagewithprivkey(args) { @@ -2635,6 +2663,8 @@ RPC.prototype.setmocktime = co(function* setmocktime(args) { if (ts < 0) throw new RPCError('Invalid parameter.'); + this.network.time.offset = 0; + delta = this.network.now() - ts; this.network.time.offset = -delta; @@ -2833,7 +2863,7 @@ RPC.prototype.getaccount = co(function* getaccount(args) { RPC.prototype.getaddressesbyaccount = co(function* getaddressesbyaccount(args) { var wallet = this.wallet; - var i, path, account, addrs, paths; + var i, path, account, address, addrs, paths; if (args.help || args.length !== 1) throw new RPCError('getaddressesbyaccount "account"'); @@ -2849,7 +2879,8 @@ RPC.prototype.getaddressesbyaccount = co(function* getaddressesbyaccount(args) { for (i = 0; i < paths.length; i++) { path = paths[i]; - addrs.push(path.toAddress().toBase58(this.network)); + address = path.toAddress(); + addrs.push(address.toBase58(this.network)); } return addrs; @@ -3346,7 +3377,7 @@ RPC.prototype.listlockunspent = co(function* listlockunspent(args) { for (i = 0; i < outpoints.length; i++) { outpoint = outpoints[i]; out.push({ - txid: util.revHex(outpoint.hash), + txid: outpoint.rhash(), vout: outpoint.index }); } @@ -3401,9 +3432,10 @@ RPC.prototype._listReceived = co(function* _listReceived(minconf, empty, account for (i = 0; i < paths.length; i++) { path = paths[i]; + address = path.toAddress(); map[path.hash] = { involvesWatchonly: wallet.watchOnly, - address: path.toAddress().toBase58(this.network), + address: address.toBase58(this.network), account: path.name, amount: 0, confirmations: -1, @@ -3713,7 +3745,7 @@ RPC.prototype.listunspent = co(function* listunspent(args) { ring = yield wallet.getKey(hash); out.push({ - txid: util.revHex(coin.hash), + txid: coin.rhash(), vout: coin.index, address: address ? address.toBase58(this.network) : null, account: ring ? ring.name : undefined, diff --git a/lib/http/server.js b/lib/http/server.js index 6b551f2e..24f7e7aa 100644 --- a/lib/http/server.js +++ b/lib/http/server.js @@ -634,7 +634,6 @@ HTTPServer.prototype._init = function _init() { res.send(200, { version: pkg.version, - agent: this.pool.userAgent, network: this.network.type, chain: { height: this.chain.height, @@ -644,6 +643,7 @@ HTTPServer.prototype._init = function _init() { pool: { host: this.pool.address.host, port: this.pool.address.port, + agent: this.pool.userAgent, services: this.pool.address.services.toString(2), outbound: this.pool.peers.outbound, inbound: this.pool.peers.inbound