scriptnum: refactor.
This commit is contained in:
parent
bf07023369
commit
5bed0455d2
@ -7,10 +7,8 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var util = require('../utils/util');
|
||||
var ScriptError = require('../btc/errors').ScriptError;
|
||||
var constants = require('../protocol/constants');
|
||||
var STACK_FALSE = new Buffer(0);
|
||||
var EMPTY_ARRAY = new Buffer(0);
|
||||
|
||||
/**
|
||||
* ScriptNum
|
||||
@ -98,7 +96,6 @@ ScriptNum.prototype.isubn = function subn(value) {
|
||||
};
|
||||
|
||||
ScriptNum.prototype.imuln = function muln(value) {
|
||||
assert(false);
|
||||
this.value *= value;
|
||||
return this;
|
||||
};
|
||||
@ -109,7 +106,6 @@ ScriptNum.prototype.idivn = function divn(value) {
|
||||
};
|
||||
|
||||
ScriptNum.prototype.iushln = function iushln(value) {
|
||||
assert(value === 1);
|
||||
this.value *= Math.pow(2, value);
|
||||
return this;
|
||||
};
|
||||
@ -142,15 +138,41 @@ ScriptNum.prototype.toNumber = function toNumber() {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
ScriptNum.prototype.toString = function toString(base) {
|
||||
var str;
|
||||
|
||||
if (!base)
|
||||
base = 10;
|
||||
|
||||
if (base === 10 || base === 'dec')
|
||||
return this.value.toString(10);
|
||||
|
||||
if (base === 16 || base === 'hex') {
|
||||
str = this.value.toString(16);
|
||||
if (str.length % 2 !== 0)
|
||||
str = '0' + str;
|
||||
return str;
|
||||
}
|
||||
|
||||
assert(false, 'Base ' + base + ' not supported.');
|
||||
};
|
||||
|
||||
ScriptNum.prototype.toJSON = function toJSON() {
|
||||
return this.toString(16);
|
||||
};
|
||||
|
||||
ScriptNum.prototype.fromString = function fromString(str, base) {
|
||||
var nonzero = 0;
|
||||
var neg = false;
|
||||
var negative = false;
|
||||
var i, ch;
|
||||
|
||||
if (!base)
|
||||
base = 10;
|
||||
|
||||
if (str[0] === '-') {
|
||||
assert(str.length > 1, 'Non-numeric string passed.');
|
||||
str = str.substring(1);
|
||||
neg = true;
|
||||
negative = true;
|
||||
} else {
|
||||
assert(str.length > 0, 'Non-numeric string passed.');
|
||||
}
|
||||
@ -176,7 +198,7 @@ ScriptNum.prototype.fromString = function fromString(str, base) {
|
||||
this.value += ch;
|
||||
}
|
||||
|
||||
if (neg)
|
||||
if (negative)
|
||||
this.value = -this.value;
|
||||
|
||||
return this;
|
||||
@ -209,7 +231,7 @@ ScriptNum.prototype.fromString = function fromString(str, base) {
|
||||
this.value += ch;
|
||||
}
|
||||
|
||||
if (neg)
|
||||
if (negative)
|
||||
this.value = -this.value;
|
||||
|
||||
return this;
|
||||
@ -222,38 +244,30 @@ ScriptNum.fromString = function fromString(str, base) {
|
||||
return new ScriptNum(0).fromString(str, base);
|
||||
};
|
||||
|
||||
ScriptNum.prototype.fromRaw = function fromRaw(value, flags, size) {
|
||||
var sign;
|
||||
ScriptNum.prototype.fromRaw = function fromRaw(data, minimal, limit) {
|
||||
if (minimal == null)
|
||||
minimal = true;
|
||||
|
||||
assert(Buffer.isBuffer(value));
|
||||
if (limit == null)
|
||||
limit = 4;
|
||||
|
||||
if (flags == null)
|
||||
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
// We can't handle more than 6 bytes.
|
||||
assert(limit <= 6, 'Number exceeds 48 bits.');
|
||||
|
||||
if (size == null)
|
||||
size = 4;
|
||||
// Max size is 4 bytes by default, 6 bytes max.
|
||||
if (data.length > limit)
|
||||
throw new ScriptError('UNKNOWN_ERROR', 'Script number overflow.');
|
||||
|
||||
assert(size <= 6, 'Number exceeds 48 bits.');
|
||||
|
||||
if (value.length === 0) {
|
||||
// Empty arrays are always zero.
|
||||
if (data.length === 0) {
|
||||
this.value = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (value.length > size)
|
||||
throw new ScriptError('UNKNOWN_ERROR', 'Script number overflow.');
|
||||
|
||||
if (flags & constants.flags.VERIFY_MINIMALDATA) {
|
||||
// If the low bits on the last byte are unset,
|
||||
// fail if the value's second to last byte does
|
||||
// not have the high bit set. A number can't
|
||||
// justify having the last byte's low bits unset
|
||||
// unless they ran out of space for the sign bit
|
||||
// in the second to last bit. We also fail on [0]
|
||||
// to avoid negative zero (also avoids positive
|
||||
// zero).
|
||||
if ((value[value.length - 1] & 0x7f) === 0) {
|
||||
if (value.length === 1 || !(value[value.length - 2] & 0x80)) {
|
||||
// Ensure minimal serialization.
|
||||
if (minimal) {
|
||||
if ((data[data.length - 1] & 0x7f) === 0) {
|
||||
if (data.length === 1 || !(data[data.length - 2] & 0x80)) {
|
||||
throw new ScriptError(
|
||||
'UNKNOWN_ERROR',
|
||||
'Non-minimally encoded Script number.');
|
||||
@ -263,89 +277,64 @@ ScriptNum.prototype.fromRaw = function fromRaw(value, flags, size) {
|
||||
|
||||
this.value = 0;
|
||||
|
||||
switch (value.length) {
|
||||
// Read number (6 bytes max).
|
||||
switch (data.length) {
|
||||
case 6:
|
||||
this.value += value[5] * 0x10000000000;
|
||||
this.value += data[5] * 0x10000000000;
|
||||
case 5:
|
||||
this.value += value[4] * 0x100000000;
|
||||
this.value += data[4] * 0x100000000;
|
||||
case 4:
|
||||
this.value += value[3] * 0x1000000;
|
||||
this.value += data[3] * 0x1000000;
|
||||
case 3:
|
||||
this.value += value[2] * 0x10000;
|
||||
this.value += data[2] * 0x10000;
|
||||
case 2:
|
||||
this.value += value[1] * 0x100;
|
||||
this.value += data[1] * 0x100;
|
||||
case 1:
|
||||
this.value += value[0];
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
this.value += data[0];
|
||||
}
|
||||
|
||||
// If the input vector's most significant byte is
|
||||
// 0x80, remove it from the result's msb and return
|
||||
// a negative.
|
||||
// Equivalent to:
|
||||
// -(result & ~(0x80 << (8 * (value.length - 1))))
|
||||
if (value[value.length - 1] & 0x80) {
|
||||
switch (value.length) {
|
||||
// Remove high bit and flip sign.
|
||||
if (data[data.length - 1] & 0x80) {
|
||||
switch (data.length) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
sign = 0x80 << (8 * (value.length - 1));
|
||||
this.value &= ~sign;
|
||||
this.value = -this.value;
|
||||
this.value &= ~(0x80 << (8 * (data.length - 1)));
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
sign = 0x80 * Math.pow(2, 8 * (value.length - 1));
|
||||
if (this.value >= sign)
|
||||
this.value -= sign;
|
||||
this.value = -this.value;
|
||||
this.value -= 0x8000000000;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
case 6:
|
||||
this.value -= 0x800000000000;
|
||||
break;
|
||||
}
|
||||
this.value = -this.value;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
ScriptNum.fromRaw = function fromRaw(value, flags, size) {
|
||||
return new ScriptNum(0).fromRaw(value, flags, size);
|
||||
ScriptNum.fromRaw = function fromRaw(data, minimal, limit) {
|
||||
return new ScriptNum(0).fromRaw(data, minimal, limit);
|
||||
};
|
||||
|
||||
ScriptNum.prototype.toRaw = function toRaw() {
|
||||
var value = this.value;
|
||||
var neg = false;
|
||||
var result, offset, size;
|
||||
var negative = false;
|
||||
var data, offset, size;
|
||||
|
||||
// Zeroes are always empty arrays.
|
||||
if (value === 0)
|
||||
return STACK_FALSE;
|
||||
|
||||
// If the most significant byte is >= 0x80
|
||||
// and the value is positive, push a new
|
||||
// zero-byte to make the significant
|
||||
// byte < 0x80 again.
|
||||
|
||||
// If the most significant byte is >= 0x80
|
||||
// and the value is negative, push a new
|
||||
// 0x80 byte that will be popped off when
|
||||
// converting to an integral.
|
||||
|
||||
// If the most significant byte is < 0x80
|
||||
// and the value is negative, add 0x80 to
|
||||
// it, since it will be subtracted and
|
||||
// interpreted as a negative when
|
||||
// converting to an integral.
|
||||
return EMPTY_ARRAY;
|
||||
|
||||
// Need to append sign bit.
|
||||
if (value < 0) {
|
||||
neg = true;
|
||||
negative = true;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// Gauge buffer size.
|
||||
if (value <= 0xff) {
|
||||
offset = (value & 0x80) ? 1 : 0;
|
||||
size = 1;
|
||||
@ -368,33 +357,31 @@ ScriptNum.prototype.toRaw = function toRaw() {
|
||||
throw new ScriptError('UNKNOWN_ERROR', 'Script number overflow.');
|
||||
}
|
||||
|
||||
result = new Buffer(size + offset);
|
||||
// Write number.
|
||||
data = new Buffer(size + offset);
|
||||
|
||||
switch (size) {
|
||||
case 6:
|
||||
result[5] = (value / 0x10000000000 | 0) & 0xff;
|
||||
data[5] = (value / 0x10000000000 | 0) & 0xff;
|
||||
case 5:
|
||||
result[4] = (value / 0x100000000 | 0) & 0xff;
|
||||
data[4] = (value / 0x100000000 | 0) & 0xff;
|
||||
case 4:
|
||||
result[3] = (value >>> 24) & 0xff;
|
||||
data[3] = (value >>> 24) & 0xff;
|
||||
case 3:
|
||||
result[2] = (value >> 16) & 0xff;
|
||||
data[2] = (value >> 16) & 0xff;
|
||||
case 2:
|
||||
result[1] = (value >> 8) & 0xff;
|
||||
data[1] = (value >> 8) & 0xff;
|
||||
case 1:
|
||||
result[0] = value & 0xff;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
data[0] = value & 0xff;
|
||||
}
|
||||
|
||||
if (result[size - 1] & 0x80)
|
||||
result[result.length - 1] = neg ? 0x80 : 0;
|
||||
else if (neg)
|
||||
result[size - 1] |= 0x80;
|
||||
// Append sign bit.
|
||||
if (data[size - 1] & 0x80)
|
||||
data[size] = negative ? 0x80 : 0;
|
||||
else if (negative)
|
||||
data[size - 1] |= 0x80;
|
||||
|
||||
return result;
|
||||
return data;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Loading…
Reference in New Issue
Block a user