fcoin/test/script-test.js
Christopher Jeffrey b9c7afa0ea
coin.fromTX.
2016-05-18 05:12:28 -07:00

512 lines
14 KiB
JavaScript

var bcoin = require('../').set('main');
var assert = require('assert');
var Script = bcoin.script;
var Stack = bcoin.stack;
var utils = bcoin.utils;
var constants = bcoin.protocol.constants;
var opcodes = bcoin.protocol.constants.opcodes;
var scripts = require('./data/script_tests');
var bn = require('bn.js');
describe('Script', function() {
it('should encode/decode script', function() {
var src = '20'
+ '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'
+ '20'
+ '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f'
+ 'ac';
var decoded = bcoin.script.decode(new Buffer(src, 'hex'));
assert.equal(decoded.length, 3);
assert.equal(decoded[0].toString('hex'),
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');
assert.equal(decoded[1].toString('hex'),
'101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f');
assert.equal(decoded[2], opcodes.OP_CHECKSIG);
var dst = bcoin.script.encode(decoded);
assert.equal(dst.toString('hex'), src);
});
it('should encode/decode numbers', function() {
var script = [0, 0x51, 0x52, 0x60];
var encoded = bcoin.script.encode(script);
var decoded = bcoin.script.decode(encoded);
assert.deepEqual(decoded, script);
});
it('should recognize a P2SH output', function() {
var hex = 'a91419a7d869032368fd1f1e26e5e73a4ad0e474960e87';
var decoded = bcoin.script.fromRaw(hex, 'hex');
assert(decoded.isScripthash());
});
it('should recognize a Null Data output', function() {
var hex = '6a28590c080112220a1b353930632e6f7267282a5f'
+ '5e294f7665726c6179404f7261636c65103b1a010c';
var decoded = bcoin.script.fromRaw(hex, 'hex');
assert(decoded.isNulldata());
});
it('should handle if statements correctly', function() {
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([
opcodes.OP_2,
opcodes.OP_EQUAL,
opcodes.OP_IF,
opcodes.OP_3,
opcodes.OP_ELSE,
opcodes.OP_4,
opcodes.OP_ENDIF,
opcodes.OP_5
]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([
opcodes.OP_9,
opcodes.OP_EQUAL,
opcodes.OP_IF,
opcodes.OP_3,
opcodes.OP_ELSE,
opcodes.OP_4,
opcodes.OP_ENDIF,
opcodes.OP_5
]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [4], [5]]);
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([
opcodes.OP_2,
opcodes.OP_EQUAL,
opcodes.OP_IF,
opcodes.OP_3,
opcodes.OP_ENDIF,
opcodes.OP_5
]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([
opcodes.OP_9,
opcodes.OP_EQUAL,
opcodes.OP_IF,
opcodes.OP_3,
opcodes.OP_ENDIF,
opcodes.OP_5
]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [5]]);
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([
opcodes.OP_9,
opcodes.OP_EQUAL,
opcodes.OP_NOTIF,
opcodes.OP_3,
opcodes.OP_ENDIF,
opcodes.OP_5
]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
});
function success(res, stack) {
if (!res)
return false;
if (stack.length === 0)
return false;
if (!bcoin.script.bool(stack.pop()))
return false;
return true;
}
it('should handle bad size pushes correctly.', function() {
var err;
var stack = new bcoin.stack();
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA1'
);
assert(utils.equal(s.raw, new Buffer('51764c', 'hex')));
delete s.raw;
assert(utils.equal(s.encode(), new Buffer('51764c', 'hex')));
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA2 0x01'
);
assert(utils.equal(s.raw, new Buffer('51764d01', 'hex')));
delete s.raw;
assert(utils.equal(s.encode(), new Buffer('51764d01', 'hex')));
err = null;
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA4 0x0001'
);
assert(utils.equal(s.raw, new Buffer('51764e0001', 'hex')));
delete s.raw;
assert(utils.equal(s.encode(), new Buffer('51764e0001', 'hex')));
err = null;
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA1 0x02 0x01'
);
assert(utils.equal(s.raw, new Buffer('51764c0201', 'hex')));
delete s.raw;
assert(utils.equal(s.encode(), new Buffer('51764c0201', 'hex')));
err = null;
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA2 0x0200 0x01'
);
assert(utils.equal(s.raw, new Buffer('51764d020001', 'hex')));
delete s.raw;
assert(utils.equal(s.encode(), new Buffer('51764d020001', 'hex')));
err = null;
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
});
it('should handle CScriptNums correctly', function() {
var s = new bcoin.script([
new Buffer([0xff, 0xff, 0xff, 0x7f]),
opcodes.OP_NEGATE,
opcodes.OP_DUP,
opcodes.OP_ADD
]);
var s2 = new bcoin.script([
new Buffer([0xfe, 0xff, 0xff, 0xff, 0x80]),
opcodes.OP_EQUAL
]);
var stack = new bcoin.stack();
assert(s.execute(stack));
assert(success(s2.execute(stack), stack));
});
it('should handle CScriptNums correctly', function() {
var s = new bcoin.script([
opcodes.OP_11,
opcodes.OP_10,
opcodes.OP_1,
opcodes.OP_ADD
]);
var s2 = new bcoin.script([
opcodes.OP_NUMNOTEQUAL,
opcodes.OP_NOT
]);
var stack = new bcoin.stack();
assert(s.execute(stack));
assert(success(s2.execute(stack), stack));
});
it('should handle OP_ROLL correctly', function() {
var s = new bcoin.script([
new Buffer([0x16]),
new Buffer([0x15]),
new Buffer([0x14])
]);
var s2 = new bcoin.script([
opcodes.OP_0,
opcodes.OP_ROLL,
new Buffer([0x14]),
opcodes.OP_EQUALVERIFY,
opcodes.OP_DEPTH,
opcodes.OP_2,
opcodes.OP_EQUAL
]);
var stack = new bcoin.stack();
assert(s.execute(stack));
assert(success(s2.execute(stack), stack));
});
scripts.forEach(function(data) {
// ["Format is: [[wit...]?, scriptSig, scriptPubKey, flags, expected_scripterror, ... comments]"],
var witness = Array.isArray(data[0]) ? data.shift() : null;
var input = data[0] ? data[0].trim() : data[0] || '';
var output = data[1] ? data[1].trim() : data[1] || '';
var flags = data[2] ? data[2].trim().split(/,\s*/) : [];
var expected = data[3] || '';
var comments = Array.isArray(data[4]) ? data[4].join('. ') : data[4] || '';
if (data.length === 1)
return;
if (!comments)
comments = output.slice(0, 60);
comments += ' (' + expected + ')';
witness = bcoin.witness.fromString(witness);
input = bcoin.script.fromString(input);
output = bcoin.script.fromString(output);
var flag = 0;
for (var i = 0; i < flags.length; i++) {
flag |= constants.flags['VERIFY_' + flags[i]];
}
flags = flag;
[false, true].forEach(function(nocache) {
var suffix = nocache ? ' without cache' : ' with cache';
it('should handle script test' + suffix + ': ' + comments, function() {
var coin = bcoin.tx({
version: 1,
inputs: [{
prevout: {
hash: constants.NULL_HASH,
index: 0xffffffff
},
coin: null,
script: [bcoin.script.array(0), bcoin.script.array(0)],
witness: new bcoin.witness(),
sequence: 0xffffffff
}],
outputs: [{
script: output,
value: 0
}],
locktime: 0
});
var tx = bcoin.tx({
version: 1,
inputs: [{
prevout: {
hash: coin.hash('hex'),
index: 0
},
coin: bcoin.coin.fromTX(coin, 0),
script: input,
witness: witness,
sequence: 0xffffffff
}],
outputs: [{
script: new bcoin.script(),
value: 0
}],
locktime: 0
});
if (nocache) {
delete input.raw;
delete input.redeem;
delete input._address;
delete output.raw;
delete output._address;
}
var err, res;
try {
res = Script.verify(input, witness, output, tx, 0, flags);
} catch (e) {
err = e;
}
if (expected !== 'OK') {
assert(!res);
assert(err);
assert.equal(err.code, expected);
return;
}
utils.assert.ifError(err);
assert(res);
});
});
});
it('should execute FindAndDelete correctly', function() {
var s, d, expect;
function del(s) {
s.mutable = true;
delete s.raw;
return s;
}
s = bcoin.script.fromString('OP_1 OP_2');
del(s);
d = new bcoin.script();
expect = s.clone();
assert.equal(s.findAndDelete(d.encode()), 0);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromString('OP_1 OP_2 OP_3');
del(s);
d = bcoin.script.fromString('OP_2');
del(d);
expect = bcoin.script.fromString('OP_1 OP_3');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromString('OP_3 OP_1 OP_3 OP_3 OP_4 OP_3');
del(s);
d = bcoin.script.fromString('OP_3');
del(d);
expect = bcoin.script.fromString('OP_1 OP_4');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 4);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('0302ff03', 'hex');
del(d);
expect = new bcoin.script();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('0302ff03', 'hex');
del(d);
expect = new bcoin.script();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 2);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('02', 'hex');
del(d);
expect = s.clone();
del(expect);
//assert.equal(s.findAndDelete(d.encode()), 0);
s.findAndDelete(d.encode());
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('ff', 'hex');
del(d);
expect = s.clone();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 0);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('03', 'hex');
del(d);
expect = new bcoin.script([new Buffer([0xff, 0x03]), new Buffer([0xff, 0x03])]);
del(expect);
assert.equal(s.findAndDelete(d.encode()), 2);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('02feed5169', 'hex');
del(s);
d = bcoin.script.fromRaw('feed51', 'hex');
del(d);
expect = s.clone();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 0);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('02feed5169', 'hex');
del(s);
d = bcoin.script.fromRaw('02feed51', 'hex');
del(d);
expect = bcoin.script.fromRaw('69', 'hex');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('516902feed5169', 'hex');
del(s);
d = bcoin.script.fromRaw('feed51', 'hex');
del(d);
expect = s.clone();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 0);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('516902feed5169', 'hex');
del(s);
d = bcoin.script.fromRaw('02feed51', 'hex');
del(d);
expect = bcoin.script.fromRaw('516969', 'hex');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromString('OP_0 OP_0 OP_1 OP_1');
del(s);
d = bcoin.script.fromString('OP_0 OP_1');
del(d);
expect = bcoin.script.fromString('OP_0 OP_1');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromString('OP_0 OP_0 OP_1 OP_0 OP_1 OP_1');
del(s);
d = bcoin.script.fromString('OP_0 OP_1');
del(d);
expect = bcoin.script.fromString('OP_0 OP_1');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 2);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0003feed', 'hex');
del(s);
d = bcoin.script.fromRaw('03feed', 'hex');
del(d);
expect = bcoin.script.fromRaw('00', 'hex');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0003feed', 'hex');
del(s);
d = bcoin.script.fromRaw('00', 'hex');
del(d);
expect = bcoin.script.fromRaw('03feed', 'hex');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
});
});