more tests. utils.
This commit is contained in:
parent
022de4a91d
commit
4b0519a073
@ -431,10 +431,26 @@ Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
|
||||
|
||||
Block.prototype.getReward = function getReward(network) {
|
||||
var reward = Block.reward(this.height, network);
|
||||
var i;
|
||||
var i, fee;
|
||||
|
||||
for (i = 1; i < this.txs.length; i++)
|
||||
reward += this.txs[i].getFee();
|
||||
for (i = 1; i < this.txs.length; i++) {
|
||||
fee = this.txs[i].getFee();
|
||||
|
||||
if (fee < 0 || fee > constants.MAX_MONEY)
|
||||
return -1;
|
||||
|
||||
reward += fee;
|
||||
|
||||
// We don't want to go above 53 bits.
|
||||
// This is to make the getClaimed check
|
||||
// fail if the miner mined an evil block.
|
||||
// Note that this check ONLY works because
|
||||
// MAX_MONEY is 51 bits. The result of
|
||||
// (51 bits + 51 bits) is _never_ greater
|
||||
// than 52 bits.
|
||||
if (reward < 0 || reward > constants.MAX_MONEY)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return reward;
|
||||
};
|
||||
@ -459,6 +475,8 @@ Block.prototype.getClaimed = function getClaimed() {
|
||||
Block.reward = function _reward(height, network) {
|
||||
var halvings, reward;
|
||||
|
||||
assert(height !== -1, 'Height is negative.');
|
||||
|
||||
network = bcoin.network.get(network);
|
||||
halvings = height / network.halvingInterval | 0;
|
||||
|
||||
|
||||
@ -633,23 +633,16 @@ utils.assert.fatal = function fatal(value, message) {
|
||||
};
|
||||
|
||||
/**
|
||||
* One bitcoin in satoshis.
|
||||
* @const {BN}
|
||||
* @default
|
||||
*/
|
||||
|
||||
utils.COIN = 100000000;
|
||||
|
||||
/**
|
||||
* Convert satoshis to a BTC string. Note that
|
||||
* BTC strings _always_ have a decimal point.
|
||||
* @param {BN|Number} satoshi
|
||||
* Convert satoshis to a BTC string.
|
||||
* This function explicitly avoids
|
||||
* any floating point arithmetic.
|
||||
* @param {Number} satoshi
|
||||
* @returns {String} BTC string.
|
||||
*/
|
||||
|
||||
utils.btc = function btc(satoshi) {
|
||||
var neg = false;
|
||||
var btc, hi, lo;
|
||||
var negative = false;
|
||||
var btc;
|
||||
|
||||
if (utils.isBTC(satoshi))
|
||||
return satoshi;
|
||||
@ -658,24 +651,22 @@ utils.btc = function btc(satoshi) {
|
||||
|
||||
if (satoshi < 0) {
|
||||
satoshi = -satoshi;
|
||||
neg = true;
|
||||
negative = true;
|
||||
}
|
||||
|
||||
hi = Math.floor(satoshi / utils.COIN).toString(10);
|
||||
lo = (satoshi % utils.COIN).toString(10);
|
||||
btc = satoshi.toString(10);
|
||||
|
||||
while (lo.length < 8)
|
||||
lo = '0' + lo;
|
||||
while (btc.length < 9)
|
||||
btc = '0' + btc;
|
||||
|
||||
lo = '.' + lo;
|
||||
btc = btc.slice(0, -8) + '.' + btc.slice(-8);
|
||||
|
||||
lo = lo.replace(/0+$/, '');
|
||||
if (lo === '.')
|
||||
lo += '0';
|
||||
btc = btc.replace(/0+$/, '');
|
||||
|
||||
btc = hi + lo;
|
||||
if (btc[btc.length - 1] === '.')
|
||||
btc = btc.slice(0, -1);
|
||||
|
||||
if (neg)
|
||||
if (negative)
|
||||
btc = '-' + btc;
|
||||
|
||||
return btc;
|
||||
@ -683,12 +674,15 @@ utils.btc = function btc(satoshi) {
|
||||
|
||||
/**
|
||||
* Convert BTC string to satoshis.
|
||||
* @param {String|Number} btc
|
||||
* @returns {BN} Satoshis.
|
||||
* This function explicitly avoids
|
||||
* any floating point arithmetic.
|
||||
* @param {String} btc
|
||||
* @returns {Number} Satoshis.
|
||||
* @throws on parse error
|
||||
*/
|
||||
|
||||
utils.satoshi = function satoshi(btc) {
|
||||
var neg = false;
|
||||
var negative = false;
|
||||
var satoshi, parts, hi, lo;
|
||||
|
||||
if (utils.isSatoshi(btc))
|
||||
@ -697,24 +691,31 @@ utils.satoshi = function satoshi(btc) {
|
||||
assert(utils.isBTC(btc), 'Non-BTC value for conversion.');
|
||||
|
||||
if (btc[0] === '-') {
|
||||
neg = true;
|
||||
negative = true;
|
||||
btc = btc.substring(1);
|
||||
}
|
||||
|
||||
parts = btc.split('.');
|
||||
|
||||
assert(parts.length <= 2, 'Bad decimal point.');
|
||||
|
||||
hi = parts[0] || '0';
|
||||
lo = parts[1] || '0';
|
||||
|
||||
hi = hi.replace(/^0+/, '');
|
||||
lo = lo.replace(/0+$/, '');
|
||||
|
||||
assert(hi.length <= 8, 'Number exceeds MAX_MONEY.');
|
||||
assert(+hi < 21000000, 'Number exceeds MAX_MONEY.');
|
||||
|
||||
assert(lo.length <= 8, 'Too many decimal places.');
|
||||
|
||||
while (lo.length < 8)
|
||||
lo += '0';
|
||||
|
||||
assert(lo.length === 8);
|
||||
satoshi = parseInt(hi + lo, 10);
|
||||
|
||||
satoshi = (hi + lo).replace(/^0+/, '');
|
||||
|
||||
satoshi = parseInt(satoshi, 10);
|
||||
|
||||
if (neg)
|
||||
if (negative)
|
||||
satoshi = -satoshi;
|
||||
|
||||
return satoshi;
|
||||
@ -747,7 +748,10 @@ utils.isSatoshi = function isSatoshi(val) {
|
||||
*/
|
||||
|
||||
utils.isBTC = function isBTC(val) {
|
||||
return typeof val === 'string' && /^-?\d+\.\d+$/.test(val);
|
||||
return typeof val === 'string'
|
||||
&& /^-?(\d+)?(?:\.\d*)?$/.test(val)
|
||||
&& val.length !== 0
|
||||
&& val !== '-';
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1083,7 +1087,7 @@ utils.uniq = function uniq(obj) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a mantissa/compact number to a big number.
|
||||
* Convert a compact number to a big number.
|
||||
* Used for `block.bits` -> `target` conversion.
|
||||
* @param {Number} compact
|
||||
* @returns {BN}
|
||||
@ -1115,7 +1119,7 @@ utils.fromCompact = function fromCompact(compact) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a big number to a mantissa/compact number.
|
||||
* Convert a big number to a compact number.
|
||||
* Used for `target` -> `block.bits` conversion.
|
||||
* @param {BN} num
|
||||
* @returns {Number}
|
||||
@ -1148,8 +1152,7 @@ utils.toCompact = function toCompact(num) {
|
||||
if (num.isNeg())
|
||||
compact |= 0x800000;
|
||||
|
||||
if (compact < 0)
|
||||
compact += 0x100000000;
|
||||
compact >>>= 0;
|
||||
|
||||
return compact;
|
||||
};
|
||||
@ -1589,7 +1592,7 @@ utils.MAX_SAFE_INTEGER = 0x1fffffffffffff;
|
||||
*/
|
||||
|
||||
utils.write64N = function write64N(dst, num, off, be) {
|
||||
var neg, hi, lo;
|
||||
var negative, hi, lo;
|
||||
|
||||
assert(typeof num === 'number');
|
||||
|
||||
@ -1597,18 +1600,17 @@ utils.write64N = function write64N(dst, num, off, be) {
|
||||
|
||||
assert(num <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1');
|
||||
|
||||
if (num < 0)
|
||||
neg = true;
|
||||
negative = num < 0;
|
||||
|
||||
num = num < 0 ? -num : num;
|
||||
|
||||
if (neg)
|
||||
num--;
|
||||
if (negative) {
|
||||
num = -num;
|
||||
num -= 1;
|
||||
}
|
||||
|
||||
hi = num / 0x100000000 | 0;
|
||||
lo = num % 0x100000000;
|
||||
|
||||
if (neg) {
|
||||
if (negative) {
|
||||
hi = ~hi >>> 0;
|
||||
lo = ~lo >>> 0;
|
||||
}
|
||||
|
||||
@ -52,8 +52,24 @@ describe('Block', function() {
|
||||
it('should be jsonified and unjsonified and still verify', function() {
|
||||
var json = block.toRaw();
|
||||
var b = bcoin.merkleblock.fromRaw(json);
|
||||
// FIXME
|
||||
//assert.equal(b.render(), json);
|
||||
assert.deepEqual(b.render(), json);
|
||||
assert(b.verify());
|
||||
});
|
||||
|
||||
it('should calculate reward properly', function() {
|
||||
var height = 0;
|
||||
var total = 0;
|
||||
var reward;
|
||||
|
||||
for (;;) {
|
||||
reward = bcoin.block.reward(height);
|
||||
total += reward;
|
||||
if (reward === 0)
|
||||
break;
|
||||
height++;
|
||||
}
|
||||
|
||||
assert.equal(height, 6930000);
|
||||
assert.equal(total, 2099999997690000);
|
||||
});
|
||||
});
|
||||
|
||||
174
test/tx-test.js
174
test/tx-test.js
@ -269,4 +269,178 @@ describe('TX', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createInput(value) {
|
||||
var hash = bcoin.ec.random(32).toString('hex');
|
||||
return {
|
||||
prevout: {
|
||||
hash: hash,
|
||||
index: 0
|
||||
},
|
||||
coin: {
|
||||
version: 1,
|
||||
height: 0,
|
||||
value: value,
|
||||
script: [],
|
||||
coinbase: false,
|
||||
hash: hash,
|
||||
index: 0
|
||||
},
|
||||
script: [],
|
||||
witness: [],
|
||||
sequence: 0xffffffff
|
||||
};
|
||||
}
|
||||
|
||||
it('should fail on >51 bit coin values', function () {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [createInput(constants.MAX_MONEY + 1)],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: constants.MAX_MONEY
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
assert.ok(tx.isSane());
|
||||
assert.ok(!tx.checkInputs(0));
|
||||
});
|
||||
|
||||
it('should handle 51 bit coin values', function () {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [createInput(constants.MAX_MONEY)],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: constants.MAX_MONEY
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
assert.ok(tx.isSane());
|
||||
assert.ok(tx.checkInputs(0));
|
||||
});
|
||||
|
||||
it('should fail on >51 bit output values', function () {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [createInput(constants.MAX_MONEY)],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: constants.MAX_MONEY + 1
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
assert.ok(!tx.isSane());
|
||||
assert.ok(!tx.checkInputs(0));
|
||||
});
|
||||
|
||||
it('should handle 51 bit output values', function () {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [createInput(constants.MAX_MONEY)],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: constants.MAX_MONEY
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
assert.ok(tx.isSane());
|
||||
assert.ok(tx.checkInputs(0));
|
||||
});
|
||||
|
||||
it('should fail on >51 bit fees', function () {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [createInput(constants.MAX_MONEY + 1)],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: 0
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
assert.ok(tx.isSane());
|
||||
assert.ok(!tx.checkInputs(0));
|
||||
});
|
||||
|
||||
it('should fail on >51 bit values from multiple', function () {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [
|
||||
createInput(Math.floor(constants.MAX_MONEY / 2)),
|
||||
createInput(Math.floor(constants.MAX_MONEY / 2)),
|
||||
createInput(Math.floor(constants.MAX_MONEY / 2))
|
||||
],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: constants.MAX_MONEY
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
assert.ok(tx.isSane());
|
||||
assert.ok(!tx.checkInputs(0));
|
||||
});
|
||||
|
||||
it('should fail on >51 bit fees from multiple', function () {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [
|
||||
createInput(Math.floor(constants.MAX_MONEY / 2)),
|
||||
createInput(Math.floor(constants.MAX_MONEY / 2)),
|
||||
createInput(Math.floor(constants.MAX_MONEY / 2))
|
||||
],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: 0
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
assert.ok(tx.isSane());
|
||||
assert.ok(!tx.checkInputs(0));
|
||||
});
|
||||
|
||||
it('should fail on >51 bit fees from multiple txs', function () {
|
||||
var data = utils.merge(bcoin.network.get().genesis, { height: 0 });
|
||||
var block = new bcoin.block(data);
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [
|
||||
createInput(Math.floor(constants.MAX_MONEY / 2))
|
||||
],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: 0
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
block.txs.push(tx);
|
||||
}
|
||||
assert.equal(block.getReward(), -1);
|
||||
});
|
||||
|
||||
it('should fail to parse >53 bit values', function () {
|
||||
var tx = bcoin.tx({
|
||||
version: 1,
|
||||
inputs: [
|
||||
createInput(Math.floor(constants.MAX_MONEY / 2))
|
||||
],
|
||||
outputs: [{
|
||||
script: [],
|
||||
value: 0
|
||||
}],
|
||||
locktime: 0
|
||||
});
|
||||
tx.outputs[0].value = new bn('00ffffffffffffff', 'hex');
|
||||
assert(tx.outputs[0].value.bitLength() === 56);
|
||||
var raw = tx.toRaw()
|
||||
assert.throws(function() {
|
||||
tx.fromRaw(raw);
|
||||
});
|
||||
tx.outputs[0].value = new bn('00ffffffffffffff', 'hex').ineg();
|
||||
assert(tx.outputs[0].value.bitLength() === 56);
|
||||
var raw = tx.toRaw()
|
||||
assert.throws(function() {
|
||||
tx.fromRaw(raw);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -27,7 +27,7 @@ describe('Utils', function() {
|
||||
btc = utils.btc(54678 * 1000000);
|
||||
assert.equal(btc, '546.78');
|
||||
btc = utils.btc(5460 * 10000000);
|
||||
assert.equal(btc, '546.0');
|
||||
assert.equal(btc, '546');
|
||||
});
|
||||
|
||||
it('should convert btc to satoshi', function() {
|
||||
@ -35,7 +35,76 @@ describe('Utils', function() {
|
||||
assert(btc === 5460);
|
||||
btc = utils.satoshi('546.78');
|
||||
assert(btc === 54678 * 1000000);
|
||||
btc = utils.satoshi('546.0');
|
||||
btc = utils.satoshi('546');
|
||||
assert(btc === 5460 * 10000000);
|
||||
});
|
||||
|
||||
var unsigned = [
|
||||
new bn('ffeeffee'),
|
||||
new bn('001fffeeffeeffee'),
|
||||
new bn('eeffeeff'),
|
||||
new bn('001feeffeeffeeff'),
|
||||
new bn(0),
|
||||
new bn(1)
|
||||
];
|
||||
|
||||
var signed = [
|
||||
new bn('ffeeffee'),
|
||||
new bn('001fffeeffeeffee'),
|
||||
new bn('eeffeeff'),
|
||||
new bn('001feeffeeffeeff'),
|
||||
new bn(0),
|
||||
new bn(1),
|
||||
new bn('ffeeffee').ineg(),
|
||||
new bn('001fffeeffeeffee').ineg(),
|
||||
new bn('eeffeeff').ineg(),
|
||||
new bn('001feeffeeffeeff').ineg(),
|
||||
new bn(0).ineg(),
|
||||
new bn(1).ineg()
|
||||
];
|
||||
|
||||
unsigned.forEach(function(num) {
|
||||
var buf1 = new Buffer(8);
|
||||
var buf2 = new Buffer(8);
|
||||
var msg = 'should write+read a ' + num.bitLength() + ' bit unsigned int';
|
||||
it(msg, function() {
|
||||
utils.writeU64(buf1, num, 0);
|
||||
utils.writeU64N(buf2, num.toNumber(), 0);
|
||||
assert.deepEqual(buf1, buf2);
|
||||
var n1 = utils.readU64(buf1, 0);
|
||||
var n2 = utils.readU64N(buf2, 0);
|
||||
assert.equal(n1.toNumber(), n2);
|
||||
});
|
||||
});
|
||||
|
||||
signed.forEach(function(num) {
|
||||
var buf1 = new Buffer(8);
|
||||
var buf2 = new Buffer(8);
|
||||
var msg = 'should write+read a ' + num.bitLength()
|
||||
+ ' bit ' + (num.isNeg() ? 'negative' : 'positive') + ' int';
|
||||
it(msg, function() {
|
||||
utils.write64(buf1, num, 0);
|
||||
utils.write64N(buf2, num.toNumber(), 0);
|
||||
assert.deepEqual(buf1, buf2);
|
||||
var n1 = utils.read64(buf1, 0);
|
||||
var n2 = utils.read64N(buf2, 0);
|
||||
assert.equal(n1.toNumber(), n2);
|
||||
});
|
||||
var msg = 'should write+read a ' + num.bitLength()
|
||||
+ ' bit ' + (num.isNeg() ? 'negative' : 'positive') + ' int as unsigned';
|
||||
it(msg, function() {
|
||||
utils.writeU64(buf1, num, 0);
|
||||
utils.writeU64N(buf2, num.toNumber(), 0);
|
||||
assert.deepEqual(buf1, buf2);
|
||||
var n1 = utils.readU64(buf1, 0);
|
||||
if (num.isNeg()) {
|
||||
assert.throws(function() {
|
||||
utils.readU64N(buf2, 0);
|
||||
});
|
||||
} else {
|
||||
var n2 = utils.readU64N(buf2, 0);
|
||||
assert.equal(n1.toNumber(), n2);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user