Merge remote-tracking branch 'maraoz/feature/add-bitcoin-core-tests'

Conflicts:
	Script.js
	ScriptInterpreter.js

...fixed conflicts in Script.js and ScriptInterpreter.js. Many tests are broken
right now, but that's because we're now including more test data in the tests.
These need to be fixed.
This commit is contained in:
Ryan X. Charles 2014-03-09 12:07:11 -04:00
commit cb00efb092
7 changed files with 130 additions and 48 deletions

106
Script.js
View File

@ -128,7 +128,7 @@ Script.prototype.finishedMultiSig = function() {
return true;
else
return false;
}
};
Script.prototype.removePlaceHolders = function() {
var chunks = [];
@ -142,7 +142,7 @@ Script.prototype.removePlaceHolders = function() {
this.chunks = chunks;
this.updateBuffer();
return this;
}
};
Script.prototype.prependOp0 = function() {
var chunks = [0];
@ -154,7 +154,7 @@ Script.prototype.prependOp0 = function() {
this.chunks = chunks;
this.updateBuffer();
return this;
}
};
// is this a script form we know?
Script.prototype.classify = function() {
@ -262,30 +262,6 @@ Script.prototype.getBuffer = function() {
return this.buffer;
};
Script.fromStringContent = function(s) {
var chunks = [];
var split = s.split(' ');
for (var i = 0; i < split.length; i++) {
var word = split[i];
if (word.length > 2 && word.substring(0, 2) === '0x') {
chunks.push(new Buffer(word.substring(2, word.length), 'hex'));
} else {
var opcode = Opcode.map['OP_' + word];
if (opcode) {
chunks.push(opcode);
} else {
var integer = parseInt(word);
if (!isNaN(integer)) {
//console.log(integer+' bits=\t'+integer.toString(2).replace('-','').length);
var data = util.intToBuffer(integer);
chunks.push(data);
}
}
}
}
return Script.fromChunks(chunks);
};
Script.prototype.getStringContent = function(truncate, maxEl) {
if (truncate === null) {
truncate = true;
@ -324,7 +300,6 @@ Script.prototype.toString = function(truncate, maxEl) {
return script;
};
Script.prototype.writeOp = function(opcode) {
var buf = Buffer(this.buffer.length + 1);
this.buffer.copy(buf);
@ -481,6 +456,79 @@ Script.fromChunks = function(chunks) {
return script;
};
Script.fromHumanReadable = function(s) {
return new Script(Script.stringToBuffer(s));
};
Script.prototype.toHumanReadable = function() {
var s = '';
for (var i = 0, l = this.chunks.length; i < l; i++) {
var chunk = this.chunks[i];
if (i > 0) {
s += ' ';
}
if (Buffer.isBuffer(chunk)) {
if (chunk.length === 0) {
s += '0';
} else {
s += '0x' + util.formatBuffer(encodeLen(chunk.length), 0) + ' ';
s += '0x' + util.formatBuffer(chunk, 0);
}
} else {
var opcode = Opcode.reverseMap[chunk];
if (typeof opcode === 'undefined') {
opcode = '0x'+chunk.toString(16);
}
s += opcode;
}
}
return s;
};
Script.stringToBuffer = function(s) {
var buf = new Put();
var split = s.split(' ');
for (var i = 0; i < split.length; i++) {
var word = split[i];
if (word === '') continue;
if (word.length > 2 && word.substring(0, 2) === '0x') {
// raw hex value
//console.log('hex value');
buf.put(new Buffer(word.substring(2, word.length), 'hex'));
} else {
var opcode = Opcode.map['OP_' + word];
if (typeof opcode !== 'undefined') {
// op code in string form
//console.log('opcode');
buf.word8(opcode);
} else {
var integer = parseInt(word);
if (!isNaN(integer)) {
// integer
//console.log('integer');
var data = util.intToBuffer(integer);
buf.put(Script.chunksToBuffer([data]));
} else if (word[0] === '\'' && word[word.length-1] === '\'') {
// string
//console.log('string');
word = word.substring(1,word.length-1);
var hexString = '';
for(var c=0;c<word.length;c++) {
hexString += ''+word.charCodeAt(c).toString(16);
}
buf.put(Script.chunksToBuffer([new Buffer(word)]));
} else {
throw new Error('Could not parse word "' +word+'" from script "'+s+'"');
}
}
}
}
return buf.buffer();
};
Script.chunksToBuffer = function(chunks) {
var buf = new Put();
@ -509,4 +557,6 @@ Script.chunksToBuffer = function(chunks) {
return buf.buffer();
};
module.exports = require('soop')(Script);

View File

@ -21,9 +21,8 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
if ("function" !== typeof callback) {
throw new Error("ScriptInterpreter.eval() requires a callback");
}
var pc = 0;
var execStack = [];
var altStack = [];
var hashStart = 0;
@ -758,7 +757,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
}
} catch (e) {
log.debug("Script aborted: " +
(e.message ? e : e));
(e.message ? e.message : e));
cb(e);
}
}

View File

@ -1,8 +1,8 @@
[
["0x01 0x0b", "11 EQUAL", "push 1 byte"],
["0x02 0x417a", "0x417a EQUAL"],
["0x02 0x417a", "'Az' EQUAL"],
["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a",
"0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a EQUAL", "push 75 bytes"],
"'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "push 75 bytes"],
["0x4c 0x01 0x07","7 EQUAL", "0x4c is OP_PUSHDATA1"],
["0x4d 0x0100 0x08","8 EQUAL", "0x4d is OP_PUSHDATA2"],
@ -11,7 +11,7 @@
["0x4c 0x00","0 EQUAL"],
["0x4d 0x0000","0 EQUAL"],
["0x4e 0x00000000","0 EQUAL"],
["0x4f 0x03e8 ADD","0x03e7 EQUAL"],
["0x4f 1000 ADD","999 EQUAL"],
["0", "IF 0x50 ENDIF 1", "0x50 is reserved (ok if not executed)"],
["0x51", "0x5f ADD 0x60 EQUAL", "0x51 through 0x60 push 1 through 16 onto stack"],
["1","NOP"],
@ -53,8 +53,8 @@
["1 1", "VERIFY"],
["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 0x15 EQUAL"],
["0x676176696e5f7761735f68657265 TOALTSTACK 11 FROMALTSTACK", "0x676176696e5f7761735f68657265 EQUALVERIFY 11 EQUAL"],
["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL"],
["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL"],
["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL"],
["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL"],

View File

@ -84,17 +84,18 @@ describe('Script', function() {
});
});
test_data.dataScriptValid.forEach(function(datum) {
test_data.dataScriptAll.forEach(function(datum) {
if (datum.length < 2) throw new Error('Invalid test data');
var human = datum[0] + ' ' + datum[1];
it('should parse script from human readable ' + human, function() {
var h2 = Script.fromStringContent(human).getStringContent(false, null);
Script.fromStringContent(h2).getStringContent(false, null).should.equal(h2);
//console.log('********');
//console.log(human);
var script = Script.fromHumanReadable(human);
//console.log(script);
var h2 = script.toHumanReadable();
//console.log(h2);
Script.fromHumanReadable(h2).toHumanReadable().should.equal(h2);
});
});
});

