/*! * rpc.js - bitcoind-compatible json rpc for bcoin. * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin */ 'use strict'; var bcoin = require('../env'); var utils = require('../utils'); var IP = require('../ip'); var constants = bcoin.protocol.constants; function RPC(node) { if (!(this instanceof RPC)) return new RPC(node); this.node = node; this.network = node.network; this.chain = node.chain; this.mempool = node.mempool; this.pool = node.pool; this.fees = node.fees; this.miner = node.miner; this.mining = false; this.proclimit = 0; } RPC.prototype.execute = function execute(json, callback) { switch (json.method) { case 'stop': return this.stop(json.params, callback); case 'help': return this.help(json.params, callback); case 'getblockchaininfo': return this.getblockchaininfo(json.params, callback); case 'getbestblockhash': return this.getbestblockhash(json.params, callback); case 'getblockcount': return this.getblockcount(json.params, callback); case 'getblock': return this.getblock(json.params, callback); case 'getblockhash': return this.getblockhash(json.params, callback); case 'getblockheader': return this.getblockheader(json.params, callback); case 'getchaintips': return this.getchaintips(json.params, callback); case 'getdifficulty': return this.getdifficulty(json.params, callback); case 'getmempoolancestors': return this.getmempoolancestors(json.params, callback); case 'getmempooldescendants': return this.getmempooldescendants(json.params, callback); case 'getmempoolentry': return this.getmempoolentry(json.params, callback); case 'getmempoolinfo': return this.getmempoolinfo(json.params, callback); case 'getrawmempool': return this.getrawmempool(json.params, callback); case 'gettxout': return this.gettxout(json.params, callback); case 'gettxoutsetinfo': return this.gettxoutsetinfo(json.params, callback); case 'verifychain': return this.verifychain(json.params, callback); case 'invalidateblock': return this.invalidateblock(json.params, callback); case 'reconsiderblock': return this.reconsiderblock(json.params, callback); case 'getnetworkhashps': return this.getnetworkhashps(json.params, callback); case 'getmininginfo': return this.getmininginfo(json.params, callback); case 'prioritisetransaction': return this.prioritisetransaction(json.params, callback); case 'getblocktemplate': return this.getblocktemplate(json.params, callback); case 'submitblock': return this.submitblock(json.params, callback); case 'setgenerate': return this.setgenerate(json.params, callback); case 'getgenerate': return this.getgenerate(json.params, callback); case 'generate': return this.generate(json.params, callback); case 'generatetoaddress': return this.generatetoaddress(json.params, callback); case 'estimatefee': return this.estimatefee(json.params, callback); case 'estimatepriority': return this.estimatepriority(json.params, callback); case 'estimatesmartfee': return this.estimatesmartfee(json.params, callback); case 'estimatesmartpriority': return this.estimatesmartpriority(json.params, callback); case 'getinfo': return this.getinfo(json.params, callback); case 'validateaddress': return this.validateaddress(json.params, callback); case 'createmultisig': return this.createmultisig(json.params, callback); case 'createwitnessaddress': return this.createwitnessaddress(json.params, callback); case 'verifymessage': return this.verifymessage(json.params, callback); case 'signmessagewithprivkey': return this.signmessagewithprivkey(json.params, callback); case 'setmocktime': return this.setmocktime(json.params, callback); case 'getconnectioncount': return this.getconnectioncount(json.params, callback); case 'ping': return this.ping(json.params, callback); case 'getpeerinfo': return this.getpeerinfo(json.params, callback); case 'addnode': return this.addnode(json.params, callback); case 'disconnectnode': return this.disconnectnode(json.params, callback); case 'getaddednodeinfo': return this.getaddednodeinfo(json.params, callback); case 'getnettotals': return this.getnettotals(json.params, callback); case 'getnetworkinfo': return this.getnetworkinfo(json.params, callback); case 'setban': return this.setban(json.params, callback); case 'listbanned': return this.listbanned(json.params, callback); case 'clearbanned': return this.clearbanned(json.params, callback); case 'getrawtransaction': return this.getrawtransaction(json.params, callback); case 'createrawtransaction': return this.createrawtransaction(json.params, callback); case 'decoderawtransaction': return this.decoderawtransaction(json.params, callback); case 'decodescript': return this.decodescript(json.params, callback); case 'sendrawtransaction': return this.sendrawtransaction(json.params, callback); case 'signrawtransaction': return this.signrawtransaction(json.params, callback); case 'gettxoutproof': return this.gettxoutproof(json.params, callback); case 'verifytxoutproof': return this.verifytxoutproof(json.params, callback); case 'fundrawtransaction': case 'resendwallettransactions': case 'abandontransaction': case 'addmultisigaddress': case 'addwitnessaddress': case 'backupwallet': case 'dumpprivkey': case 'dumpwallet': case 'encryptwallet': case 'getaccountaddress': case 'getaccount': case 'getaddressesbyaccount': case 'getbalance': case 'getnewaddress': case 'getrawchangeaddress': case 'getreceivedbyaccount': case 'getreceivedbyaddress': case 'gettransaction': case 'getunconfirmedbalance': case 'getwalletinfo': case 'importprivkey': case 'importwallet': case 'importaddress': case 'importprunedfunds': case 'importpubkey': case 'keypoolrefill': case 'listaccounts': case 'listaddressgroupings': case 'listlockunspent': case 'listreceivedbyaccount': case 'listreceivedbyaddress': case 'listsinceblock': case 'listtransactions': case 'listunspent': case 'lockunspent': case 'move': case 'sendfrom': case 'sendmany': case 'sendtoaddress': case 'setaccount': case 'settxfee': case 'signmessage': case 'walletlock': case 'walletpassphrasechange': case 'walletpassphrase': case 'removeprunedfunds': return callback(new Error('Method not found.')); default: return callback(new Error('Method not found.')); } }; /* * Overall control/query calls */ RPC.prototype.getinfo = function getinfo(args, callback) { return callback(null, { version: constants.USER_VERSION, protocolversion: constants.VERSION, walletversion: 0, balance: 0, blocks: this.chain.height, timeoffset: bcoin.time.offset, connections: this.pool.peers.all.length, proxy: '', difficulty: this._getDifficulty(), testnet: this.network.type !== 'main', keypoololdest: 0, keypoolsize: 0, unlocked_until: 0, paytxfee: this.network.getRate() / constants.COIN, relayfee: this.network.getMinRelay() / constants.COIN, errors: '' }); }; RPC.prototype.help = function help(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.stop = function stop(args, callback) { callback(null, 'Stopping.'); utils.nextTick(function() { process.exit(0); }); }; /* * P2P networking */ RPC.prototype.getnetworkinfo = function getnetworkinfo(args, callback) { callback(null, { version: constants.USER_VERSION, subversion: constants.USER_AGENT, protocolversion: constants.VERSION, localservices: this.pool.services, timeoffset: bcoin.time.offset, connections: this.pool.peers.all.length, networks: [ { name: 'ipv4', limited: false, reachable: false, proxy: '', proxy_randomize_credentials: false }, { name: 'ipv6', limited: false, reachable: false, proxy: '', proxy_randomize_credentials: false }, { name: 'onion', limited: false, reachable: false, proxy: '', proxy_randomize_credentials: false } ], relayfee: this.network.getMinRelay() / 100000000, localaddresses: [], warnings: '' }); }; RPC.prototype.addnode = function addnode(args, callback) { var i, node, cmd, host, seed; if (args.help || args.length !== 2) return callback(new Error('addnode "node" "add|remove|onetry"')); node = String(args[0]); cmd = String(args[1]); host = bcoin.packets.NetworkAddress.fromHostname(node, this.network); switch (cmd) { case 'add': this.pool.seeds.push(host); break; case 'remove': for (i = 0; i < this.pool.seeds.length; i++) { seed = this.pool.seeds[i]; if (seed.host === host.host) break; } if (i === this.pool.seeds.length) break; this.pool.seeds.splice(i, 1); break; case 'onetry': break; } callback(null, null); }; RPC.prototype.disconnectnode = function disconnectnode(args, callback) { var node, peer; if (args.help || args.length !== 1) return callback(new Error('disconnectnode "node" ')); node = String(args[0]); node = IP.normalize(node); peer = this.pool.getPeer(node); if (peer) peer.destroy(); callback(null, null); }; RPC.prototype.getaddednodeinfo = function getaddednodeinfo(args, callback) { if (args.help || args.length < 1 || args.length > 2) return callback(new Error('getaddednodeinfo dummy ( "node" )')); callback(new Error('Not implemented.')); }; RPC.prototype.getconnectioncount = function getconnectioncount(args, callback) { if (args.help || args.length !== 0) return callback(new Error('getconnectioncount')); callback(null, this.pool.peers.all.length); }; RPC.prototype.getnettotals = function getnettotals(args, callback) { if (args.help || args.length < 1 || args.length > 2) return callback(new Error('getnettotals')); callback(null, { totalbytesrecv: 0, totalbytessent: 0, timemillis: utils.ms(), uploadtarget: { timeframe: 86400, target: 0, target_reached: false, serve_historical_blocks: !this.pool.options.selfish && !this.pool.options.spv && !this.chain.db.options.prune, bytes_left_in_cycle: 0, time_left_in_cycle: 0 } }); }; RPC.prototype.getpeerinfo = function getpeerinfo(args, callback) { var peers = []; var i, peer; if (args.help || args.length !== 0) return callback(new Error('getpeerinfo')); for (i = 0; i < this.pool.peers.all.length; i++) { peer = this.pool.peers.all[i]; peers.push({ id: peer.id, addr: peer.hostname, addrlocal: peer.hostname, relaytxes: peer.type !== bcoin.peer.types.LEECH, lastsend: 0, lastrecv: 0, bytessent: 0, bytesrecv: 0, conntime: utils.now() - peer.ts, timeoffset: bcoin.time.known[peer.host] || 0, pingtime: peer.lastPing, minping: peer.minPing, version: peer.version ? peer.version.version : 0, subver: peer.version ? peer.version.agent : '', inbound: peer.type === bcoin.peer.types.LEECH, startingheight: peer.version ? peer.version.height : -1, banscore: peer.banScore, synced_headers: 0, synced_blocks: 0, inflight: [], whitelisted: false }); } callback(null, peers); }; RPC.prototype.ping = function ping(args, callback) { var i; if (args.help || args.length !== 0) return callback(new Error('ping')); for (i = 0; i < this.pool.peers.all.length; i++) this.pool.peers.all[i].sendPing(); callback(null, null); }; RPC.prototype.setban = function setban(args, callback) { var peer, ip; if (args.help || args.length < 2 || (args[1] !== 'add' && args[1] !== 'remove')) { return callback(new Error( 'setban "ip(/netmask)" "add|remove" (bantime) (absolute)')); } ip = IP.normalize(args[0]); switch (args[1]) { case 'add': peer = this.pool.getPeer(ip); if (peer) peer.setMisbehavior(100); else this.pool.peers.misbehaving[ip] = utils.now(); break; case 'remove': delete this.pool.peers.misbehaving[ip]; break; } callback(null, null); }; RPC.prototype.listbanned = function listbanned(args, callback) { var i, banned, keys, host, time; if (args.help || args.length !== 0) return callback(new Error('listbanned')); banned = []; keys = Object.keys(this.pool.peers.misbehaving); for (i = 0; i < keys.length; i++) { host = keys[i]; time = this.pool.peers.misbehaving[host]; banned.push({ address: host, banned_until: time + constants.BAN_TIME, ban_created: time, ban_reason: '' }); } callback(null, banned); }; RPC.prototype.clearbanned = function clearbanned(args, callback) { if (args.help || args.length !== 0) return callback(new Error('clearbanned')); this.pool.peers.misbehaving = {}; callback(null, null); }; RPC.prototype._deployment = function _deployment(id, version, status) { return { id: id, version: version, enforce: { status: status, found: status ? this.network.block.majorityWindow : 0, required: this.network.block.majorityEnforceUpgrade, window: this.network.block.majorityWindow, }, reject: { status: status, found: status ? this.network.block.majorityWindow : 0, required: this.network.block.majorityRejectOutdated, winodw: this.network.block.majorityWindow, } }; }; RPC.prototype._getSoftforks = function _getSoftforks() { return [ this._deployment('bip34', 2, this.chain.state.hasBIP34()), this._deployment('bip66', 3, this.chain.state.hasBIP66()), this._deployment('bip65', 4, this.chain.state.hasCLTV()) ]; }; RPC.prototype._getBIP9Softforks = function _getBIP9Softforks(callback) { var self = this; var forks = []; var keys = Object.keys(this.network.deployments); utils.forEachSerial(keys, function(id, next) { self.chain.getState(self.chain.tip, id, function(err, state) { if (err) return next(err); switch (state) { case constants.thresholdStates.DEFINED: state = 'defined'; break; case constants.thresholdStates.STARTED: state = 'started'; break; case constants.thresholdStates.LOCKED_IN: state = 'locked_in'; break; case constants.thresholdStates.ACTIVE: state = 'active'; break; case constants.thresholdStates.FAILED: state = 'failed'; break; } forks.push({ id: id, state: state }); next(); }); }, function(err) { if (err) return callback(err); return callback(null, forks); }); }; /* Block chain and UTXO */ RPC.prototype.getblockchaininfo = function getblockchaininfo(args, callback) { var self = this; if (args.help || args.length !== 0) return callback(new Error('getblockchaininfo')); this.chain.tip.getMedianTimeAsync(function(err, medianTime) { if (err) return callback(err); self._getBIP9Softforks(function(err, forks) { if (err) return callback(err); callback(null, { chain: self.network.type, blocks: self.chain.height, headers: self.chain.bestHeight, bestblockhash: utils.revHex(self.chain.tip.hash), difficulty: self._getDifficulty(), mediantime: medianTime, verificationprogress: self.chain.getProgress(), chainwork: self.chain.tip.chainwork .toArrayLike(Buffer, 'be', 32).toString('hex'), pruned: self.chain.db.options.prune, softforks: self._getSoftforks(), bip9_softforks: forks, pruneheight: self.chain.db.prune ? Math.max(0, self.chain.height - self.chain.db.keepBlocks) : null }); }); }); }; RPC.prototype._getDifficulty = function getDifficulty(entry) { var shift, diff; if (!entry) { if (!this.chain.tip) return 1.0; entry = this.chain.tip; } shift = (entry.bits >>> 24) & 0xff; diff = 0x0000ffff / (entry.bits & 0x00ffffff); while (shift < 29) { diff *= 256.0; shift++; } while (shift > 29) { diff /= 256.0; shift--; } return diff; }; RPC.prototype.getbestblockhash = function getbestblockhash(args, callback) { if (args.help || args.length !== 0) return callback(new Error('getbestblockhash')); callback(null, this.chain.tip.rhash); }; RPC.prototype.getblockcount = function getblockcount(args, callback) { if (args.help || args.length !== 0) return callback(new Error('getblockcount')); callback(null, this.chain.tip.height + 1); }; RPC.prototype.getblock = function getblock(args, callback) { var self = this; var hash, verbose; if (args.help || args.length < 1 || args.length > 2) return callback(new Error('getblock "hash" ( verbose )')); hash = utils.revHex(String(args[0])); verbose = true; if (args.length > 1) verbose = Boolean(args[1]); this.chain.db.get(hash, function(err, entry) { if (err) return callback(err); if (!entry) return callback(new Error('Block not found')); self.chain.db.getBlock(entry.hash, function(err, block) { if (err) return callback(err); if (!block) { if (self.chain.db.prune) return callback(new Error('Block not available (pruned data)')); return callback(new Error('Can"t read block from disk')); } if (!verbose) return callback(null, block.toRaw('hex')); return self.blockToJSON(entry, block, false, callback); }); }); }; RPC.prototype.txToJSON = function txToJSON(tx) { return { txid: tx.txid, hash: tx.wtxid, size: tx.getSize(), vsize: tx.getVirtualSize(), version: tx.version, locktime: tx.locktime, vin: tx.inputs.map(function(input) { var out = {}; if (tx.isCoinbase()) { out.coinbase = input.script.toRaw().toString('hex'); } else { out.txid = utils.revHex(input.prevout.hash); out.vout = input.prevout.index; out.scriptSig = { asm: input.script.toASM(), hex: input.script.toRaw().toString('hex') }; } if (input.witness.items.length > 0) { out.txinwitness = input.witness.items.map(function(item) { return item.toString('hex'); }); } out.sequence = input.sequence; return out; }), vout: tx.outputs.map(function(output, i) { return { value: utils.btc(output.value), n: i, scriptPubKey: scriptToJSON(output.script, true) }; }), blockhash: tx.block || null, confirmations: tx.getConfirmations(), time: tx.ts, blocktime: tx.ts }; }; function scriptToJSON(script, hex) { var out = {}; var type, address; out.asm = script.toASM(); if (hex) out.hex = script.toRaw().toString('hex'); type = script.getType(); out.type = bcoin.script.typesByVal[type]; out.reqSigs = script.isMultisig() ? bcoin.script.getSmall(script.code[0]) : 1; address = script.getAddress(); out.addresses = address ? [address.toBase58()] : []; return out; } RPC.prototype.getblockhash = function getblockhash(args, callback) { var height; if (args.help || args.length !== 1) return callback(new Error('getblockhash index')); height = args[0]; if (height < 0 || height > this.chain.height) return callback(new Error('Block height out of range.')); this.chain.db.get(height, function(err, entry) { if (err) return callback(err); if (!entry) return callback(new Error('Not found.')); return callback(null, entry.rhash); }); }; RPC.prototype.getblockheader = function getblockheader(args, callback) { var self = this; var hash, verbose; if (args.help || args.length < 1 || args.length > 2) return callback(new Error('getblockheader "hash" ( verbose )')); hash = utils.revHex(String(args[0])); verbose = true; if (args.length > 1) verbose = Boolean(args[1]); this.chain.db.get(hash, function(err, entry) { if (err) return callback(err); if (!entry) return callback(new Error('Block not found')); if (!verbose) return callback(null, entry.toRaw().toString('hex', 0, 80)); return self.blockheaderToJSON(entry, callback); }); }; RPC.prototype.blockheaderToJSON = function blockheaderToJSON(entry, callback) { var self = this; entry.getMedianTimeAsync(function(err, medianTime) { if (err) return callback(err); self.chain.db.getNextHash(entry.hash, function(err, nextHash) { if (err) return callback(err); return callback(null, { hash: utils.revHex(entry.hash), confirmations: this.chain.height - entry.height + 1, height: entry.height, version: entry.version, merkleroot: utils.revHex(entry.merkleRoot), time: entry.ts, mediantime: medianTime, bits: entry.bits, difficulty: self._getDifficulty(entry), chainwork: entry.chainwork.toString('hex'), previousblockhash: entry.prevBlock !== constants.NULL_HASH ? utils.revHex(entry.prevBlock) : null, nextblockhash: nextHash ? utils.revHex(nextHash) : null }); }); }); }; RPC.prototype.blockToJSON = function blockToJSON(entry, block, txDetails, callback) { var self = this; entry.getMedianTimeAsync(function(err, medianTime) { if (err) return callback(err); self.chain.db.getNextHash(entry, function(err, nextHash) { if (err) return callback(err); return callback(null, { hash: utils.revHex(entry.hash), confirmations: this.chain.height - entry.height + 1, strippedsize: block.getBaseSize(), size: block.getSize(), cost: block.getCost(), height: entry.height, version: entry.version, merkleroot: utils.revHex(entry.merkleRoot), tx: block.txs.map(function(tx) { if (txDetails) return self.txToJSON(tx); return tx.rhash; }), time: entry.ts, mediantime: medianTime, bits: entry.bits, difficulty: self._getDifficulty(entry), chainwork: entry.chainwork.toString('hex'), previousblockhash: entry.prevBlock !== constants.NULL_HASH ? utils.revHex(entry.prevBlock) : null, nextblockhash: nextHash ? utils.revHex(nextHash) : null }); }); }); }; RPC.prototype.getchaintips = function getchaintips(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getdifficulty = function getdifficulty(args, callback) { if (args.help || args.length !== 0) return callback(new Error('getdifficulty')); callback(null, this._getDifficulty()); }; RPC.prototype.getmempoolinfo = function getmempoolinfo(args, callback) { callback(null, { size: this.mempool.total, bytes: this.mempool.size, usage: this.mempool.size, maxmempool: constants.mempool.MAX_MEMPOOL_SIZE, mempoolminfee: this.mempool.minFeeRate / constants.COIN }); }; RPC.prototype.getrawmempool = function getrawmempool(args, callback) { var verbose; if (args.help || args.length > 1) return callback(new Error('getrawmempool ( verbose )')); verbose = false; if (args.length > 0) verbose = !!args[0]; return this.mempoolToJSON(verbose, callback); }; RPC.prototype.mempoolToJSON = function mempoolToJSON(verbose, callback) { var self = this; var out = {}; var tx; if (verbose) { return this.mempool.getSnapshot(function(err, hashes) { if (err) return callback(err); utils.forEachSerial(hashes, function(hash, next) { self.mempool.getEntry(hash, function(err, entry) { if (err) return callback(err); tx = entry; out[tx.rhash] = { size: entry.size, fee: entry.fee, modifiedfee: entry.fees, time: entry.ts, height: entry.height, startingpriority: entry.priority, currentpriority: entry.getPriority(self.chain.height), descendantcount: -1, descendantsize: -1, descendantfees: -1, depends: tx.getPrevout() }; next(); }); }, function(err) { if (err) return callback(err); return callback(null, out); }); }); } this.mempool.getSnapshot(function(err, hashes) { if (err) return callback(err); return callback(null, hashes.map(utils.revHex)); }); }; RPC.prototype.gettxout = function gettxout(args, callback) { var self = this; var hash, index, mempool; if (args.help || args.length < 2 || args.length > 3) return callback(new Error('gettxout "txid" n ( includemempool )')); hash = utils.revHex(String(args[0])); index = Number(args[1]); mempool = true; if (args.length > 2) mempool = Boolean(args[2]); function getCoin(callback) { if (mempool) return self.node.getCoin(hash, index, callback); self.chain.db.getCoin(hash, index, callback); } getCoin(function(err, coin) { if (err) return callback(err); if (!coin) return callback(null, null); callback(null, { bestblock: utils.revHex(self.chain.tip.hash), confirmations: coin.getConfirmations(), value: utils.btc(coin.value), scriptPubKey: scriptToJSON(coin.script, true), version: coin.version, coinbase: coin.coinbase }); }); }; RPC.prototype.gettxoutproof = function gettxoutproof(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.verifytxoutproof = function verifytxoutproof(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.gettxoutsetinfo = function gettxoutsetinfo(args, callback) { if (args.help || args.length !== 0) return callback(new Error('gettxoutsetinfo')); callback(null, { height: this.chain.height, bestblock: utils.revHex(this.chain.tip.hash), transactions: 0, txouts: 0, bytes_serialized: 0, hash_serialized: 0, total_amount: 0 }); }; RPC.prototype.verifychain = function verifychain(args, callback) { if (args.help || args.length > 2) return callback(new Error('verifychain ( checklevel numblocks )')); callback(); }; /* * Mining */ RPC.prototype.getblocktemplate = function getblocktemplate(args, callback) { var self = this; var txs = []; var txIndex = {}; var i, j, tx, deps, input, dep, block; if (args.help || args.length > 1) return callback(new Error('getblocktemplate ( "jsonrequestobject" )')); this.miner.createBlock(function(err, attempt) { if (err) return callback(err); block = attempt.block; for (i = 1; i < block.txs.length; i++) { tx = block.txs[i]; txIndex[tx.hash('hex')] = i; deps = []; for (j = 0; j < tx.inputs.length; j++) { input = tx.inputs[j]; dep = txIndex[input.prevout.hash]; if (dep != null) deps.push(dep); } txs.push({ data: tx.toRaw().toString('hex'), txid: tx.rhash, hash: tx.rwhash, depends: deps, fee: tx.getFee(), sigops: tx.getSigops(), cost: tx.getCost() }); } callback(null, { capabilities: ['proposal'], previousblockhash: utils.revHex(block.prevBlock), transactions: txs, coinbaseaux: attempt.coinbaseFlags.toString('hex'), coinbasevalue: attempt.coinbase.outputs[0].value, longpollid: self.chain.tip.rhash + self.mempool.total, target: attempt.target.toString('hex'), mintime: attempt.ts, mutable: ['time', 'transactions', 'prevblock', 'version/force'], noncerange: '00000000ffffffff', sigoplimit: constants.block.MAX_SIGOPS_COST, sizelimit: constants.block.MAX_SIZE, costlimit: constants.block.MAX_COST, curtime: block.ts, bits: block.bits, height: attempt.height, default_witness_commitment: attempt.witness ? attempt.coinbase.outputs[1].script.toRaw().toString('hex') : undefined }); }); }; RPC.prototype.getmininginfo = function getmininginfo(args, callback) { if (args.help || args.length !== 0) return callback(new Error('getmininginfo')); callback(new Error('Not implemented.')); }; RPC.prototype.getnetworkhashps = function getnetworkhashps(args, callback) { var lookup, height; if (args.help || args.length > 2) return callback(new Error('getnetworkhashps ( blocks height )')); lookup = args.length > 0 ? Number(args[0]) : 120; height = args.length > 1 ? Number(args[1]) : -1; return this._hashps(lookup, height, callback); }; RPC.prototype.prioritisetransaction = function prioritisetransaction(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.submitblock = function submitblock(args, callback) { var block; if (args.help || args.length < 1 || args.length > 2) return callback(new Error('submitblock "hexdata" ( "jsonparametersobject" )')); block = bcoin.block.fromRaw(args[0], 'hex'); this.chain.add(block, function(err, total) { if (err) return callback(null, 'rejected'); return callback(null, 'valid'); }); }; RPC.prototype._hashps = function _hashps(lookup, height, callback) { var self = this; var minTime, maxTime, pb0, time, workDiff, timeDiff, ps; function getPB(callback) { if (height >= 0 && height < self.chain.tip.height) return self.chain.db.get(height, callback); return callback(null, self.chain.tip); } getPB(function(err, pb) { if (err) return callback(err); if (!pb) return callback(null, 0); if (lookup <= 0) lookup = pb.height % self.network.pow.retargetInterval + 1; if (lookup > pb.height) lookup = pb.height; minTime = pb.ts; maxTime = minTime; pb0 = pb; utils.forRangeSerial(0, lookup, function(i, next) { pb0.getPrevious(function(err, entry) { if (err) return callback(err); if (!entry) return callback(new Error('Not found.')); pb0 = entry; time = pb0.ts; minTime = Math.min(time, minTime); maxTime = Math.max(time, maxTime); next(); }); }, function(err) { if (err) return callback(err); if (minTime === maxTime) return callback(null, 0); workDiff = pb.chainwork.sub(pb0.chainwork); timeDiff = maxTime - minTime; ps = +workDiff.toString(10) / timeDiff; return callback(null, ps); }); }); }; /* * Coin generation */ RPC.prototype.getgenerate = function getgenerate(args, callback) { callback(null, this.mining); }; RPC.prototype.setgenerate = function setgenerate(args, callback) { this.mining = Boolean(args[0]); this.proclimit = Number(args[1]); if (this.mining) this.miner.start(); else this.miner.stop(); callback(null, this.mining); }; RPC.prototype.generate = function generate(args, callback) { var self = this; var numblocks, hashes; if (args.help || args.length < 1 || args.length > 2) return callback(new Error('generate numblocks ( maxtries )')); numblocks = Number(args[0]); hashes = []; utils.forRangeSerial(0, numblocks, function(i, next) { self.miner.mineBlock(function(err, block) { if (err) return next(err); hashes.push(block.rhash); self.chain.add(block, next); }); }, function(err) { if (err) return callback(err); return callback(null, hashes); }); }; RPC.prototype.generatetoaddress = function generatetoaddress(args, callback) { var self = this; var address; if (args.help || args.length < 2 || args.length > 3) return callback(new Error('generatetoaddress numblocks address (maxtries)')); address = this.miner.address; this.miner.address = bcoin.address.fromBase58(args[1]); this.generate(args, function(err, hashes) { if (err) return callback(err); self.miner.address = address; return callback(null, hashes); }); }; /* * Raw transactions */ RPC.prototype.createrawtransaction = function createrawtransaction(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.decoderawtransaction = function decoderawtransaction(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.decodescript = function decodescript(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getrawtransaction = function getrawtransaction(args, callback) { if (args.help || args.length < 1 || args.length > 2) return callback(new Error('getrawtransaction "txid" ( verbose )')); callback(new Error('Not implemented.')); }; RPC.prototype.sendrawtransaction = function sendrawtransaction(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.signrawtransaction = function signrawtransaction(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.fundrawtransaction = function fundrawtransaction(args, callback) { callback(new Error('Not implemented.')); }; /* Utility functions */ RPC.prototype.createmultisig = function createmultisig(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.createwitnessaddress = function createwitnessaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.validateaddress = function validateaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.verifymessage = function verifymessage(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.estimatefee = function estimatefee(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.estimatepriority = function estimatepriority(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.estimatesmartfee = function estimatesmartfee(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.estimatesmartpriority = function estimatesmartpriority(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.invalidateblock = function invalidateblock(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.reconsiderblock = function reconsiderblock(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.setmocktime = function setmocktime(args, callback) { callback(new Error('Not implemented.')); }; /* * Wallet */ RPC.prototype.resendwallettransactions = function resendwallettransactions(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.addmultisigaddress = function addmultisigaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.addwitnessaddress = function addwitnessaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.backupwallet = function backupwallet(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.dumpprivkey = function dumpprivkey(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.dumpwallet = function dumpwallet(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.encryptwallet = function encryptwallet(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getaccountaddress = function getaccountaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getaccount = function getaccount(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getaddressesbyaccount = function getaddressesbyaccount(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getbalance = function getbalance(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getnewaddress = function getnewaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getrawchangeaddress = function getrawchangeaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getreceivedbyaccount = function getreceivedbyaccount(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getreceivedbyaddress = function getreceivedbyaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.gettransaction = function gettransaction(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.abandontransaction = function abandontransaction(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getunconfirmedbalance = function getunconfirmedbalance(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.getwalletinfo = function getwalletinfo(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.importprivkey = function importprivkey(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.importwallet = function importwallet(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.importaddress = function importaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.importpubkey = function importpubkey(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.keypoolrefill = function keypoolrefill(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.listaccounts = function listaccounts(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.listaddressgroupings = function listaddressgroupings(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.listlockunspent = function listlockunspent(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.listreceivedbyaccount = function listreceivedbyaccount(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.listreceivedbyaddress = function listreceivedbyaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.listsinceblock = function listsinceblock(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.listtransactions = function listtransactions(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.listunspent = function listunspent(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.lockunspent = function lockunspent(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.move = function move(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.sendfrom = function sendfrom(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.sendmany = function sendmany(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.sendtoaddress = function sendtoaddress(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.setaccount = function setaccount(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.settxfee = function settxfee(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.signmessage = function signmessage(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.walletlock = function walletlock(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.walletpassphrasechange = function walletpassphrasechange(args, callback) { callback(new Error('Not implemented.')); }; RPC.prototype.walletpassphrase = function walletpassphrase(args, callback) { callback(new Error('Not implemented.')); }; module.exports = RPC;