encoding: refactor int64 handling.
This commit is contained in:
parent
79d1bbd823
commit
b81643473e
@ -2105,9 +2105,9 @@ ChainState.fromRaw = function fromRaw(data) {
|
||||
const state = new ChainState();
|
||||
const br = new BufferReader(data);
|
||||
state.tip = br.readHash();
|
||||
state.tx = br.readU53();
|
||||
state.coin = br.readU53();
|
||||
state.value = br.readU53();
|
||||
state.tx = br.readU64();
|
||||
state.coin = br.readU64();
|
||||
state.value = br.readU64();
|
||||
return state;
|
||||
};
|
||||
|
||||
|
||||
@ -291,7 +291,7 @@ VersionPacket.prototype.fromReader = function fromReader(br) {
|
||||
// are currently unused.
|
||||
br.readU32();
|
||||
|
||||
this.time = br.readI53();
|
||||
this.time = br.readI64();
|
||||
this.remote.fromReader(br, false);
|
||||
|
||||
if (br.left() > 0) {
|
||||
@ -2209,7 +2209,7 @@ SendCmpctPacket.prototype.toRaw = function toRaw() {
|
||||
|
||||
SendCmpctPacket.prototype.fromReader = function fromReader(br) {
|
||||
this.mode = br.readU8();
|
||||
this.version = br.readU53();
|
||||
this.version = br.readU64();
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
@ -166,36 +166,6 @@ encoding.ZERO_U32 = Buffer.from('00000000', 'hex');
|
||||
|
||||
encoding.ZERO_U64 = Buffer.from('0000000000000000', 'hex');
|
||||
|
||||
/**
|
||||
* Read uint64 as a js number.
|
||||
* @private
|
||||
* @param {Buffer} data
|
||||
* @param {Number} off
|
||||
* @param {Boolean} force53 - Read only 53 bits, but maintain the sign.
|
||||
* @param {Boolean} be
|
||||
* @returns {Number}
|
||||
* @throws on num > MAX_SAFE_INTEGER
|
||||
*/
|
||||
|
||||
encoding._readU64 = function _readU64(data, off, force53, be) {
|
||||
let hi, lo;
|
||||
|
||||
if (be) {
|
||||
hi = data.readUInt32BE(off, true);
|
||||
lo = data.readUInt32BE(off + 4, true);
|
||||
} else {
|
||||
hi = data.readUInt32LE(off + 4, true);
|
||||
lo = data.readUInt32LE(off, true);
|
||||
}
|
||||
|
||||
if (force53)
|
||||
hi &= 0x1fffff;
|
||||
|
||||
enforce((hi & 0xffe00000) === 0, off, 'Number exceeds 2^53-1');
|
||||
|
||||
return (hi * 0x100000000) + lo;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read uint64le as a js number.
|
||||
* @param {Buffer} data
|
||||
@ -205,7 +175,10 @@ encoding._readU64 = function _readU64(data, off, force53, be) {
|
||||
*/
|
||||
|
||||
encoding.readU64 = function readU64(data, off) {
|
||||
return encoding._readU64(data, off, false, false);
|
||||
const hi = data.readUInt32LE(off + 4, true);
|
||||
const lo = data.readUInt32LE(off, true);
|
||||
enforce((hi & 0xffe00000) === 0, off, 'Number exceeds 2^53-1');
|
||||
return hi * 0x100000000 + lo;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -217,72 +190,9 @@ encoding.readU64 = function readU64(data, off) {
|
||||
*/
|
||||
|
||||
encoding.readU64BE = function readU64BE(data, off) {
|
||||
return encoding._readU64(data, off, false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read uint64le as a js number (limit at 53 bits).
|
||||
* @param {Buffer} data
|
||||
* @param {Number} off
|
||||
* @returns {Number}
|
||||
* @throws on num > MAX_SAFE_INTEGER
|
||||
*/
|
||||
|
||||
encoding.readU53 = function readU53(data, off) {
|
||||
return encoding._readU64(data, off, true, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read uint64be as a js number (limit at 53 bits).
|
||||
* @param {Buffer} data
|
||||
* @param {Number} off
|
||||
* @returns {Number}
|
||||
* @throws on num > MAX_SAFE_INTEGER
|
||||
*/
|
||||
|
||||
encoding.readU53BE = function readU53BE(data, off) {
|
||||
return encoding._readU64(data, off, true, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read int64 as a js number.
|
||||
* @private
|
||||
* @param {Buffer} data
|
||||
* @param {Number} off
|
||||
* @param {Boolean} force53 - Read only 53 bits, but maintain the sign.
|
||||
* @param {Boolean} be
|
||||
* @returns {Number}
|
||||
* @throws on num > MAX_SAFE_INTEGER
|
||||
*/
|
||||
|
||||
encoding._readI64 = function _readI64(data, off, force53, be) {
|
||||
let hi, lo;
|
||||
|
||||
if (be) {
|
||||
hi = data.readUInt32BE(off, true);
|
||||
lo = data.readUInt32BE(off + 4, true);
|
||||
} else {
|
||||
hi = data.readUInt32LE(off + 4, true);
|
||||
lo = data.readUInt32LE(off, true);
|
||||
}
|
||||
|
||||
if (hi & 0x80000000) {
|
||||
hi = ~hi >>> 0;
|
||||
lo = ~lo >>> 0;
|
||||
|
||||
if (force53)
|
||||
hi &= 0x1fffff;
|
||||
|
||||
enforce((hi & 0xffe00000) === 0, off, 'Number exceeds 2^53-1');
|
||||
|
||||
return -(hi * 0x100000000 + lo + 1);
|
||||
}
|
||||
|
||||
if (force53)
|
||||
hi &= 0x1fffff;
|
||||
|
||||
const hi = data.readUInt32BE(off, true);
|
||||
const lo = data.readUInt32BE(off + 4, true);
|
||||
enforce((hi & 0xffe00000) === 0, off, 'Number exceeds 2^53-1');
|
||||
|
||||
return hi * 0x100000000 + lo;
|
||||
};
|
||||
|
||||
@ -295,7 +205,10 @@ encoding._readI64 = function _readI64(data, off, force53, be) {
|
||||
*/
|
||||
|
||||
encoding.readI64 = function readI64(data, off) {
|
||||
return encoding._readI64(data, off, false, false);
|
||||
const hi = data.readInt32LE(off + 4, true);
|
||||
const lo = data.readUInt32LE(off, true);
|
||||
enforce(isSafe(hi, lo), 'Number exceeds 2^53-1');
|
||||
return hi * 0x100000000 + lo;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -307,85 +220,10 @@ encoding.readI64 = function readI64(data, off) {
|
||||
*/
|
||||
|
||||
encoding.readI64BE = function readI64BE(data, off) {
|
||||
return encoding._readI64(data, off, false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read int64be as a js number (limit at 53 bits).
|
||||
* @param {Buffer} data
|
||||
* @param {Number} off
|
||||
* @returns {Number}
|
||||
* @throws on num > MAX_SAFE_INTEGER
|
||||
*/
|
||||
|
||||
encoding.readI53 = function readI53(data, off) {
|
||||
return encoding._readI64(data, off, true, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read int64be as a js number (limit at 53 bits).
|
||||
* @param {Buffer} data
|
||||
* @param {Number} off
|
||||
* @returns {Number}
|
||||
* @throws on num > MAX_SAFE_INTEGER
|
||||
*/
|
||||
|
||||
encoding.readI53BE = function readI53BE(data, off) {
|
||||
return encoding._readI64(data, off, true, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Write a javascript number as an int64.
|
||||
* @private
|
||||
* @param {Buffer} dst
|
||||
* @param {Number} num
|
||||
* @param {Number} off
|
||||
* @param {Boolean} be
|
||||
* @returns {Number} Buffer offset.
|
||||
* @throws on num > MAX_SAFE_INTEGER
|
||||
*/
|
||||
|
||||
encoding._writeI64 = function _writeI64(dst, num, off, be) {
|
||||
const neg = num < 0;
|
||||
|
||||
if (neg) {
|
||||
num = -num;
|
||||
num -= 1;
|
||||
}
|
||||
|
||||
enforce(num <= MAX_SAFE_INTEGER, off, 'Number exceeds 2^53-1');
|
||||
|
||||
let hi = (num * (1 / 0x100000000)) | 0;
|
||||
let lo = num | 0;
|
||||
|
||||
if (neg) {
|
||||
hi = ~hi;
|
||||
lo = ~lo;
|
||||
}
|
||||
|
||||
if (be) {
|
||||
dst[off++] = hi >>> 24;
|
||||
dst[off++] = (hi >> 16) & 0xff;
|
||||
dst[off++] = (hi >> 8) & 0xff;
|
||||
dst[off++] = hi & 0xff;
|
||||
|
||||
dst[off++] = lo >>> 24;
|
||||
dst[off++] = (lo >> 16) & 0xff;
|
||||
dst[off++] = (lo >> 8) & 0xff;
|
||||
dst[off++] = lo & 0xff;
|
||||
} else {
|
||||
dst[off++] = lo & 0xff;
|
||||
dst[off++] = (lo >> 8) & 0xff;
|
||||
dst[off++] = (lo >> 16) & 0xff;
|
||||
dst[off++] = lo >>> 24;
|
||||
|
||||
dst[off++] = hi & 0xff;
|
||||
dst[off++] = (hi >> 8) & 0xff;
|
||||
dst[off++] = (hi >> 16) & 0xff;
|
||||
dst[off++] = hi >>> 24;
|
||||
}
|
||||
|
||||
return off;
|
||||
const hi = data.readInt32BE(off, true);
|
||||
const lo = data.readUInt32BE(off + 4, true);
|
||||
enforce(isSafe(hi, lo), 'Number exceeds 2^53-1');
|
||||
return hi * 0x100000000 + lo;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -398,7 +236,7 @@ encoding._writeI64 = function _writeI64(dst, num, off, be) {
|
||||
*/
|
||||
|
||||
encoding.writeU64 = function writeU64(dst, num, off) {
|
||||
return encoding._writeI64(dst, num, off, false);
|
||||
return write64(dst, num, off, false);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -411,7 +249,7 @@ encoding.writeU64 = function writeU64(dst, num, off) {
|
||||
*/
|
||||
|
||||
encoding.writeU64BE = function writeU64BE(dst, num, off) {
|
||||
return encoding._writeI64(dst, num, off, true);
|
||||
return write64(dst, num, off, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -424,7 +262,7 @@ encoding.writeU64BE = function writeU64BE(dst, num, off) {
|
||||
*/
|
||||
|
||||
encoding.writeI64 = function writeI64(dst, num, off) {
|
||||
return encoding._writeI64(dst, num, off, false);
|
||||
return write64(dst, num, off, false);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -437,7 +275,7 @@ encoding.writeI64 = function writeI64(dst, num, off) {
|
||||
*/
|
||||
|
||||
encoding.writeI64BE = function writeI64BE(dst, num, off) {
|
||||
return encoding._writeI64(dst, num, off, true);
|
||||
return write64(dst, num, off, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -610,28 +448,6 @@ encoding.writeVarint = function writeVarint(dst, num, off) {
|
||||
return off;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a varint size.
|
||||
* @param {Buffer} data
|
||||
* @param {Number} off
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
encoding.skipVarint = function skipVarint(data, off) {
|
||||
assert(off < data.length, off);
|
||||
|
||||
switch (data[off]) {
|
||||
case 0xff:
|
||||
return 9;
|
||||
case 0xfe:
|
||||
return 5;
|
||||
case 0xfd:
|
||||
return 3;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate size of varint.
|
||||
* @param {Number} num
|
||||
@ -772,27 +588,6 @@ encoding.writeVarint2 = function writeVarint2(dst, num, off) {
|
||||
return off;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a varint size.
|
||||
* @param {Buffer} data
|
||||
* @param {Number} off
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
encoding.skipVarint2 = function skipVarint2(data, off) {
|
||||
let size = 0;
|
||||
|
||||
for (;;) {
|
||||
assert(off < data.length, off);
|
||||
const ch = data[off++];
|
||||
size++;
|
||||
if ((ch & 0x80) === 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate size of varint (type 2).
|
||||
* @param {Number} num
|
||||
@ -986,9 +781,9 @@ encoding.sizeVarString = function sizeVarString(str, enc) {
|
||||
* @param {String} reason
|
||||
*/
|
||||
|
||||
encoding.EncodingError = function EncodingError(offset, reason) {
|
||||
encoding.EncodingError = function EncodingError(offset, reason, start) {
|
||||
if (!(this instanceof EncodingError))
|
||||
return new EncodingError(offset, reason);
|
||||
return new EncodingError(offset, reason, start);
|
||||
|
||||
Error.call(this);
|
||||
|
||||
@ -996,7 +791,7 @@ encoding.EncodingError = function EncodingError(offset, reason) {
|
||||
this.message = `${reason} (offset=${offset}).`;
|
||||
|
||||
if (Error.captureStackTrace)
|
||||
Error.captureStackTrace(this, EncodingError);
|
||||
Error.captureStackTrace(this, start || EncodingError);
|
||||
};
|
||||
|
||||
Object.setPrototypeOf(encoding.EncodingError.prototype, Error.prototype);
|
||||
@ -1005,17 +800,58 @@ Object.setPrototypeOf(encoding.EncodingError.prototype, Error.prototype);
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
function isSafe(hi, lo) {
|
||||
if (hi < 0) {
|
||||
hi = ~hi;
|
||||
if (lo === 0)
|
||||
hi += 1;
|
||||
}
|
||||
|
||||
return (hi & 0xffe00000) === 0;
|
||||
}
|
||||
|
||||
function write64(dst, num, off, be) {
|
||||
let neg = false;
|
||||
|
||||
if (num < 0) {
|
||||
num = -num;
|
||||
neg = true;
|
||||
}
|
||||
|
||||
let hi = (num * (1 / 0x100000000)) | 0;
|
||||
let lo = num | 0;
|
||||
|
||||
if (neg) {
|
||||
if (lo === 0) {
|
||||
hi = (~hi + 1) | 0;
|
||||
} else {
|
||||
hi = ~hi;
|
||||
lo = ~lo + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (be) {
|
||||
off = dst.writeInt32BE(hi, off, true);
|
||||
off = dst.writeInt32BE(lo, off, true);
|
||||
} else {
|
||||
off = dst.writeInt32LE(lo, off, true);
|
||||
off = dst.writeInt32LE(hi, off, true);
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
function Varint(size, value) {
|
||||
this.size = size;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
function enforce(value, offset, reason) {
|
||||
if (!value)
|
||||
throw new encoding.EncodingError(offset, reason);
|
||||
}
|
||||
|
||||
function assert(value, offset) {
|
||||
if (!value)
|
||||
throw new encoding.EncodingError(offset, 'Out of bounds read');
|
||||
throw new encoding.EncodingError(offset, 'Out of bounds read', assert);
|
||||
}
|
||||
|
||||
function enforce(value, offset, reason) {
|
||||
if (!value)
|
||||
throw new encoding.EncodingError(offset, reason, enforce);
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ function BufferReader(data, zeroCopy) {
|
||||
|
||||
BufferReader.prototype.assert = function assert(value) {
|
||||
if (!value)
|
||||
throw new encoding.EncodingError(this.offset, 'Out of bounds read');
|
||||
throw new encoding.EncodingError(this.offset, 'Out of bounds read', assert);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -53,7 +53,7 @@ BufferReader.prototype.assert = function assert(value) {
|
||||
|
||||
BufferReader.prototype.enforce = function enforce(value, reason) {
|
||||
if (!value)
|
||||
throw new encoding.EncodingError(this.offset, reason);
|
||||
throw new encoding.EncodingError(this.offset, reason, enforce);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -237,32 +237,6 @@ BufferReader.prototype.readU64BE = function readU64BE() {
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read first least significant 53 bits of
|
||||
* a uint64le as a js number. Maintain the sign.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
BufferReader.prototype.readU53 = function readU53() {
|
||||
this.assert(this.offset + 8 <= this.data.length);
|
||||
const ret = encoding.readU53(this.data, this.offset);
|
||||
this.offset += 8;
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read first least significant 53 bits of
|
||||
* a uint64be as a js number. Maintain the sign.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
BufferReader.prototype.readU53BE = function readU53BE() {
|
||||
this.assert(this.offset + 8 <= this.data.length);
|
||||
const ret = encoding.readU53BE(this.data, this.offset);
|
||||
this.offset += 8;
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read int8.
|
||||
* @returns {Number}
|
||||
@ -349,32 +323,6 @@ BufferReader.prototype.readI64BE = function readI64BE() {
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read first least significant 53 bits of
|
||||
* a int64le as a js number. Maintain the sign.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
BufferReader.prototype.readI53 = function readI53() {
|
||||
this.assert(this.offset + 8 <= this.data.length);
|
||||
const ret = encoding.readI53(this.data, this.offset);
|
||||
this.offset += 8;
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read first least significant 53 bits of
|
||||
* a int64be as a js number. Maintain the sign.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
BufferReader.prototype.readI53BE = function readI53BE() {
|
||||
this.assert(this.offset + 8 <= this.data.length);
|
||||
const ret = encoding.readI53BE(this.data, this.offset);
|
||||
this.offset += 8;
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read uint64le.
|
||||
* @returns {U64}
|
||||
@ -482,18 +430,6 @@ BufferReader.prototype.readVarint = function readVarint() {
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Skip past a varint.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
BufferReader.prototype.skipVarint = function skipVarint() {
|
||||
const size = encoding.skipVarint(this.data, this.offset);
|
||||
this.assert(this.offset + size <= this.data.length);
|
||||
this.offset += size;
|
||||
return size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a varint.
|
||||
* @returns {U64}
|
||||
@ -516,17 +452,6 @@ BufferReader.prototype.readVarint2 = function readVarint2() {
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Skip past a varint (type 2).
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
BufferReader.prototype.skipVarint2 = function skipVarint2() {
|
||||
const size = encoding.skipVarint2(this.data, this.offset);
|
||||
this.assert(this.offset + size <= this.data.length);
|
||||
this.offset += size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a varint (type 2).
|
||||
* @returns {U64}
|
||||
|
||||
@ -594,7 +594,7 @@ MasterKey.prototype.fromRaw = function fromRaw(raw) {
|
||||
}
|
||||
|
||||
// NOTE: useless varint
|
||||
br.skipVarint();
|
||||
br.readVarint();
|
||||
|
||||
this.key = HD.PrivateKey.fromRaw(br.readBytes(82));
|
||||
|
||||
|
||||
@ -2669,10 +2669,10 @@ TXDBState.prototype.toRaw = function toRaw() {
|
||||
|
||||
TXDBState.prototype.fromRaw = function fromRaw(data) {
|
||||
const br = new BufferReader(data);
|
||||
this.tx = br.readU53();
|
||||
this.coin = br.readU53();
|
||||
this.unconfirmed = br.readU53();
|
||||
this.confirmed = br.readU53();
|
||||
this.tx = br.readU64();
|
||||
this.coin = br.readU64();
|
||||
this.unconfirmed = br.readU64();
|
||||
this.confirmed = br.readU64();
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
@ -600,7 +600,7 @@ function skipCoin(br) {
|
||||
}
|
||||
|
||||
// Skip past the value.
|
||||
br.skipVarint();
|
||||
br.readVarint();
|
||||
|
||||
return br.offset - start;
|
||||
}
|
||||
|
||||
@ -218,7 +218,7 @@ function skipOutput(br) {
|
||||
const start = br.offset;
|
||||
|
||||
// Skip past the value.
|
||||
br.skipVarint();
|
||||
br.readVarint();
|
||||
|
||||
// Skip past the compressed scripts.
|
||||
switch (br.readU8()) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user