stop using vsize. switch to cost.
This commit is contained in:
parent
c312550429
commit
e258755671
@ -125,13 +125,24 @@ Block.prototype._getSize = function _getSize() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Block.prototype.getVirtualSize = function getVirtualSize(force) {
|
Block.prototype.getVirtualSize = function getVirtualSize(force) {
|
||||||
|
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||||
|
return (this.getCost() + scale - 1) / scale | 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate block cost.
|
||||||
|
* @param {Boolean?} force - If true, always recalculate.
|
||||||
|
* @returns {Number} cost
|
||||||
|
*/
|
||||||
|
|
||||||
|
Block.prototype.getCost = function getCost(force) {
|
||||||
var size, witnessSize, base;
|
var size, witnessSize, base;
|
||||||
|
|
||||||
size = this.getSize(force);
|
size = this.getSize(force);
|
||||||
witnessSize = this.getWitnessSize(force);
|
witnessSize = this.getWitnessSize(force);
|
||||||
base = size - witnessSize;
|
base = size - witnessSize;
|
||||||
|
|
||||||
return (base * 4 + witnessSize + 3) / 4 | 0;
|
return base * (constants.WITNESS_SCALE_FACTOR - 1) + size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,6 +157,18 @@ Block.prototype.getSize = function getSize(force) {
|
|||||||
return this._size;
|
return this._size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get base block size (without witness).
|
||||||
|
* @param {Boolean?} force - If true, always recalculate.
|
||||||
|
* @returns {Number} size
|
||||||
|
*/
|
||||||
|
|
||||||
|
Block.prototype.getBaseSize = function getBaseSize(force) {
|
||||||
|
if (force || this._size === 0)
|
||||||
|
this._getSize();
|
||||||
|
return this._size - this._witnessSize;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the total size of the witnesses.
|
* Get the total size of the witnesses.
|
||||||
* @param {Boolean?} force - If true, always recalculate.
|
* @param {Boolean?} force - If true, always recalculate.
|
||||||
@ -202,24 +225,6 @@ Block.prototype.indexOf = function indexOf(hash) {
|
|||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Count sigops taking into account the cost vs. witness ops.
|
|
||||||
* @param {Boolean?} scriptHash - Whether to count redeem script ops.
|
|
||||||
* @param {Boolean?} accurate - Whether to use accurate counting
|
|
||||||
* for CHECKMULTISIG(VERIFY).
|
|
||||||
* @returns {Number} sigops
|
|
||||||
*/
|
|
||||||
|
|
||||||
Block.prototype.getSigops = function getSigops(scriptHash, accurate) {
|
|
||||||
var total = 0;
|
|
||||||
var i;
|
|
||||||
|
|
||||||
for (i = 0; i < this.txs.length; i++)
|
|
||||||
total += this.txs[i].getSigops(scriptHash, accurate);
|
|
||||||
|
|
||||||
return total;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate merkle root.
|
* Calculate merkle root.
|
||||||
* @param {String?} enc - Encoding, can be `'hex'` or null.
|
* @param {String?} enc - Encoding, can be `'hex'` or null.
|
||||||
@ -327,6 +332,7 @@ Block.prototype.__defineGetter__('commitmentHash', function() {
|
|||||||
|
|
||||||
Block.prototype._verify = function _verify(ret) {
|
Block.prototype._verify = function _verify(ret) {
|
||||||
var sigops = 0;
|
var sigops = 0;
|
||||||
|
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||||
var i, tx, merkle;
|
var i, tx, merkle;
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@ -337,7 +343,7 @@ Block.prototype._verify = function _verify(ret) {
|
|||||||
|
|
||||||
// Size can't be bigger than MAX_BLOCK_SIZE
|
// Size can't be bigger than MAX_BLOCK_SIZE
|
||||||
if (this.txs.length > constants.block.MAX_SIZE
|
if (this.txs.length > constants.block.MAX_SIZE
|
||||||
|| this.getVirtualSize() > constants.block.MAX_SIZE) {
|
|| this.getBaseSize() > constants.block.MAX_SIZE) {
|
||||||
ret.reason = 'bad-blk-length';
|
ret.reason = 'bad-blk-length';
|
||||||
ret.score = 100;
|
ret.score = 100;
|
||||||
return false;
|
return false;
|
||||||
@ -366,13 +372,13 @@ Block.prototype._verify = function _verify(ret) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Count legacy sigops (do not count scripthash or witness)
|
// Count legacy sigops (do not count scripthash or witness)
|
||||||
// sigops += tx._getSigops();
|
sigops += tx.getLegacySigops();
|
||||||
// if (sigops > constants.block.MAX_SIGOPS) {
|
if (sigops * scale > constants.block.MAX_SIGOPS_COST) {
|
||||||
// return callback(new VerifyError(block,
|
return callback(new VerifyError(block,
|
||||||
// 'invalid',
|
'invalid',
|
||||||
// 'bad-blk-sigops',
|
'bad-blk-sigops',
|
||||||
// 100));
|
100));
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check merkle root
|
// Check merkle root
|
||||||
|
|||||||
@ -555,6 +555,15 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check block cost (different from block size
|
||||||
|
// check in non-contextual verification).
|
||||||
|
if (block.getCost() > constants.block.MAX_COST) {
|
||||||
|
return done(new VerifyError(block,
|
||||||
|
'invalid',
|
||||||
|
'bad-blk-cost',
|
||||||
|
100));
|
||||||
|
}
|
||||||
|
|
||||||
// Get timestamp for tx.isFinal().
|
// Get timestamp for tx.isFinal().
|
||||||
ts = (state.lockFlags & constants.flags.MEDIAN_TIME_PAST) !== 0
|
ts = (state.lockFlags & constants.flags.MEDIAN_TIME_PAST) !== 0
|
||||||
? medianTime
|
? medianTime
|
||||||
@ -819,21 +828,6 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
|
|||||||
tx = block.txs[i];
|
tx = block.txs[i];
|
||||||
hash = tx.hash('hex');
|
hash = tx.hash('hex');
|
||||||
|
|
||||||
// Check for block sigops limits
|
|
||||||
// Start counting P2SH sigops once block
|
|
||||||
// timestamps reach March 31st, 2012.
|
|
||||||
if (flags & constants.flags.VERIFY_P2SH)
|
|
||||||
sigops += tx.getSigops(true);
|
|
||||||
else
|
|
||||||
sigops += tx.getSigops();
|
|
||||||
|
|
||||||
if (sigops > constants.block.MAX_SIGOPS) {
|
|
||||||
return callback(new VerifyError(block,
|
|
||||||
'invalid',
|
|
||||||
'bad-blk-sigops',
|
|
||||||
100));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Coinbases do not have prevouts
|
// Coinbases do not have prevouts
|
||||||
if (tx.isCoinbase())
|
if (tx.isCoinbase())
|
||||||
continue;
|
continue;
|
||||||
@ -876,6 +870,16 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Count sigops (legacy + scripthash? + witness?)
|
||||||
|
sigops += tx.getSigopsCost(flags);
|
||||||
|
|
||||||
|
if (sigops > constants.block.MAX_SIGOPS_COST) {
|
||||||
|
return callback(new VerifyError(block,
|
||||||
|
'invalid',
|
||||||
|
'bad-blk-sigops',
|
||||||
|
100));
|
||||||
|
}
|
||||||
|
|
||||||
if (!tx.checkInputs(height, ret)) {
|
if (!tx.checkInputs(height, ret)) {
|
||||||
return callback(new VerifyError(block,
|
return callback(new VerifyError(block,
|
||||||
'invalid',
|
'invalid',
|
||||||
|
|||||||
@ -550,6 +550,8 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!tx.hasCoins()) {
|
if (!tx.hasCoins()) {
|
||||||
|
// if (tx.getSize() > 5000)
|
||||||
|
// return callback();
|
||||||
if (self.totalSize > constants.mempool.MAX_MEMPOOL_SIZE) {
|
if (self.totalSize > constants.mempool.MAX_MEMPOOL_SIZE) {
|
||||||
return callback(new VerifyError(tx,
|
return callback(new VerifyError(tx,
|
||||||
'insufficientfee',
|
'insufficientfee',
|
||||||
@ -700,7 +702,7 @@ Mempool.prototype.verify = function verify(tx, callback) {
|
|||||||
0));
|
0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.getSigops(true) > constants.tx.MAX_SIGOPS) {
|
if (tx.getSigopsCost(flags) > constants.tx.MAX_SIGOPS_COST) {
|
||||||
return callback(new VerifyError(tx,
|
return callback(new VerifyError(tx,
|
||||||
'nonstandard',
|
'nonstandard',
|
||||||
'bad-txns-too-many-sigops',
|
'bad-txns-too-many-sigops',
|
||||||
|
|||||||
@ -460,15 +460,14 @@ MinerBlock.prototype.updateMerkle = function updateMerkle() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
MinerBlock.prototype.addTX = function addTX(tx) {
|
MinerBlock.prototype.addTX = function addTX(tx) {
|
||||||
var size;
|
var cost;
|
||||||
|
|
||||||
if (tx.mutable)
|
if (tx.mutable)
|
||||||
tx = tx.toTX();
|
tx = tx.toTX();
|
||||||
|
|
||||||
size = this.block.getVirtualSize(true) + tx.getVirtualSize();
|
cost = this.block.getCost(true) + tx.getCost();
|
||||||
|
|
||||||
// Deliver me from the block size debate, please
|
if (cost > constants.block.MAX_COST)
|
||||||
if (size > constants.block.MAX_SIZE)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (this.block.hasTX(tx))
|
if (this.block.hasTX(tx))
|
||||||
|
|||||||
@ -369,6 +369,14 @@ exports.hashType = {
|
|||||||
|
|
||||||
exports.hashTypeByVal = utils.revMap(exports.hashType);
|
exports.hashTypeByVal = utils.revMap(exports.hashType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount to multiply base/non-witness sizes by.
|
||||||
|
* @const {Number}
|
||||||
|
* @default
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.WITNESS_SCALE_FACTOR = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block-related constants.
|
* Block-related constants.
|
||||||
* @enum {Number}
|
* @enum {Number}
|
||||||
@ -377,7 +385,9 @@ exports.hashTypeByVal = utils.revMap(exports.hashType);
|
|||||||
|
|
||||||
exports.block = {
|
exports.block = {
|
||||||
MAX_SIZE: 1000000,
|
MAX_SIZE: 1000000,
|
||||||
|
MAX_COST: 4000000,
|
||||||
MAX_SIGOPS: 1000000 / 50,
|
MAX_SIGOPS: 1000000 / 50,
|
||||||
|
MAX_SIGOPS_COST: 80000,
|
||||||
MEDIAN_TIMESPAN: 11,
|
MEDIAN_TIMESPAN: 11,
|
||||||
BIP16_TIME: 1333238400,
|
BIP16_TIME: 1333238400,
|
||||||
SIGHASH_LIMIT: 1300000000
|
SIGHASH_LIMIT: 1300000000
|
||||||
@ -404,10 +414,12 @@ exports.bip30 = {
|
|||||||
exports.tx = {
|
exports.tx = {
|
||||||
MAX_VERSION: 2,
|
MAX_VERSION: 2,
|
||||||
MAX_SIZE: 100000,
|
MAX_SIZE: 100000,
|
||||||
|
MAX_COST: 400000,
|
||||||
MIN_FEE: 10000,
|
MIN_FEE: 10000,
|
||||||
BARE_MULTISIG: true,
|
BARE_MULTISIG: true,
|
||||||
FREE_THRESHOLD: exports.COIN.muln(144).divn(250),
|
FREE_THRESHOLD: exports.COIN.muln(144).divn(250),
|
||||||
MAX_SIGOPS: exports.block.MAX_SIGOPS / 5,
|
MAX_SIGOPS: exports.block.MAX_SIGOPS / 5,
|
||||||
|
MAX_SIGOPS_COST: exports.block.MAX_SIGOPS_COST / 5,
|
||||||
COINBASE_MATURITY: 100
|
COINBASE_MATURITY: 100
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1423,9 +1423,8 @@ Framer.tx.size = function txSize(tx) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Framer.block.virtualSize = function blockVirtualSize(block) {
|
Framer.block.virtualSize = function blockVirtualSize(block) {
|
||||||
var sizes = Framer.block.sizes(block);
|
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||||
var base = sizes.size - sizes.witnessSize;
|
return (Framer.block.cost(block) + scale - 1) / scale | 0;
|
||||||
return (base * 4 + sizes.witnessSize + 3) / 4 | 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1435,9 +1434,34 @@ Framer.block.virtualSize = function blockVirtualSize(block) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Framer.tx.virtualSize = function txVirtualSize(tx) {
|
Framer.tx.virtualSize = function txVirtualSize(tx) {
|
||||||
|
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||||
|
return (Framer.tx.cost(tx) + scale - 1) / scale | 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate block cost.
|
||||||
|
* @param {NakedBlock|Block} block
|
||||||
|
* @returns {Number} cost
|
||||||
|
*/
|
||||||
|
|
||||||
|
Framer.block.cost = function blockCost(block) {
|
||||||
|
var sizes = Framer.block.sizes(block);
|
||||||
|
var base = sizes.size - sizes.witnessSize;
|
||||||
|
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||||
|
return base * (scale - 1) + sizes.size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate transaction cost.
|
||||||
|
* @param {NakedTX|TX} tx
|
||||||
|
* @returns {Number} cost
|
||||||
|
*/
|
||||||
|
|
||||||
|
Framer.tx.cost = function txCost(tx) {
|
||||||
var sizes = Framer.tx.sizes(tx);
|
var sizes = Framer.tx.sizes(tx);
|
||||||
var base = sizes.size - sizes.witnessSize;
|
var base = sizes.size - sizes.witnessSize;
|
||||||
return (base * 4 + sizes.witnessSize + 3) / 4 | 0;
|
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||||
|
return base * (scale - 1) + sizes.size;
|
||||||
};
|
};
|
||||||
|
|
||||||
return Framer;
|
return Framer;
|
||||||
|
|||||||
@ -3437,9 +3437,6 @@ Script.prototype.getSigops = function getSigops(accurate) {
|
|||||||
var lastOp = -1;
|
var lastOp = -1;
|
||||||
var i, op;
|
var i, op;
|
||||||
|
|
||||||
if (flags == null)
|
|
||||||
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
|
||||||
|
|
||||||
for (i = 0; i < this.code.length; i++) {
|
for (i = 0; i < this.code.length; i++) {
|
||||||
op = this.code[i];
|
op = this.code[i];
|
||||||
|
|
||||||
|
|||||||
@ -290,6 +290,17 @@ TX.prototype.getRaw = function getRaw() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TX.prototype.getVirtualSize = function getVirtualSize() {
|
TX.prototype.getVirtualSize = function getVirtualSize() {
|
||||||
|
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||||
|
return (this.getCost() + scale - 1) / scale | 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the cost of the transaction.
|
||||||
|
* Note that this is cached.
|
||||||
|
* @returns {Number} cost
|
||||||
|
*/
|
||||||
|
|
||||||
|
TX.prototype.getCost = function getCost() {
|
||||||
var size, witnessSize, base;
|
var size, witnessSize, base;
|
||||||
|
|
||||||
this.getRaw();
|
this.getRaw();
|
||||||
@ -298,7 +309,7 @@ TX.prototype.getVirtualSize = function getVirtualSize() {
|
|||||||
witnessSize = this._witnessSize;
|
witnessSize = this._witnessSize;
|
||||||
base = size - witnessSize;
|
base = size - witnessSize;
|
||||||
|
|
||||||
return (base * 4 + witnessSize + 3) / 4 | 0;
|
return base * (constants.WITNESS_SCALE_FACTOR - 1) + size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -886,11 +897,11 @@ TX.prototype.getLegacySigops = function getLegacySigops() {
|
|||||||
var total = 0;
|
var total = 0;
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
for (i = 0; i < tx.inputs.length; i++)
|
for (i = 0; i < this.inputs.length; i++)
|
||||||
total += tx.inputs[i].script.getSigops(false);
|
total += this.inputs[i].script.getSigops(false);
|
||||||
|
|
||||||
for (i = 0; i < tx.outputs.length; i++)
|
for (i = 0; i < this.outputs.length; i++)
|
||||||
total += tx.outputs[i].script.getSigops(false);
|
total += this.outputs[i].script.getSigops(false);
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
};
|
};
|
||||||
@ -907,8 +918,12 @@ TX.prototype.getScripthashSigops = function getScripthashSigops() {
|
|||||||
if (this.isCoinbase())
|
if (this.isCoinbase())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < tx.inputs.length; i++) {
|
for (i = 0; i < this.inputs.length; i++) {
|
||||||
input = tx.inputs[i];
|
input = this.inputs[i];
|
||||||
|
|
||||||
|
if (!input.coin)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (input.coin.script.isScripthash())
|
if (input.coin.script.isScripthash())
|
||||||
total += input.coin.script.getSigops(input.script);
|
total += input.coin.script.getSigops(input.script);
|
||||||
}
|
}
|
||||||
@ -923,7 +938,7 @@ TX.prototype.getScripthashSigops = function getScripthashSigops() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TX.prototype.getSigopsCost = function getSigopsCost(flags) {
|
TX.prototype.getSigopsCost = function getSigopsCost(flags) {
|
||||||
var cost = this.getLegacySigops() * 4;
|
var cost = this.getLegacySigops() * constants.WITNESS_SCALE_FACTOR;
|
||||||
var input, i;
|
var input, i;
|
||||||
|
|
||||||
if (flags == null)
|
if (flags == null)
|
||||||
@ -933,10 +948,14 @@ TX.prototype.getSigopsCost = function getSigopsCost(flags) {
|
|||||||
return cost;
|
return cost;
|
||||||
|
|
||||||
if (flags & constants.flags.VERIFY_P2SH)
|
if (flags & constants.flags.VERIFY_P2SH)
|
||||||
cost += this.getScripthashSigops() * 4;
|
cost += this.getScripthashSigops() * constants.WITNESS_SCALE_FACTOR;
|
||||||
|
|
||||||
for (i = 0; i < this.inputs.length; i++) {
|
for (i = 0; i < this.inputs.length; i++) {
|
||||||
input = this.inputs[i];
|
input = this.inputs[i];
|
||||||
|
|
||||||
|
if (!input.coin)
|
||||||
|
continue;
|
||||||
|
|
||||||
cost += Script.getWitnessSigops(
|
cost += Script.getWitnessSigops(
|
||||||
input.script,
|
input.script,
|
||||||
input.coin.script,
|
input.coin.script,
|
||||||
@ -989,7 +1008,7 @@ TX.prototype.isSane = function isSane(ret) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getVirtualSize() > constants.block.MAX_SIZE) {
|
if (this.getSize() > constants.block.MAX_SIZE) {
|
||||||
ret.reason = 'bad-txns-oversize';
|
ret.reason = 'bad-txns-oversize';
|
||||||
ret.score = 100;
|
ret.score = 100;
|
||||||
return false;
|
return false;
|
||||||
@ -1079,7 +1098,7 @@ TX.prototype.isStandard = function isStandard(flags, ret) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getVirtualSize() > constants.tx.MAX_SIZE) {
|
if (this.getCost() > constants.tx.MAX_COST) {
|
||||||
ret.reason = 'tx-size';
|
ret.reason = 'tx-size';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1162,11 +1181,7 @@ TX.prototype.hasStandardInputs = function hasStandardInputs(flags) {
|
|||||||
|
|
||||||
if ((flags & constants.flags.VERIFY_P2SH)
|
if ((flags & constants.flags.VERIFY_P2SH)
|
||||||
&& input.coin.script.isScripthash()) {
|
&& input.coin.script.isScripthash()) {
|
||||||
// Not accurate:
|
assert(input.script.isPushOnly());
|
||||||
// Failsafe to avoid getting dos'd in case we ever
|
|
||||||
// call hasStandardInputs before isStandard.
|
|
||||||
if (!input.script.isPushOnly())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
stack = new Stack();
|
stack = new Stack();
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,23 @@
|
|||||||
|
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
var querystring = require('querystring');
|
var querystring = require('querystring');
|
||||||
|
var utils = require('./utils');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ParsedURI
|
||||||
|
* @property {Base58Address} address
|
||||||
|
* @property {BN?} amount? - Amount in satoshis.
|
||||||
|
* @property {String?} label
|
||||||
|
* @property {String?} message
|
||||||
|
* @property {String?} request - Payment request URL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a bitcoin URI.
|
||||||
|
* @param {String} uri - Bitcoin URI.
|
||||||
|
* @returns {ParsedURI}
|
||||||
|
* @throws on non-bitcoin uri
|
||||||
|
*/
|
||||||
|
|
||||||
exports.parse = function parse(uri) {
|
exports.parse = function parse(uri) {
|
||||||
var data = url.parse(uri);
|
var data = url.parse(uri);
|
||||||
@ -24,6 +41,12 @@ exports.parse = function parse(uri) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether an object is a bitcoin URI.
|
||||||
|
* @param {String} uri
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
exports.validate = function validate(uri) {
|
exports.validate = function validate(uri) {
|
||||||
try {
|
try {
|
||||||
exports.parse(uri);
|
exports.parse(uri);
|
||||||
@ -33,6 +56,14 @@ exports.validate = function validate(uri) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode data as a bitcoin URI.
|
||||||
|
* @param {ParsedURI|Base58Address} data/address
|
||||||
|
* @param {BN?} amount
|
||||||
|
* @returns {String} URI
|
||||||
|
* @throws when no address provided
|
||||||
|
*/
|
||||||
|
|
||||||
exports.stringify = function stringify(address, amount) {
|
exports.stringify = function stringify(address, amount) {
|
||||||
var query = {};
|
var query = {};
|
||||||
var data = address;
|
var data = address;
|
||||||
@ -57,5 +88,10 @@ exports.stringify = function stringify(address, amount) {
|
|||||||
if (data.request)
|
if (data.request)
|
||||||
query.r = data.request;
|
query.r = data.request;
|
||||||
|
|
||||||
return uri + querystring.stringify(query);
|
query = querystring.stringify(query);
|
||||||
|
|
||||||
|
if (query.length === 0)
|
||||||
|
return uri;
|
||||||
|
|
||||||
|
return uri + '?' + query;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user