Manuel Araoz
10 years ago
5 changed files with 2929 additions and 6 deletions
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,303 @@ |
|||
'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 Sig = bitcore.crypto.Signature; |
|||
var BufferReader = bitcore.encoding.BufferReader; |
|||
|
|||
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'); |
|||
|
|||
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 or unverify these trivial scripts from script_valid.json', function() { |
|||
var verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_1'), Transaction(), 0); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_0'), Transaction(), 0); |
|||
verified.should.equal(false); |
|||
verified = ScriptInterpreter().verify(Script('OP_0'), Script('OP_1'), Transaction(), 0); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_CODESEPARATOR'), Script('OP_1'), Transaction(), 0); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script(''), Script('OP_DEPTH OP_0 OP_EQUAL'), Transaction(), 0); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_1 OP_2'), Script('OP_2 OP_EQUALVERIFY OP_1 OP_EQUAL'), Transaction(), 0); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('9 0x000000000000000010'), Script(''), Transaction(), 0); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_15 OP_ADD OP_16 OP_EQUAL'), Transaction(), 0); |
|||
verified.should.equal(true); |
|||
verified = ScriptInterpreter().verify(Script('OP_0'), Script('OP_IF OP_VER OP_ELSE OP_1 OP_ENDIF'), Transaction(), 0); |
|||
verified.should.equal(true); |
|||
}); |
|||
|
|||
it('should verify this new pay-to-pubkey script', function() { |
|||
var keypair = Keypair().fromRandom(); |
|||
var scriptPubkey = Script().writeBuffer(keypair.pubkey.toDER(true)).writeOp('OP_CHECKSIG'); |
|||
|
|||
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(); |
|||
spendtx.addTxin(idbuf, 0, Script(), 0xffffffff); |
|||
spendtx.addTxout(BN(0), Script()); |
|||
|
|||
var sig = spendtx.sign(keypair, Sig.SIGHASH_ALL, 0, scriptPubkey); |
|||
var scriptSig = Script().writeBuffer(sig.toTxFormat()); |
|||
spendtx.txins[0].setScript(scriptSig); |
|||
|
|||
var interp = ScriptInterpreter(); |
|||
var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0); |
|||
verified.should.equal(true); |
|||
}); |
|||
|
|||
it('should verify this pay-to-pubkey script from script_valid.json', function() { |
|||
var scriptSig = Script().fromBitcoindString('0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501'); |
|||
var scriptPubkey = Script().fromBitcoindString('0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG'); |
|||
|
|||
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(); |
|||
spendtx.addTxin(idbuf, 0, scriptSig, 0xffffffff); |
|||
spendtx.addTxout(BN(0), Script()); |
|||
|
|||
var interp = ScriptInterpreter(); |
|||
var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, 0); |
|||
verified.should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('vectors', function() { |
|||
|
|||
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 c = 0; |
|||
script_valid.forEach(function(vector) { |
|||
if (vector.length === 1) { |
|||
return; |
|||
} |
|||
c++; |
|||
var descstr = vector[3]; |
|||
it('should pass script_valid vector ' + c + '(' + descstr + ')', function() { |
|||
var scriptSig = Script().fromBitcoindString(vector[0]); |
|||
var scriptPubkey = Script().fromBitcoindString(vector[1]); |
|||
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(); |
|||
spendtx.addTxin(idbuf, 0, scriptSig, 0xffffffff); |
|||
spendtx.addTxout(BN(0), Script()); |
|||
|
|||
var interp = ScriptInterpreter(); |
|||
var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags); |
|||
verified.should.equal(true); |
|||
}); |
|||
}); |
|||
|
|||
c = 0; |
|||
script_invalid.forEach(function(vector) { |
|||
if (vector.length === 1) { |
|||
return; |
|||
} |
|||
c++; |
|||
var descstr = vector[3]; |
|||
it('should pass script_invalid vector ' + c + '(' + descstr + ')', function() { |
|||
var scriptSig = Script().fromBitcoindString(vector[0]); |
|||
var scriptPubkey = Script().fromBitcoindString(vector[1]); |
|||
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(); |
|||
spendtx.addTxin(idbuf, 0, scriptSig, 0xffffffff); |
|||
spendtx.addTxout(BN(0), Script()); |
|||
|
|||
var interp = ScriptInterpreter(); |
|||
var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags); |
|||
verified.should.equal(false); |
|||
}); |
|||
}); |
|||
|
|||
c = 0; |
|||
tx_valid.forEach(function(vector) { |
|||
if (vector.length === 1) { |
|||
return; |
|||
} |
|||
c++; |
|||
it('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 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')); |
|||
tx.txins.forEach(function(txin, j) { |
|||
var scriptSig = txin.script; |
|||
var txidhex = BufR(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); |
|||
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('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 = BufR(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