bitcore/test/test.sighash.js

172 lines
4.5 KiB
JavaScript
Raw Normal View History

'use strict';
// inspired in bitcoin core test:
// https://github.com/bitcoin/bitcoin/blob/7d49a9173ab636d118c2a81fc3c3562192e7813a/src/test/sighash_tests.cpp
var chai = chai || require('chai');
var should = chai.should();
var bitcore = bitcore || require('../bitcore');
var Transaction = bitcore.Transaction;
var Script = bitcore.Script;
var Opcode = bitcore.Opcode;
2014-03-26 07:51:28 -07:00
var util = bitcore.util;
var Put = bitcore.Put;
var Put = require('bufferput');
var buffertools = require('buffertools');
2014-03-28 12:20:52 -07:00
var testdata = testdata || require('./testdata');
2014-03-26 07:51:28 -07:00
var seed = 1;
// seedable pseudo-random function
var random = function() {
var x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
};
var randInt = function(low, high) {
2014-03-26 07:51:28 -07:00
return Math.floor(random() * (high - low + 1) + low);
};
var randUIntN = function(nBits) {
return randInt(0, Math.pow(2, nBits));
};
var randUInt32 = function() {
return randUIntN(32);
};
var randBool = function() {
2014-03-26 07:51:28 -07:00
return random() < 0.5;
};
var hexAlphabet = '0123456789abcdef';
var randHex = function() {
return hexAlphabet[randInt(0, 15)];
};
var randHexN = function(n) {
var s = '';
while (n--) {
s += randHex();
}
return s;
};
var randTxHash = function() {
return randHexN(64);
};
var randPick = function(list) {
2014-03-26 07:51:28 -07:00
return list[randInt(0, list.length - 1)];
};
var opList = Opcode.asList();
var randomScript = function() {
var s = new Script();
2014-03-26 07:51:28 -07:00
var ops = randInt(0, 10);
for (var i = 0; i < ops; i++) {
var op = randPick(opList);
s.writeOp(Opcode.map[op]);
}
return s;
};
var randomTx = function(single) {
var tx = new Transaction({
version: randUInt32(),
lock_time: randBool() ? randUInt32() : 0
});
var insN = randInt(1, 5);
var outsN = single ? insN : randInt(1, 5);
for (var i = 0; i < insN; i++) {
var txin = new Transaction.In({
oTxHash: randTxHash(),
oIndex: randInt(0, 4),
script: randomScript().serialize(),
sequence: randBool() ? randUInt32() : 0xffffffff
});
tx.ins.push(txin);
}
for (i = 0; i < outsN; i++) {
2014-03-26 07:51:28 -07:00
var txout = new Transaction.Out({
value: new Buffer(8),
script: randomScript().serialize()
});
tx.outs.push(txout);
}
return tx;
};
2014-03-26 07:51:28 -07:00
2014-04-03 11:50:05 -07:00
var oneBuffer = function() {
// bug present in bitcoind which must be also present in bitcore
// see https://bitcointalk.org/index.php?topic=260595
2014-04-04 13:33:36 -07:00
var ret = new Buffer(32);
2014-04-03 11:50:05 -07:00
ret.writeUInt8(1, 0);
2014-04-04 13:33:36 -07:00
for (var i=1; i<32; i++) ret.writeUInt8(0, i);
2014-04-03 11:50:05 -07:00
return ret; // return 1 bug
};
2014-03-26 07:51:28 -07:00
var signatureHashOld = function(tx, script, inIndex, hashType) {
if (+inIndex !== inIndex ||
inIndex < 0 || inIndex >= tx.ins.length) {
2014-04-03 11:50:05 -07:00
return oneBuffer();
2014-03-26 07:51:28 -07:00
}
2014-04-03 11:50:05 -07:00
// Check for invalid use of SIGHASH_SINGLE
2014-03-26 07:51:28 -07:00
var hashTypeMode = hashType & 0x1f;
2014-04-03 11:50:05 -07:00
if (hashTypeMode === Transaction.SIGHASH_SINGLE) {
if (inIndex >= tx.outs.length) {
return oneBuffer();
2014-03-26 07:51:28 -07:00
}
}
2014-04-03 11:50:05 -07:00
// Wrapper to serialize only the necessary parts of the transaction being signed
var serializer = new Transaction.Serializer(tx, script, inIndex, hashType);
// Serialize
var buffer = serializer.buffer();
2014-03-26 07:51:28 -07:00
// Append hashType
2014-04-03 11:50:05 -07:00
var hashBuf = new Put().word32le(hashType).buffer();
buffer = Buffer.concat([buffer, hashBuf]);
2014-04-04 13:33:36 -07:00
return util.twoSha256(buffer);
2014-03-26 07:51:28 -07:00
};
describe('Transaction sighash (#hashForSignature)', function() {
2014-03-26 07:51:28 -07:00
for (var i = 0; i < 250; i++) {
2014-04-03 11:50:05 -07:00
it('should hash correctly random tx #' + (i + 1), function() {
var tx = randomTx();
2014-03-26 07:51:28 -07:00
var l = tx.ins.length;
for (var i = 0; i < l; i++) {
var script = randomScript();
var hashType = randUInt32();
var h = buffertools.toHex(tx.hashForSignature(script, i, hashType));
var oh = buffertools.toHex(signatureHashOld(tx, script, i, hashType));
h.should.equal(oh);
}
});
}
2014-03-28 12:20:52 -07:00
testdata.dataSighash.forEach(function(datum) {
if (datum.length < 5) return;
var raw_tx = new Buffer(datum[0], 'hex');
var scriptPubKey = new Script(new Buffer(datum[1], 'hex'));
var input_index = parseInt(datum[2]);
var hashType = parseInt(datum[3]);
2014-04-04 13:33:36 -07:00
var sighash = buffertools.toHex(buffertools.reverse(new Buffer(datum[4],'hex')));
2014-03-28 12:20:52 -07:00
it('should validate correctly ' + buffertools.toHex(raw_tx), function() {
var tx = new Transaction();
tx.parse(raw_tx);
var ser_tx = buffertools.toHex(tx.serialize());
ser_tx.should.equal(buffertools.toHex(raw_tx));
var h = buffertools.toHex(tx.hashForSignature(scriptPubKey, input_index, hashType));
2014-04-03 11:50:05 -07:00
h.should.equal(sighash); // compare our output with bitcoind's output
2014-03-28 12:20:52 -07:00
});
});
});