22 changed files with 2089 additions and 208 deletions
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||
[ |
|||
"300602010002010001", |
|||
"3008020200ff020200ff01", |
|||
"304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001", |
|||
"30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01", |
|||
"3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01" |
|||
] |
@ -0,0 +1,22 @@ |
|||
[ |
|||
"non-hex strings are ignored", |
|||
|
|||
"too short:", "30050201FF020001", |
|||
"too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
"hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11", |
|||
"type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
"total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
"S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101", |
|||
"R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001", |
|||
|
|||
"R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
"R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
"R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
"R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
|
|||
|
|||
"S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
"S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001", |
|||
"S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", |
|||
"S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01" |
|||
] |
@ -0,0 +1,315 @@ |
|||
'use strict'; |
|||
|
|||
var should = require('chai').should(); |
|||
var bitcore = require('..'); |
|||
var ScriptInterpreter = bitcore.ScriptInterpreter; |
|||
var Transaction = bitcore.Transaction; |
|||
var Script = bitcore.Script; |
|||
var BN = bitcore.crypto.BN; |
|||
var BufferReader = bitcore.encoding.BufferReader; |
|||
var BufferWriter = bitcore.encoding.BufferWriter; |
|||
var Opcode = bitcore.Opcode; |
|||
|
|||
var script_valid = require('./data/bitcoind/script_valid'); |
|||
var script_invalid = require('./data/bitcoind/script_invalid'); |
|||
var tx_valid = require('./transaction/tx_valid'); |
|||
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); |
|||
}; |
|||
|
|||
|
|||
|
|||
describe('ScriptInterpreter', function() { |
|||
|
|||
it('should make a new interp', function() { |
|||
var interp = new ScriptInterpreter(); |
|||
(interp instanceof ScriptInterpreter).should.equal(true); |
|||
interp.stack.length.should.equal(0); |
|||
interp.altstack.length.should.equal(0); |
|||
interp.pc.should.equal(0); |
|||
interp.pbegincodehash.should.equal(0); |
|||
interp.nOpCount.should.equal(0); |
|||
interp.vfExec.length.should.equal(0); |
|||
interp.errstr.should.equal(''); |
|||
interp.flags.should.equal(0); |
|||
}); |
|||
|
|||
describe('@castToBool', function() { |
|||
|
|||
it('should cast these bufs to bool correctly', function() { |
|||
ScriptInterpreter.castToBool(BN(0).toSM({ |
|||
endian: 'little' |
|||
})).should.equal(false); |
|||
ScriptInterpreter.castToBool(new Buffer('0080', 'hex')).should.equal(false); //negative 0
|
|||
ScriptInterpreter.castToBool(BN(1).toSM({ |
|||
endian: 'little' |
|||
})).should.equal(true); |
|||
ScriptInterpreter.castToBool(BN(-1).toSM({ |
|||
endian: 'little' |
|||
})).should.equal(true); |
|||
|
|||
var buf = new Buffer('00', 'hex'); |
|||
var bool = BN().fromSM(buf, { |
|||
endian: 'little' |
|||
}).cmp(0) !== 0; |
|||
ScriptInterpreter.castToBool(buf).should.equal(bool); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#verify', function() { |
|||
|
|||
it('should verify these trivial scripts', function() { |
|||
var verified; |
|||
var si = ScriptInterpreter(); |
|||
verified = si.verify(Script('OP_1'), Script('OP_1')); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_0')); |
|||
verified.should.equal(false); |
|||
verified = ScriptInterpreter().verify(Script('OP_0'), Script('OP_1')); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_CODESEPARATOR'), Script('OP_1')); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script(''), Script('OP_DEPTH OP_0 OP_EQUAL')); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_1 OP_2'), Script('OP_2 OP_EQUALVERIFY OP_1 OP_EQUAL')); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('9 0x000000000000000010'), Script('')); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_15 OP_ADD OP_16 OP_EQUAL')); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_0'), Script('OP_IF OP_VER OP_ELSE OP_1 OP_ENDIF')); |
|||
verified.should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
var getFlags = function getFlags(flagstr) { |
|||
var flags = 0; |
|||
if (flagstr.indexOf('NONE') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_NONE; |
|||
} |
|||
if (flagstr.indexOf('P2SH') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_P2SH; |
|||
} |
|||
if (flagstr.indexOf('STRICTENC') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_STRICTENC; |
|||
} |
|||
if (flagstr.indexOf('DERSIG') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_DERSIG; |
|||
} |
|||
if (flagstr.indexOf('LOW_S') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_LOW_S; |
|||
} |
|||
if (flagstr.indexOf('NULLDUMMY') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_NULLDUMMY; |
|||
} |
|||
if (flagstr.indexOf('SIGPUSHONLY') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_SIGPUSHONLY; |
|||
} |
|||
if (flagstr.indexOf('MINIMALDATA') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_MINIMALDATA; |
|||
} |
|||
if (flagstr.indexOf('DISCOURAGE_UPGRADABLE_NOPS') !== -1) { |
|||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS; |
|||
} |
|||
return flags; |
|||
}; |
|||
|
|||
|
|||
var testToFromString = function(script) { |
|||
var s = script.toString(); |
|||
Script.fromString(s).toString().should.equal(s); |
|||
}; |
|||
|
|||
var testFixture = function(vector, expected) { |
|||
var scriptSig = Script.fromBitcoindString(vector[0]); |
|||
var scriptPubkey = Script.fromBitcoindString(vector[1]); |
|||
var flags = getFlags(vector[2]); |
|||
|
|||
|
|||
//testToFromString(scriptSig);
|
|||
//testToFromString(scriptPubkey);
|
|||
|
|||
var hashbuf = new Buffer(32); |
|||
hashbuf.fill(0); |
|||
var credtx = Transaction(); |
|||
credtx.inputs.push(new Transaction.Input({ |
|||
prevTxId: '0000000000000000000000000000000000000000000000000000000000000000', |
|||
outputIndex: 0xffffffff, |
|||
sequenceNumber: 0xffffffff, |
|||
script: Script('OP_0 OP_0') |
|||
})); |
|||
credtx._addOutput(new Transaction.Output({ |
|||
script: scriptPubkey, |
|||
satoshis: 0 |
|||
})); |
|||
var idbuf = credtx.id; |
|||
|
|||
var spendtx = Transaction(); |
|||
spendtx.inputs.push(new Transaction.Input({ |
|||
prevTxId: idbuf.toString('hex'), |
|||
outputIndex: 0, |
|||
sequenceNumber: 0xffffffff, |
|||
script: scriptSig |
|||
})); |
|||
spendtx._addOutput(new Transaction.Output({ |
|||
script: Script(), |
|||
satoshis: 0 |
|||
})); |
|||
|
|||
var interp = ScriptInterpreter(); |
|||
var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags); |
|||
verified.should.equal(expected); |
|||
}; |
|||
describe('bitcoind fixtures', function() { |
|||
var testAllFixtures = function(set, expected) { |
|||
var c = 0; |
|||
set.forEach(function(vector) { |
|||
if (vector.length === 1) { |
|||
return; |
|||
} |
|||
c++; |
|||
var descstr = vector[3]; |
|||
var fullScriptString = vector[0] + ' ' + vector[1]; |
|||
var comment = descstr ? (' (' + descstr + ')') : ''; |
|||
it('should pass script_' + (expected ? '' : 'in') + 'valid vector #' + c + ': ' + fullScriptString + comment, function() { |
|||
testFixture(vector, expected); |
|||
}); |
|||
}); |
|||
}; |
|||
testAllFixtures(script_valid, true); |
|||
testAllFixtures(script_invalid, false); |
|||
|
|||
var c = 0; |
|||
tx_valid.forEach(function(vector) { |
|||
if (vector.length === 1) { |
|||
return; |
|||
} |
|||
c++; |
|||
it.skip('should pass tx_valid vector ' + c, function() { |
|||
var inputs = vector[0]; |
|||
var txhex = vector[1]; |
|||
var flags = getFlags(vector[2]); |
|||
|
|||
var map = {}; |
|||
inputs.forEach(function(input) { |
|||
var txid = input[0]; |
|||
var txoutnum = input[1]; |
|||
var scriptPubKeyStr = input[2]; |
|||
if (txoutnum === -1) { |
|||
txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int
|
|||
} |
|||
var txkey = txid + ':' + txoutnum; |
|||
map[txkey] = Script.fromBitcoindString(scriptPubKeyStr); |
|||
}); |
|||
|
|||
var tx = Transaction(txhex); |
|||
tx.inputs.forEach(function(txin, j) { |
|||
var scriptSig = txin.script; |
|||
var txidhex = txin.prevTxId.toString('hex'); |
|||
var txoutnum = txin.outputIndex; |
|||
var txkey = txidhex + ':' + txoutnum; |
|||
var scriptPubkey = map[txkey]; |
|||
should.exist(scriptPubkey); |
|||
var interp = ScriptInterpreter(); |
|||
var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags); |
|||
verified.should.equal(true); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
c = 0; |
|||
tx_invalid.forEach(function(vector) { |
|||
if (vector.length === 1) { |
|||
return; |
|||
} |
|||
c++; |
|||
|
|||
// tests intentionally not performed by the script interpreter:
|
|||
// TODO: check this?
|
|||
/* |
|||
if (c === 7 || // tests if valuebn is negative
|
|||
c === 8 || // tests if valuebn is greater than MAX_MONEY
|
|||
c === 10 || // tests if two inputs are equal
|
|||
c === 11 || // coinbase
|
|||
c === 12 || // coinbase
|
|||
c === 13 // null input
|
|||
) { |
|||
return; |
|||
} |
|||
*/ |
|||
|
|||
it.skip('should pass tx_invalid vector ' + c, function() { |
|||
var inputs = vector[0]; |
|||
var txhex = vector[1]; |
|||
var flags = getFlags(vector[2]); |
|||
|
|||
var map = {}; |
|||
inputs.forEach(function(input) { |
|||
var txoutnum = input[1]; |
|||
if (txoutnum === -1) { |
|||
txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int
|
|||
} |
|||
map[input[0] + ':' + txoutnum] = Script.fromBitcoindString(input[2]); |
|||
}); |
|||
|
|||
var tx = Transaction().fromBuffer(new Buffer(txhex, 'hex')); |
|||
if (tx.txins.length > 0) { |
|||
tx.txins.some(function(txin, j) { |
|||
var scriptSig = txin.script; |
|||
var txidhex = BufferReader(txin.txidbuf).readReverse().toString('hex'); |
|||
var txoutnum = txin.txoutnum; |
|||
var scriptPubkey = map[txidhex + ':' + txoutnum]; |
|||
should.exist(scriptPubkey); |
|||
var interp = ScriptInterpreter(); |
|||
var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags); |
|||
return verified === false; |
|||
}).should.equal(true); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
Loading…
Reference in new issue