Browse Source

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.
patch-2
Ryan X. Charles 11 years ago
parent
commit
cb00efb092
  1. 106
      Script.js
  2. 5
      ScriptInterpreter.js
  3. 10
      test/data/script_valid.json
  4. 15
      test/test.Script.js
  5. 22
      test/test.ScriptInterpreter.js
  6. 1
      test/testdata.js
  7. 19
      util/util.js

106
Script.js

@ -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);

5
ScriptInterpreter.js

@ -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);
}
}

10
test/data/script_valid.json

@ -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"],

15
test/test.Script.js

@ -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);
});
});
});

22
test/test.ScriptInterpreter.js

@ -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();
}
);
});
});
});

1
test/testdata.js

@ -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);

19
util/util.js

@ -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;

Loading…
Cancel
Save