View File

@ -4,8 +4,10 @@ var chai = chai || require('chai');
var bitcore = bitcore || require('../bitcore');
var should = chai.should();
var test_data = require('./testdata');
var ScriptInterpreterModule = bitcore.ScriptInterpreter;
var Script = bitcore.Script;
var ScriptInterpreter;
describe('ScriptInterpreter', function() {
@ -20,6 +22,26 @@ describe('ScriptInterpreter', function() {
var si = new ScriptInterpreter();
should.exist(si);
});
var i = 0;
test_data.dataScriptValid.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('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
function (err, result) {
should.not.exist(err);
result.should.equal(true);
done();
}
);
});
});
});

View File

@ -15,3 +15,4 @@ module.exports.dataTxValid = dataTxValid;
module.exports.dataTxInvalid = dataTxInvalid;
module.exports.dataScriptValid = dataScriptValid;
module.exports.dataScriptInvalid = dataScriptInvalid;
module.exports.dataScriptAll = dataScriptValid.concat(dataScriptInvalid);

View File

@ -111,18 +111,27 @@ var intTo64Bits = function(integer) {
lo: (integer & 0xFFFFFFFF) >>> 0
};
};
var fitsIn32Bits = function(integer) {
var fitsInNBits = function(integer, n) {
// TODO: make this efficient!!!
return integer.toString(2).replace('-','').length < 32;
return integer.toString(2).replace('-','').length < n;
}
exports.intToBuffer = function(integer) {
if (fitsIn32Bits(integer)) {
var data = new Buffer(4);
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;
} else {
var x = intTo64Bits(integer);
var data = new Buffer(8);
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;