Merge pull request #169 from maraoz/feature/add-bitcoin-core-tests
add bitcoin core ScriptInterpreter valid/invalid script tests
This commit is contained in:
commit
c6dcbc256b
24
Script.js
24
Script.js
|
@ -35,7 +35,7 @@ function Script(buffer) {
|
|||
}
|
||||
this.chunks = [];
|
||||
this.parse();
|
||||
};
|
||||
}
|
||||
this.class = Script;
|
||||
|
||||
Script.TX_UNKNOWN = TX_UNKNOWN;
|
||||
|
@ -51,19 +51,25 @@ Script.prototype.parse = function() {
|
|||
while (!parser.eof()) {
|
||||
var opcode = parser.word8();
|
||||
|
||||
var len;
|
||||
var len, chunk;
|
||||
if (opcode > 0 && opcode < OP_PUSHDATA1) {
|
||||
// Read some bytes of data, opcode value is the length of data
|
||||
this.chunks.push(parser.buffer(opcode));
|
||||
} else if (opcode == OP_PUSHDATA1) {
|
||||
} else if (opcode === OP_PUSHDATA1) {
|
||||
len = parser.word8();
|
||||
this.chunks.push(parser.buffer(len));
|
||||
} else if (opcode == OP_PUSHDATA2) {
|
||||
chunk = parser.buffer(len);
|
||||
if (chunk.length < len) throw new Error('Invalid data size: not enough data');
|
||||
this.chunks.push(chunk);
|
||||
} else if (opcode === OP_PUSHDATA2) {
|
||||
len = parser.word16le();
|
||||
this.chunks.push(parser.buffer(len));
|
||||
} else if (opcode == OP_PUSHDATA4) {
|
||||
chunk = parser.buffer(len);
|
||||
if (chunk.length < len) throw new Error('Invalid data size: not enough data');
|
||||
this.chunks.push(chunk);
|
||||
} else if (opcode === OP_PUSHDATA4) {
|
||||
len = parser.word32le();
|
||||
this.chunks.push(parser.buffer(len));
|
||||
chunk = parser.buffer(len);
|
||||
if (chunk.length < len) throw new Error('Invalid data size: not enough data');
|
||||
this.chunks.push(chunk);
|
||||
} else {
|
||||
this.chunks.push(opcode);
|
||||
}
|
||||
|
@ -509,7 +515,7 @@ Script.stringToBuffer = function(s) {
|
|||
if (!isNaN(integer)) {
|
||||
// integer
|
||||
//console.log('integer');
|
||||
var data = util.intToBuffer(integer);
|
||||
var data = util.intToBufferSM(integer);
|
||||
buf.put(Script.chunksToBuffer([data]));
|
||||
} else if (word[0] === '\'' && word[word.length-1] === '\'') {
|
||||
// string
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var imports = require('soop').imports();
|
||||
var config = imports.config || require('./config');
|
||||
var log = imports.log || require('./util/log');
|
||||
var util = imports.util || require('./util/util');
|
||||
var Opcode = imports.Opcode || require('./Opcode');
|
||||
var buffertools = imports.buffertools || require('buffertools');
|
||||
var bignum = imports.bignum || require('bignum');
|
||||
|
@ -17,6 +18,9 @@ for (var i in Opcode.map) {
|
|||
eval(i + " = " + Opcode.map[i] + ";");
|
||||
}
|
||||
|
||||
var intToBufferSM = Util.intToBufferSM
|
||||
var bufferSMToInt = Util.bufferSMToInt;
|
||||
|
||||
function ScriptInterpreter() {
|
||||
this.stack = [];
|
||||
this.disableUnsafeOpcodes = true;
|
||||
|
@ -92,8 +96,9 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
throw new Error("Encountered a disabled opcode");
|
||||
}
|
||||
|
||||
if (exec && Buffer.isBuffer(opcode))
|
||||
if (exec && Buffer.isBuffer(opcode)) {
|
||||
this.stack.push(opcode);
|
||||
}
|
||||
else if (exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
|
||||
switch (opcode) {
|
||||
case OP_0:
|
||||
|
@ -117,7 +122,9 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
case OP_14:
|
||||
case OP_15:
|
||||
case OP_16:
|
||||
this.stack.push(bigintToBuffer(opcode - OP_1 + 1));
|
||||
var opint = opcode - OP_1 + 1;
|
||||
var opbuf = intToBufferSM(opint);
|
||||
this.stack.push(opbuf);
|
||||
break;
|
||||
|
||||
case OP_NOP:
|
||||
|
@ -241,7 +248,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
case OP_DEPTH:
|
||||
// -- stacksize
|
||||
var value = bignum(this.stack.length);
|
||||
this.stack.push(bigintToBuffer(value));
|
||||
this.stack.push(intToBufferSM(value));
|
||||
break;
|
||||
|
||||
case OP_DROP:
|
||||
|
@ -350,7 +357,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
case OP_SIZE:
|
||||
// (in -- in size)
|
||||
var value = bignum(this.stackTop().length);
|
||||
this.stack.push(bigintToBuffer(value));
|
||||
this.stack.push(intToBufferSM(value));
|
||||
break;
|
||||
|
||||
case OP_INVERT:
|
||||
|
@ -392,6 +399,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
// (x1 x2 - bool)
|
||||
var v1 = this.stackTop(2);
|
||||
var v2 = this.stackTop(1);
|
||||
|
||||
var value = buffertools.compare(v1, v2) === 0;
|
||||
|
||||
// OP_NOTEQUAL is disabled because it would be too easy to say
|
||||
|
@ -421,7 +429,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
case OP_NOT:
|
||||
case OP_0NOTEQUAL:
|
||||
// (in -- out)
|
||||
var num = castBigint(this.stackTop());
|
||||
var num = bufferSMToInt(this.stackTop());
|
||||
switch (opcode) {
|
||||
case OP_1ADD:
|
||||
num = num.add(bignum(1));
|
||||
|
@ -448,7 +456,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
num = bignum(num.cmp(0) == 0 ? 0 : 1);
|
||||
break;
|
||||
}
|
||||
this.stack[this.stack.length - 1] = bigintToBuffer(num);
|
||||
this.stack[this.stack.length - 1] = intToBufferSM(num);
|
||||
break;
|
||||
|
||||
case OP_ADD:
|
||||
|
@ -470,8 +478,8 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
case OP_MIN:
|
||||
case OP_MAX:
|
||||
// (x1 x2 -- out)
|
||||
var v1 = castBigint(this.stackTop(2));
|
||||
var v2 = castBigint(this.stackTop(1));
|
||||
var v1 = bufferSMToInt(this.stackTop(2));
|
||||
var v2 = bufferSMToInt(this.stackTop(1));
|
||||
var num;
|
||||
switch (opcode) {
|
||||
case OP_ADD:
|
||||
|
@ -547,7 +555,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
}
|
||||
this.stackPop();
|
||||
this.stackPop();
|
||||
this.stack.push(bigintToBuffer(num));
|
||||
this.stack.push(intToBufferSM(num));
|
||||
|
||||
if (opcode === OP_NUMEQUALVERIFY) {
|
||||
if (castBool(this.stackTop())) {
|
||||
|
@ -560,14 +568,14 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
|
||||
case OP_WITHIN:
|
||||
// (x min max -- out)
|
||||
var v1 = castBigint(this.stackTop(3));
|
||||
var v2 = castBigint(this.stackTop(2));
|
||||
var v3 = castBigint(this.stackTop(1));
|
||||
var v1 = bufferSMToInt(this.stackTop(3));
|
||||
var v2 = bufferSMToInt(this.stackTop(2));
|
||||
var v3 = bufferSMToInt(this.stackTop(1));
|
||||
this.stackPop();
|
||||
this.stackPop();
|
||||
this.stackPop();
|
||||
var value = v1.cmp(v2) >= 0 && v1.cmp(v3) < 0;
|
||||
this.stack.push(bigintToBuffer(value ? 1 : 0));
|
||||
this.stack.push(intToBufferSM(value ? 1 : 0));
|
||||
break;
|
||||
|
||||
case OP_RIPEMD160:
|
||||
|
@ -747,7 +755,6 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
|
|||
return;
|
||||
|
||||
default:
|
||||
console.log('opcode '+opcode);
|
||||
throw new Error("Unknown opcode encountered");
|
||||
}
|
||||
|
||||
|
@ -804,7 +811,7 @@ ScriptInterpreter.prototype.stackTop = function stackTop(offset) {
|
|||
};
|
||||
|
||||
ScriptInterpreter.prototype.stackBack = function stackBack() {
|
||||
return this.stack[-1];
|
||||
return this.stack[this.stack.length -1];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -842,7 +849,7 @@ ScriptInterpreter.prototype.getPrimitiveStack = function getPrimitiveStack() {
|
|||
if (entry.length > 2) {
|
||||
return buffertools.toHex(entry.slice(0));
|
||||
}
|
||||
var num = castBigint(entry);
|
||||
var num = bufferSMToInt(entry);
|
||||
if (num.cmp(-128) >= 0 && num.cmp(127) <= 0) {
|
||||
return num.toNumber();
|
||||
} else {
|
||||
|
@ -864,61 +871,7 @@ var castBool = ScriptInterpreter.castBool = function castBool(v) {
|
|||
return false;
|
||||
};
|
||||
var castInt = ScriptInterpreter.castInt = function castInt(v) {
|
||||
return castBigint(v).toNumber();
|
||||
};
|
||||
var castBigint = ScriptInterpreter.castBigint = function castBigint(v) {
|
||||
if (!v.length) {
|
||||
return bignum(0);
|
||||
}
|
||||
|
||||
// Arithmetic operands must be in range [-2^31...2^31]
|
||||
if (v.length > 4) {
|
||||
throw new Error("Bigint cast overflow (> 4 bytes)");
|
||||
}
|
||||
|
||||
var w = new Buffer(v.length);
|
||||
v.copy(w);
|
||||
w = buffertools.reverse(w);
|
||||
if (w[0] & 0x80) {
|
||||
w[0] &= 0x7f;
|
||||
return bignum.fromBuffer(w).neg();
|
||||
} else {
|
||||
// Positive number
|
||||
return bignum.fromBuffer(w);
|
||||
}
|
||||
};
|
||||
var bigintToBuffer = ScriptInterpreter.bigintToBuffer = function bigintToBuffer(v) {
|
||||
if ("number" === typeof v) {
|
||||
v = bignum(v);
|
||||
}
|
||||
|
||||
var b, c;
|
||||
|
||||
var cmp = v.cmp(0);
|
||||
if (cmp > 0) {
|
||||
b = v.toBuffer();
|
||||
if (b[0] & 0x80) {
|
||||
c = new Buffer(b.length + 1);
|
||||
b.copy(c, 1);
|
||||
c[0] = 0;
|
||||
return buffertools.reverse(c);
|
||||
} else {
|
||||
return buffertools.reverse(b);
|
||||
}
|
||||
} else if (cmp == 0) {
|
||||
return new Buffer([]);
|
||||
} else {
|
||||
b = v.neg().toBuffer();
|
||||
if (b[0] & 0x80) {
|
||||
c = new Buffer(b.length + 1);
|
||||
b.copy(c, 1);
|
||||
c[0] = 0x80;
|
||||
return buffertools.reverse(c);
|
||||
} else {
|
||||
b[0] |= 0x80;
|
||||
return buffertools.reverse(b);
|
||||
}
|
||||
}
|
||||
return bufferSMToInt(v).toNumber();
|
||||
};
|
||||
|
||||
ScriptInterpreter.prototype.getResult = function getResult() {
|
||||
|
@ -991,7 +944,8 @@ function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
|
|||
return;
|
||||
}
|
||||
|
||||
assert.notEqual(siCopy.length, 0);
|
||||
if (siCopy.length === 0)
|
||||
throw new Error('siCopy should have length != 0');
|
||||
|
||||
var subscript = new Script(siCopy.stackPop());
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
"browser-pack": "~2.0.1",
|
||||
"commander": "~2.1.0",
|
||||
"browserify-bignum": "git://github.com/maraoz/browserify-bignum.git",
|
||||
"browserify-buffertools": "~1.0.2",
|
||||
"browserify-buffertools": "git://github.com/maraoz/browserify-buffertools.git",
|
||||
"brfs": "~1.0.0",
|
||||
"uglifyify": "~1.2.3"
|
||||
},
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
var chai = chai || require('chai');
|
||||
var bitcore = bitcore || require('../bitcore');
|
||||
var buffertools = require('buffertools');
|
||||
|
||||
var should = chai.should();
|
||||
var testdata = testdata || require('./testdata');
|
||||
|
@ -22,28 +23,49 @@ describe('ScriptInterpreter', function() {
|
|||
var si = new ScriptInterpreter();
|
||||
should.exist(si);
|
||||
});
|
||||
var testScripts = function(data, valid) {
|
||||
var i = 0;
|
||||
testdata.dataScriptValid.forEach(function(datum) {
|
||||
data.forEach(function(datum) {
|
||||
if (datum.length < 2) throw new Error('Invalid test data');
|
||||
var scriptSig = datum[0]; // script inputs
|
||||
var scriptPubKey = datum[1]; // output script
|
||||
var human = scriptSig + ' ' + scriptPubKey;
|
||||
it.skip('should validate script ' + human, function(done) {
|
||||
i++;
|
||||
console.log(i + ' ' + human);
|
||||
ScriptInterpreter.verify(Script.fromHumanReadable(scriptSig),
|
||||
Script.fromHumanReadable(scriptPubKey),
|
||||
null, 0, 0, // tx, output index, and hashtype
|
||||
it('should ' + (!valid ? 'not ' : '') + 'validate script ' + human, function(done) {
|
||||
try {
|
||||
ScriptInterpreter.verifyFull(
|
||||
Script.fromHumanReadable(scriptSig), // scriptSig
|
||||
Script.fromHumanReadable(scriptPubKey), // scriptPubKey
|
||||
null, 0, 0, // tx, output index, hashtype
|
||||
{ verifyP2SH: !valid}, // only verify P2SH for invalid data set
|
||||
function(err, result) {
|
||||
if (valid) {
|
||||
should.not.exist(err);
|
||||
result.should.equal(true);
|
||||
} else {
|
||||
var failed = (typeof err !== 'undefined') || (result === false);
|
||||
failed.should.equal(true);
|
||||
}
|
||||
if (typeof result !== 'undefined') {
|
||||
result.should.equal(valid);
|
||||
}
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
if (valid) {
|
||||
console.log(e);
|
||||
}
|
||||
valid.should.equal(false);
|
||||
done();
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
testScripts(testdata.dataScriptValid, true);
|
||||
testScripts(testdata.dataScriptInvalid, false);
|
||||
|
||||
|
||||
|
||||
var i = 0;
|
||||
testdata.dataSigCanonical.forEach(function(datum) {
|
||||
it('should validate valid canonical signatures', function() {
|
||||
ScriptInterpreter.isCanonicalSignature(new Buffer(datum, 'hex')).should.equal(true);
|
||||
|
@ -51,7 +73,6 @@ describe('ScriptInterpreter', function() {
|
|||
});
|
||||
testdata.dataSigNonCanonical.forEach(function(datum) {
|
||||
it('should NOT validate invalid canonical signatures', function() {
|
||||
|
||||
var sig;
|
||||
var isHex;
|
||||
//is Hex?
|
||||
|
@ -61,14 +82,10 @@ describe('ScriptInterpreter', function() {
|
|||
} catch (e) {}
|
||||
|
||||
if (isHex)
|
||||
ScriptInterpreter.isCanonicalSignature.bind(sig).should.throw();
|
||||
ScriptInterpreter.isCanonicalSignature.bind(sig).should.
|
||||
throw ();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -80,22 +80,35 @@ describe('util', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('#intToBuffer', function() {
|
||||
describe('#intToBuffer2C', function() {
|
||||
var data = [
|
||||
[0, '00'],
|
||||
[-0, '00'],
|
||||
[-1, 'ff'],
|
||||
[0, ''],
|
||||
[-0, ''],
|
||||
[1, '01'],
|
||||
[-1, 'ff'],
|
||||
[18, '12'],
|
||||
[-18, 'ee'],
|
||||
[127, '7f'],
|
||||
[128, '8000'],
|
||||
[129, '8100'],
|
||||
[4096, '0010'],
|
||||
[-4096, '00f0'],
|
||||
[32767, 'ff7f'],
|
||||
[878082192, '90785634'],
|
||||
[0x01234567890, '1200000090785634'],
|
||||
[-4294967297, 'feffffffffffffff'],
|
||||
[0x01234567890, '9078563412'],
|
||||
[4294967295, 'ffffffff00'],
|
||||
[4294967296, '0000000001'],
|
||||
[4294967297, '0100000001'],
|
||||
[2147483647, 'ffffff7f'],
|
||||
[-2147483647, '01000080'],
|
||||
];
|
||||
data.forEach(function(datum) {
|
||||
var integer = datum[0];
|
||||
var result = datum[1];
|
||||
it('should work for ' + integer, function() {
|
||||
buffertools.toHex(coinUtil.intToBuffer(integer)).should.equal(result);
|
||||
var buf = coinUtil.intToBuffer2C(integer);
|
||||
var hex = buffertools.toHex(buf);
|
||||
hex.should.equal(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -147,4 +160,22 @@ describe('util', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('#intToBufferSM', function() {
|
||||
var data = [
|
||||
[0, ''],
|
||||
[1, '01'],
|
||||
[-1, '81'],
|
||||
[2, '02'],
|
||||
[-2, '82'],
|
||||
[-32768, '008080'],
|
||||
];
|
||||
data.forEach(function(datum) {
|
||||
var i = datum[0];
|
||||
var hex = datum[1];
|
||||
it('should work for ' + i, function() {
|
||||
var result = coinUtil.intToBufferSM(i);
|
||||
buffertools.toHex(result).should.equal(hex);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
139
util/util.js
139
util/util.js
|
@ -112,39 +112,128 @@ var bigIntToValue = exports.bigIntToValue = function (valueBigInt) {
|
|||
}
|
||||
};
|
||||
|
||||
var intTo64Bits = function(integer) {
|
||||
return {
|
||||
hi: Math.floor(integer / 4294967296),
|
||||
lo: (integer & 0xFFFFFFFF) >>> 0
|
||||
};
|
||||
};
|
||||
var fitsInNBits = function(integer, n) {
|
||||
// TODO: make this efficient!!!
|
||||
return integer.toString(2).replace('-','').length < n;
|
||||
};
|
||||
exports.bytesNeededToStore = bytesNeededToStore = function(integer) {
|
||||
if (integer === 0) return 0;
|
||||
return Math.ceil(((integer).toString(2).replace('-','').length + 1)/ 8);
|
||||
};
|
||||
|
||||
exports.negativeBuffer = negativeBuffer = function(b) {
|
||||
// implement two-complement negative
|
||||
var c = new Buffer(b.length);
|
||||
// negate each byte
|
||||
for (var i=0; i<b.length; i++){
|
||||
c[i] = ~b[i];
|
||||
if (c[i] < 0) c[i] += 256;
|
||||
}
|
||||
exports.intToBuffer = function(integer) {
|
||||
var data = null;
|
||||
if (fitsInNBits(integer, 8)) {
|
||||
data = new Buffer(1);
|
||||
data.writeInt8(integer, 0);
|
||||
return data;
|
||||
} else if (fitsInNBits(integer, 16)) {
|
||||
data = new Buffer(2);
|
||||
data.writeInt16LE(integer, 0);
|
||||
return data;
|
||||
} else if (fitsInNBits(integer, 32)) {
|
||||
data = new Buffer(4);
|
||||
data.writeInt32LE(integer, 0);
|
||||
return data;
|
||||
// add one
|
||||
for (var i=b.length - 1; i>=0; i--){
|
||||
c[i] += 1;
|
||||
if (c[i] >= 256) c[i] -= 256;
|
||||
if (c[i] !== 0) break;
|
||||
}
|
||||
return c;
|
||||
};
|
||||
|
||||
/*
|
||||
* Transforms an integer into a buffer using two-complement encoding
|
||||
* For example, 1 is encoded as 01 and -1 is encoded as ff
|
||||
* For more info see:
|
||||
* http://en.wikipedia.org/wiki/Signed_number_representations#Two.27s_complement
|
||||
*/
|
||||
exports.intToBuffer2C = function(integer) {
|
||||
var size = bytesNeededToStore(integer);
|
||||
var buf = new Put();
|
||||
var s = integer.toString(16);
|
||||
var neg = s[0] === '-';
|
||||
s = s.replace('-','');
|
||||
for (var i=0; i<size; i++) {
|
||||
var si = s.substring(s.length - 2*(i+1), s.length - 2*(i));
|
||||
if (si.lenght === 1) {
|
||||
si = '0' + si;
|
||||
}
|
||||
var pi = parseInt(si, 16);
|
||||
buf.word8(pi);
|
||||
}
|
||||
var ret = buf.buffer();
|
||||
if (neg) {
|
||||
ret = buffertools.reverse(ret);
|
||||
ret = negativeBuffer(ret);
|
||||
ret = buffertools.reverse(ret);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
var padSign = function(b) {
|
||||
var c;
|
||||
if (b[0] & 0x80) {
|
||||
c = new Buffer(b.length + 1);
|
||||
b.copy(c, 1);
|
||||
c[0] = 0;
|
||||
} else {
|
||||
var x = intTo64Bits(integer);
|
||||
data = new Buffer(8);
|
||||
data.writeInt32LE(x.hi, 0); // high part contains sign information (signed)
|
||||
data.writeUInt32LE(x.lo, 4); // low part encoded as unsigned integer
|
||||
return data;
|
||||
c = b;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Transforms an integer into a buffer using sign+magnitude encoding
|
||||
* For example, 1 is encoded as 01 and -1 is encoded as 81
|
||||
* For more info see:
|
||||
* http://en.wikipedia.org/wiki/Signed_number_representations#Signed_magnitude_representation
|
||||
*/
|
||||
exports.intToBufferSM = function(v) {
|
||||
if ("number" === typeof v) {
|
||||
v = bignum(v);
|
||||
}
|
||||
var b, c;
|
||||
var cmp = v.cmp(0);
|
||||
if (cmp > 0) {
|
||||
b = v.toBuffer();
|
||||
c = padSign(b);
|
||||
c = buffertools.reverse(c);
|
||||
} else if (cmp == 0) {
|
||||
c = new Buffer([]);
|
||||
} else {
|
||||
b = v.neg().toBuffer();
|
||||
c = padSign(b);
|
||||
c[0] |= 0x80;
|
||||
c = buffertools.reverse(c);
|
||||
}
|
||||
return c;
|
||||
};
|
||||
|
||||
/*
|
||||
* Reverse of intToBufferSM
|
||||
*/
|
||||
exports.bufferSMToInt = function(v) {
|
||||
if (!v.length) {
|
||||
return bignum(0);
|
||||
}
|
||||
// Arithmetic operands must be in range [-2^31...2^31]
|
||||
if (v.length > 4) {
|
||||
throw new Error('Bigint cast overflow (> 4 bytes)');
|
||||
}
|
||||
|
||||
var w = new Buffer(v.length);
|
||||
v.copy(w);
|
||||
w = buffertools.reverse(w);
|
||||
var isNeg = w[0] & 0x80;
|
||||
if (isNeg) {
|
||||
w[0] &= 0x7f;
|
||||
return bignum.fromBuffer(w).neg();
|
||||
} else {
|
||||
return bignum.fromBuffer(w);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
var formatValue = exports.formatValue = function (valueBuffer) {
|
||||
var value = valueToBigInt(valueBuffer).toString();
|
||||
var integerPart = value.length > 8 ? value.substr(0, value.length-8) : '0';
|
||||
|
|
Loading…
Reference in New Issue