Browse Source

refactors and fixes for script interpreter

patch-2
Manuel Araoz 10 years ago
parent
commit
3de71f8558
  1. 4
      lib/crypto/bn.js
  2. 46
      lib/crypto/hash.js
  3. 22
      lib/script.js
  4. 19
      lib/script_interpreter.js
  5. 27
      test/crypto/hash.js
  6. 17
      test/script.js
  7. 114
      test/script_interpreter.js

4
lib/crypto/bn.js

@ -140,7 +140,7 @@ BN.prototype.toSM = function(opts) {
// bitcoind's script interpreter use CScriptNum, which is not really a proper // bitcoind's script interpreter use CScriptNum, which is not really a proper
// bignum. Instead, an error is thrown if trying to input a number bigger than // bignum. Instead, an error is thrown if trying to input a number bigger than
// 4 bytes. We copy that behavior here. // 4 bytes. We copy that behavior here.
BN.prototype.fromCScriptNumBuffer = function(buf, fRequireMinimal) { BN.prototype.fromScriptNumBuffer = function(buf, fRequireMinimal) {
var nMaxNumSize = 4; var nMaxNumSize = 4;
if (buf.length > nMaxNumSize) if (buf.length > nMaxNumSize)
throw new Error('script number overflow'); throw new Error('script number overflow');
@ -169,7 +169,7 @@ BN.prototype.fromCScriptNumBuffer = function(buf, fRequireMinimal) {
// an error if the output is larger than four bytes. (Which can happen if // an error if the output is larger than four bytes. (Which can happen if
// performing a numerical operation that results in an overflow to more than 4 // performing a numerical operation that results in an overflow to more than 4
// bytes). // bytes).
BN.prototype.toCScriptNumBuffer = function(buf) { BN.prototype.toScriptNumBuffer = function(buf) {
return this.toSM({endian: 'little'}); return this.toSM({endian: 'little'});
}; };

46
lib/crypto/hash.js

@ -2,44 +2,44 @@
var hashjs = require('hash.js'); var hashjs = require('hash.js');
var sha512 = require('sha512'); var sha512 = require('sha512');
var crypto = require('crypto');
var BufferUtil = require('../util/buffer');
var $ = require('../util/preconditions');
var Hash = module.exports; var Hash = module.exports;
Hash.sha1 = function(buf) {
$.checkArgument(BufferUtil.isBuffer(buf));
return crypto.createHash('sha1').update(buf).digest();
};
Hash.sha1.blocksize = 512;
Hash.sha256 = function(buf) { Hash.sha256 = function(buf) {
if (!Buffer.isBuffer(buf)) $.checkArgument(BufferUtil.isBuffer(buf));
throw new Error('sha256 hash must be of a buffer'); return crypto.createHash('sha256').update(buf).digest();
var hash = (new hashjs.sha256()).update(buf).digest();
return new Buffer(hash);
}; };
Hash.sha256.blocksize = 512; Hash.sha256.blocksize = 512;
Hash.sha256sha256 = function(buf) { Hash.sha256sha256 = function(buf) {
try { $.checkArgument(BufferUtil.isBuffer(buf));
return Hash.sha256(Hash.sha256(buf)); return Hash.sha256(Hash.sha256(buf));
} catch (e) {
throw new Error('sha256sha256 hash must be of a buffer');
}
}; };
Hash.ripemd160 = function(buf) { Hash.ripemd160 = function(buf) {
if (!Buffer.isBuffer(buf)) $.checkArgument(BufferUtil.isBuffer(buf));
throw new Error('ripemd160 hash must be of a buffer');
var hash = (new hashjs.ripemd160()).update(buf).digest(); var hash = (new hashjs.ripemd160()).update(buf).digest();
return new Buffer(hash); return new Buffer(hash);
}; };
Hash.sha256ripemd160 = function(buf) { Hash.sha256ripemd160 = function(buf) {
try { $.checkArgument(BufferUtil.isBuffer(buf));
return Hash.ripemd160(Hash.sha256(buf)); return Hash.ripemd160(Hash.sha256(buf));
} catch (e) {
throw new Error('sha256ripemd160 hash must be of a buffer');
}
}; };
Hash.sha512 = function(buf) { Hash.sha512 = function(buf) {
if (!Buffer.isBuffer(buf)) $.checkArgument(BufferUtil.isBuffer(buf));
throw new Error('sha512 hash must be of a buffer');
var hash = sha512(buf); var hash = sha512(buf);
return new Buffer(hash); return new Buffer(hash);
}; };
@ -47,19 +47,17 @@ Hash.sha512 = function(buf) {
Hash.sha512.blocksize = 1024; Hash.sha512.blocksize = 1024;
Hash.hmac = function(hashf, data, key) { Hash.hmac = function(hashf, data, key) {
if (!Buffer.isBuffer(data) || !Buffer.isBuffer(key))
throw new Error('data and key must be buffers');
//http://en.wikipedia.org/wiki/Hash-based_message_authentication_code //http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
//http://tools.ietf.org/html/rfc4868#section-2 //http://tools.ietf.org/html/rfc4868#section-2
if (!hashf.blocksize) $.checkArgument(BufferUtil.isBuffer(data));
throw new Error('Blocksize for hash function unknown'); $.checkArgument(BufferUtil.isBuffer(key));
$.checkArgument(hashf.blocksize);
var blocksize = hashf.blocksize/8; var blocksize = hashf.blocksize / 8;
if (key.length > blocksize) if (key.length > blocksize) {
key = hashf(key); key = hashf(key);
else if (key < blocksize) { } else if (key < blocksize) {
var fill = new Buffer(blocksize); var fill = new Buffer(blocksize);
fill.fill(0); fill.fill(0);
key.copy(fill); key.copy(fill);

22
lib/script.js

@ -127,7 +127,7 @@ Script.prototype.toBuffer = function() {
}; };
Script.fromString = function(str) { Script.fromString = function(str) {
if (jsUtil.isHexa(str)) { if (jsUtil.isHexa(str) || str.length === 0) {
return new Script(new buffer.Buffer(str, 'hex')); return new Script(new buffer.Buffer(str, 'hex'));
} }
var script = new Script(); var script = new Script();
@ -140,7 +140,7 @@ Script.fromString = function(str) {
var opcode = Opcode(token); var opcode = Opcode(token);
var opcodenum = opcode.toNumber(); var opcodenum = opcode.toNumber();
if (typeof opcodenum === 'undefined') { if (_.isUndefined(opcodenum)) {
opcodenum = parseInt(token); opcodenum = parseInt(token);
if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) {
script.chunks.push({ script.chunks.push({
@ -184,7 +184,11 @@ Script.prototype.toString = function() {
if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') { if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') {
str = str + ' ' + Opcode(opcodenum).toString(); str = str + ' ' + Opcode(opcodenum).toString();
} else { } else {
str = str + ' ' + '0x' + opcodenum.toString(16); var numstr = opcodenum.toString(16);
if (numstr.length % 2 !== 0) {
numstr = '0' + numstr;
}
str = str + ' ' + '0x' + numstr;
} }
} else { } else {
if (opcodenum === Opcode.OP_PUSHDATA1 || if (opcodenum === Opcode.OP_PUSHDATA1 ||
@ -193,9 +197,11 @@ Script.prototype.toString = function() {
str = str + ' ' + Opcode(opcodenum).toString(); str = str + ' ' + Opcode(opcodenum).toString();
} }
str = str + ' ' + chunk.len; str = str + ' ' + chunk.len;
if (chunk.len > 0) {
str = str + ' ' + '0x' + chunk.buf.toString('hex'); str = str + ' ' + '0x' + chunk.buf.toString('hex');
} }
} }
}
return str.substr(1); return str.substr(1);
}; };
@ -475,9 +481,7 @@ Script.prototype._addOpcode = function(opcode, prepend) {
Script.prototype._addBuffer = function(buf, prepend) { Script.prototype._addBuffer = function(buf, prepend) {
var opcodenum; var opcodenum;
var len = buf.length; var len = buf.length;
if (len === 0) { if (len >= 0 && len < Opcode.OP_PUSHDATA1) {
return;
} else if (len > 0 && len < Opcode.OP_PUSHDATA1) {
opcodenum = len; opcodenum = len;
} else if (len < Math.pow(2, 8)) { } else if (len < Math.pow(2, 8)) {
opcodenum = Opcode.OP_PUSHDATA1; opcodenum = Opcode.OP_PUSHDATA1;
@ -601,8 +605,10 @@ Script.buildDataOut = function(data) {
data = new Buffer(data); data = new Buffer(data);
} }
var s = new Script(); var s = new Script();
s.add(Opcode.OP_RETURN) s.add(Opcode.OP_RETURN);
.add(data); if (!_.isUndefined(data)) {
s.add(data);
}
return s; return s;
}; };

19
lib/script_interpreter.js

@ -167,7 +167,7 @@ ScriptInterpreter.prototype.evaluate = function() {
return false; return false;
} }
try { //try {
while (this.pc < this.script.chunks.length) { while (this.pc < this.script.chunks.length) {
var fSuccess = this.step(); var fSuccess = this.step();
if (!fSuccess) { if (!fSuccess) {
@ -180,10 +180,10 @@ ScriptInterpreter.prototype.evaluate = function() {
this.errstr = 'SCRIPT_ERR_STACK_SIZE'; this.errstr = 'SCRIPT_ERR_STACK_SIZE';
return false; return false;
} }
} catch (e) { //} catch (e) {
this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e; // this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e;
return false; // return false;
} //}
if (this.vfExec.length > 0) { if (this.vfExec.length > 0) {
this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL';
@ -202,12 +202,11 @@ ScriptInterpreter.prototype.step = function() {
var fRequireMinimal = (this.flags & ScriptInterpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0; var fRequireMinimal = (this.flags & ScriptInterpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0;
//bool fExec = !count(vfExec.begin(), vfExec.end(), false); //bool fExec = !count(vfExec.begin(), vfExec.end(), false);
var fExec = (this.vfExec.indexOf(false) !== -1); var fExec = (this.vfExec.indexOf(false) === -1);
// Read instruction // Read instruction
var chunk = this.script.chunks[this.pc]; var chunk = this.script.chunks[this.pc];
console.log('STEP!' + JSON.stringify(chunk));
this.pc++; this.pc++;
var opcodenum = chunk.opcodenum; var opcodenum = chunk.opcodenum;
if (_.isUndefined(opcodenum)) { if (_.isUndefined(opcodenum)) {
@ -225,6 +224,7 @@ ScriptInterpreter.prototype.step = function() {
return false; return false;
} }
if (opcodenum === Opcode.OP_CAT || if (opcodenum === Opcode.OP_CAT ||
opcodenum === Opcode.OP_SUBSTR || opcodenum === Opcode.OP_SUBSTR ||
opcodenum === Opcode.OP_LEFT || opcodenum === Opcode.OP_LEFT ||
@ -257,6 +257,7 @@ ScriptInterpreter.prototype.step = function() {
this.stack.push(chunk.buf); this.stack.push(chunk.buf);
} }
} else if (fExec || (Opcode.OP_IF <= opcodenum && opcodenum <= Opcode.OP_ENDIF)) { } else if (fExec || (Opcode.OP_IF <= opcodenum && opcodenum <= Opcode.OP_ENDIF)) {
console.log('STEP!' + JSON.stringify(chunk));
switch (opcodenum) { switch (opcodenum) {
// Push value // Push value
case Opcode.OP_1NEGATE: case Opcode.OP_1NEGATE:
@ -1095,7 +1096,7 @@ ScriptInterpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin,
} }
// Additional validation for spend-to-script-hash transactions: // Additional validation for spend-to-script-hash transactions:
if ((flags & ScriptInterpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScripthashOut()) { if ((flags & ScriptInterpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScriptHashOut()) {
// scriptSig must be literals-only or validation fails // scriptSig must be literals-only or validation fails
if (!scriptSig.isPushOnly()) { if (!scriptSig.isPushOnly()) {
this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY';
@ -1109,7 +1110,7 @@ ScriptInterpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin,
throw new Error('internal error - stack copy empty'); throw new Error('internal error - stack copy empty');
var pubkeySerialized = stackCopy[stackCopy.length - 1]; var pubkeySerialized = stackCopy[stackCopy.length - 1];
var scriptPubkey2 = Script().fromBuffer(pubkeySerialized); var scriptPubkey2 = Script.fromBuffer(pubkeySerialized);
stackCopy.pop(); stackCopy.pop();
this.initialize(); this.initialize();

27
test/crypto/hash.js

@ -8,6 +8,23 @@ describe('Hash', function() {
var buf = new Buffer([0, 1, 2, 3, 253, 254, 255]); var buf = new Buffer([0, 1, 2, 3, 253, 254, 255]);
var str = 'test string'; var str = 'test string';
describe('@sha1', function() {
it('should calculate the hash of this buffer correctly', function() {
var hash = Hash.sha1(buf);
hash.toString('hex').should.equal('de69b8a4a5604d0486e6420db81e39eb464a17b2');
hash = Hash.sha1(new Buffer(0));
hash.toString('hex').should.equal('da39a3ee5e6b4b0d3255bfef95601890afd80709');
});
it('should throw an error when the input is not a buffer', function() {
(function() {
Hash.sha1(str);
}).should.throw('Invalid Argument');
});
});
describe('#sha256', function() { describe('#sha256', function() {
it('should calculate the hash of this buffer correctly', function() { it('should calculate the hash of this buffer correctly', function() {
@ -18,7 +35,7 @@ describe('Hash', function() {
it('should throw an error when the input is not a buffer', function() { it('should throw an error when the input is not a buffer', function() {
(function() { (function() {
Hash.sha256(str); Hash.sha256(str);
}).should.throw('sha256 hash must be of a buffer'); }).should.throw('Invalid Argument');
}); });
}); });
@ -49,7 +66,7 @@ describe('Hash', function() {
it('should throw an error when the input is not a buffer', function() { it('should throw an error when the input is not a buffer', function() {
(function() { (function() {
Hash.sha256sha256(str); Hash.sha256sha256(str);
}).should.throw('sha256sha256 hash must be of a buffer'); }).should.throw('Invalid Argument');
}); });
}); });
@ -64,7 +81,7 @@ describe('Hash', function() {
it('should throw an error when the input is not a buffer', function() { it('should throw an error when the input is not a buffer', function() {
(function() { (function() {
Hash.sha256ripemd160(str); Hash.sha256ripemd160(str);
}).should.throw('sha256ripemd160 hash must be of a buffer'); }).should.throw('Invalid Argument');
}); });
}); });
@ -79,7 +96,7 @@ describe('Hash', function() {
it('should throw an error when the input is not a buffer', function() { it('should throw an error when the input is not a buffer', function() {
(function() { (function() {
Hash.ripemd160(str); Hash.ripemd160(str);
}).should.throw('ripemd160 hash must be of a buffer'); }).should.throw('Invalid Argument');
}); });
}); });
@ -94,7 +111,7 @@ describe('Hash', function() {
it('should throw an error when the input is not a buffer', function() { it('should throw an error when the input is not a buffer', function() {
(function() { (function() {
Hash.sha512(str); Hash.sha512(str);
}).should.throw('sha512 hash must be of a buffer'); }).should.throw('Invalid Argument');
}); });
}); });

17
test/script.js

@ -349,9 +349,8 @@ describe('Script', function() {
describe('#add and #prepend', function() { describe('#add and #prepend', function() {
it('should add these ops', function() { it('should add these ops', function() {
Script().add(Opcode('OP_RETURN')).add(new Buffer('')).toString().should.equal('OP_RETURN'); Script().add(1).add(10).add(186).toString().should.equal('0x01 0x0a 0xba');
}); Script().add(1000).toString().should.equal('0x03e8');
it('should add these ops', function() {
Script().add('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG'); Script().add('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG');
Script().add('OP_1').add('OP_2').toString().should.equal('OP_1 OP_2'); Script().add('OP_1').add('OP_2').toString().should.equal('OP_1 OP_2');
Script().add(new Opcode('OP_CHECKMULTISIG')).toString().should.equal('OP_CHECKMULTISIG'); Script().add(new Opcode('OP_CHECKMULTISIG')).toString().should.equal('OP_CHECKMULTISIG');
@ -390,6 +389,10 @@ describe('Script', function() {
buf.fill(0); buf.fill(0);
Script().add(buf).toString().should.equal('1 0x00'); Script().add(buf).toString().should.equal('1 0x00');
}); });
it('should work for no data OP_RETURN', function() {
Script().add(Opcode('OP_RETURN')).add(new Buffer('')).toString().should.equal('OP_RETURN 0');
});
}); });
describe('#isStandard', function() { describe('#isStandard', function() {
@ -469,11 +472,17 @@ describe('Script', function() {
}); });
}); });
describe('#buildDataOut', function() { describe('#buildDataOut', function() {
it('should create script from no data', function() {
var s = Script.buildDataOut();
should.exist(s);
s.toString().should.equal('OP_RETURN');
s.isDataOut().should.equal(true);
});
it('should create script from empty data', function() { it('should create script from empty data', function() {
var data = new Buffer(''); var data = new Buffer('');
var s = Script.buildDataOut(data); var s = Script.buildDataOut(data);
should.exist(s); should.exist(s);
s.toString().should.equal('OP_RETURN'); s.toString().should.equal('OP_RETURN 0');
s.isDataOut().should.equal(true); s.isDataOut().should.equal(true);
}); });
it('should create script from some data', function() { it('should create script from some data', function() {

114
test/script_interpreter.js

@ -8,12 +8,79 @@ var Script = bitcore.Script;
var BN = bitcore.crypto.BN; var BN = bitcore.crypto.BN;
var Sig = bitcore.crypto.Signature; var Sig = bitcore.crypto.Signature;
var BufferReader = bitcore.encoding.BufferReader; var BufferReader = bitcore.encoding.BufferReader;
var BufferWriter = bitcore.encoding.BufferWriter;
var PrivateKey = bitcore.PrivateKey;
var Opcode = bitcore.Opcode;
var script_valid = require('./data/bitcoind/script_valid'); var script_valid = require('./data/bitcoind/script_valid');
var script_invalid = require('./data/bitcoind/script_invalid'); var script_invalid = require('./data/bitcoind/script_invalid');
var tx_valid = require('./transaction/tx_valid'); var tx_valid = require('./transaction/tx_valid');
var tx_invalid = require('./transaction/tx_invalid'); var tx_invalid = require('./transaction/tx_invalid');
//the script string format used in bitcoind data tests
Script.fromBitcoindString = function(str) {
var bw = new BufferWriter();
var tokens = str.split(' ');
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (token === '') {
continue;
}
var opstr;
var opcodenum;
var tbuf;
if (token[0] === '0' && token[1] === 'x') {
var hex = token.slice(2);
bw.write(new Buffer(hex, 'hex'));
} else if (token[0] === '\'') {
var tstr = token.slice(1, token.length - 1);
var cbuf = new Buffer(tstr);
tbuf = Script().add(cbuf).toBuffer();
bw.write(tbuf);
} else if (typeof Opcode['OP_' + token] !== 'undefined') {
opstr = 'OP_' + token;
opcodenum = Opcode[opstr];
bw.writeUInt8(opcodenum);
} else if (typeof Opcode[token] === 'number') {
opstr = token;
opcodenum = Opcode[opstr];
bw.writeUInt8(opcodenum);
} else if (!isNaN(parseInt(token))) {
var script = Script().add(BN(token).toScriptNumBuffer());
tbuf = script.toBuffer();
bw.write(tbuf);
} else {
throw new Error('Could not determine type of script value');
}
}
var buf = bw.concat();
return this.fromBuffer(buf);
};
//the script string format used in bitcoind data tests
Script.toBitcoindString = function() {
var str = '';
for (var i = 0; i < this.chunks.length; i++) {
var chunk = this.chunks[i];
if (chunk.buf) {
var buf = Script({
chunks: [chunk]
}).toBuffer();
var hex = buf.toString('hex');
str = str + ' ' + '0x' + hex;
} else if (typeof Opcode.str[chunk.opcodenum] !== 'undefined') {
var ostr = Opcode(chunk.opcodenum).toString();
str = str + ' ' + ostr.slice(3); //remove OP_
} else {
str = str + ' ' + '0x' + chunk.opcodenum.toString(16);
}
}
return str.substr(1);
};
describe('ScriptInterpreter', function() { describe('ScriptInterpreter', function() {
it('should make a new interp', function() { it('should make a new interp', function() {
@ -58,7 +125,6 @@ describe('ScriptInterpreter', function() {
var verified; var verified;
var si = ScriptInterpreter(); var si = ScriptInterpreter();
verified = si.verify(Script('OP_1'), Script('OP_1')); verified = si.verify(Script('OP_1'), Script('OP_1'));
console.log(si.errstr);
verified.should.equal(true); verified.should.equal(true);
verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_0')); verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_0'));
verified.should.equal(false); verified.should.equal(false);
@ -78,9 +144,11 @@ describe('ScriptInterpreter', function() {
verified.should.equal(true); verified.should.equal(true);
}); });
it('should verify this new pay-to-pubkey script', function() { it.skip('should verify this new pay-to-pubkey script', function() {
var keypair = Keypair().fromRandom(); // TODO: unskip when Transaction is done
var scriptPubkey = Script().writeBuffer(keypair.pubkey.toDER(true)).writeOp('OP_CHECKSIG'); var privkey = new PrivateKey();
var pubkey = privkey.toPublicKey();
var scriptPubkey = Script.buildPublicKeyOut(pubkey);
var hashbuf = new Buffer(32); var hashbuf = new Buffer(32);
hashbuf.fill(0); hashbuf.fill(0);
@ -102,9 +170,9 @@ describe('ScriptInterpreter', function() {
verified.should.equal(true); verified.should.equal(true);
}); });
it('should verify this pay-to-pubkey script from script_valid.json', function() { it.skip('should verify this pay-to-pubkey script from script_valid.json', function() {
var scriptSig = Script().fromBitcoindString('0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501'); var scriptSig = Script.fromBitcoindString('0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501');
var scriptPubkey = Script().fromBitcoindString('0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG'); var scriptPubkey = Script.fromBitcoindString('0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG');
var hashbuf = new Buffer(32); var hashbuf = new Buffer(32);
hashbuf.fill(0); hashbuf.fill(0);
@ -124,7 +192,6 @@ describe('ScriptInterpreter', function() {
}); });
describe('vectors', function() {
var getFlags = function getFlags(flagstr) { var getFlags = function getFlags(flagstr) {
var flags = 0; var flags = 0;
@ -159,30 +226,25 @@ describe('ScriptInterpreter', function() {
}; };
var c = 0; var c = 0;
describe.only('bitcoind fixtures', function() {
script_valid.forEach(function(vector) { script_valid.forEach(function(vector) {
if (vector.length === 1) { if (vector.length === 1) {
return; return;
} }
c++; c++;
var descstr = vector[3]; var descstr = vector[3];
it('should pass script_valid vector ' + c + '(' + descstr + ')', function() { var fullScriptString = vector[0] + ' ' + vector[1];
var scriptSig = Script().fromBitcoindString(vector[0]); var comment = descstr ? (' (' + descstr + ')') : '';
var scriptPubkey = Script().fromBitcoindString(vector[1]); it('should pass script_valid vector #' + c + ': ' + fullScriptString + comment, function() {
var scriptSig = Script.fromBitcoindString(vector[0]);
var scriptPubkey = Script.fromBitcoindString(vector[1]);
var flags = getFlags(vector[2]); var flags = getFlags(vector[2]);
var hashbuf = new Buffer(32);
hashbuf.fill(0);
var credtx = Transaction();
credtx.addTxin(hashbuf, 0xffffffff, Script('OP_0 OP_0'), 0xffffffff);
credtx.addTxout(BN(0), scriptPubkey);
var idbuf = credtx.hash();
var spendtx = Transaction(); var spendtx = Transaction();
spendtx.addTxin(idbuf, 0, scriptSig, 0xffffffff);
spendtx.addTxout(BN(0), Script());
var interp = ScriptInterpreter(); var interp = ScriptInterpreter();
var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags); var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags);
console.log(interp.errstr);
verified.should.equal(true); verified.should.equal(true);
}); });
}); });
@ -195,8 +257,8 @@ describe('ScriptInterpreter', function() {
c++; c++;
var descstr = vector[3]; var descstr = vector[3];
it('should pass script_invalid vector ' + c + '(' + descstr + ')', function() { it('should pass script_invalid vector ' + c + '(' + descstr + ')', function() {
var scriptSig = Script().fromBitcoindString(vector[0]); var scriptSig = Script.fromBitcoindString(vector[0]);
var scriptPubkey = Script().fromBitcoindString(vector[1]); var scriptPubkey = Script.fromBitcoindString(vector[1]);
var flags = getFlags(vector[2]); var flags = getFlags(vector[2]);
var hashbuf = new Buffer(32); var hashbuf = new Buffer(32);
@ -233,13 +295,13 @@ describe('ScriptInterpreter', function() {
if (txoutnum === -1) { if (txoutnum === -1) {
txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int
} }
map[input[0] + ':' + txoutnum] = Script().fromBitcoindString(input[2]); map[input[0] + ':' + txoutnum] = Script.fromBitcoindString(input[2]);
}); });
var tx = Transaction().fromBuffer(new Buffer(txhex, 'hex')); var tx = Transaction().fromBuffer(new Buffer(txhex, 'hex'));
tx.txins.forEach(function(txin, j) { tx.txins.forEach(function(txin, j) {
var scriptSig = txin.script; var scriptSig = txin.script;
var txidhex = BufR(txin.txidbuf).readReverse().toString('hex'); var txidhex = BufferReader(txin.txidbuf).readReverse().toString('hex');
var txoutnum = txin.txoutnum; var txoutnum = txin.txoutnum;
var scriptPubkey = map[txidhex + ':' + txoutnum]; var scriptPubkey = map[txidhex + ':' + txoutnum];
should.exist(scriptPubkey); should.exist(scriptPubkey);
@ -282,14 +344,14 @@ describe('ScriptInterpreter', function() {
if (txoutnum === -1) { if (txoutnum === -1) {
txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int
} }
map[input[0] + ':' + txoutnum] = Script().fromBitcoindString(input[2]); map[input[0] + ':' + txoutnum] = Script.fromBitcoindString(input[2]);
}); });
var tx = Transaction().fromBuffer(new Buffer(txhex, 'hex')); var tx = Transaction().fromBuffer(new Buffer(txhex, 'hex'));
if (tx.txins.length > 0) { if (tx.txins.length > 0) {
tx.txins.some(function(txin, j) { tx.txins.some(function(txin, j) {
var scriptSig = txin.script; var scriptSig = txin.script;
var txidhex = BufR(txin.txidbuf).readReverse().toString('hex'); var txidhex = BufferReader(txin.txidbuf).readReverse().toString('hex');
var txoutnum = txin.txoutnum; var txoutnum = txin.txoutnum;
var scriptPubkey = map[txidhex + ':' + txoutnum]; var scriptPubkey = map[txidhex + ':' + txoutnum];
should.exist(scriptPubkey); should.exist(scriptPubkey);

Loading…
Cancel
Save