some Transaction tests fixed (canonical signatures)

This commit is contained in:
Manuel Araoz 2014-03-20 15:11:58 -03:00 committed by MattFaus
parent 7869308784
commit b227341c12
5 changed files with 238 additions and 178 deletions

View File

@ -1,12 +1,12 @@
var imports = require('soop').imports();
var config = imports.config || require('./config');
var log = imports.log || require('./util/log');
var util = imports.util || require('./util/util');
var Opcode = imports.Opcode || require('./Opcode');
var imports = require('soop').imports();
var config = imports.config || require('./config');
var log = imports.log || require('./util/log');
var util = imports.util || require('./util/util');
var Opcode = imports.Opcode || require('./Opcode');
var buffertools = imports.buffertools || require('buffertools');
var bignum = imports.bignum || require('bignum');
var Util = imports.Util || require('./util/util');
var Script = require('./Script');
var bignum = imports.bignum || require('bignum');
var Util = imports.Util || require('./util/util');
var Script = require('./Script');
var SIGHASH_ALL = 1;
var SIGHASH_NONE = 2;
@ -21,7 +21,8 @@ for (var i in Opcode.map) {
var intToBufferSM = Util.intToBufferSM
var bufferSMToInt = Util.bufferSMToInt;
function ScriptInterpreter() {
function ScriptInterpreter(opts) {
this.opts = opts || {};
this.stack = [];
this.disableUnsafeOpcodes = true;
};
@ -98,8 +99,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
if (exec && Buffer.isBuffer(opcode)) {
this.stack.push(opcode);
}
else if (exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
} else if (exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
switch (opcode) {
case OP_0:
this.stack.push(new Buffer([]));
@ -411,10 +411,13 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
this.stackPop();
this.stackPop();
this.stack.push(new Buffer([value ? 1 : 0]));
console.log(script.toHumanReadable());
if (opcode === OP_EQUALVERIFY) {
if (value) {
this.stackPop();
} else {
console.log(v1);
console.log(v2);
throw new Error("OP_EQUALVERIFY negative");
}
}
@ -621,7 +624,7 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
scriptCode.findAndDelete(sig);
//
isCanonicalSignature(new Buffer(sig));
this.isCanonicalSignature(new Buffer(sig));
// Verify signature
checkSig(sig, pubkey, scriptCode, tx, inIndex, hashType, function(e, result) {
@ -695,8 +698,9 @@ ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType,
var scriptCode = Script.fromChunks(scriptChunks);
// Drop the signatures, since a signature can't sign itself
var that = this;
sigs.forEach(function(sig) {
isCanonicalSignature(new Buffer(sig));
that.isCanonicalSignature(new Buffer(sig));
scriptCode.findAndDelete(sig);
});
@ -811,7 +815,7 @@ ScriptInterpreter.prototype.stackTop = function stackTop(offset) {
};
ScriptInterpreter.prototype.stackBack = function stackBack() {
return this.stack[this.stack.length -1];
return this.stack[this.stack.length - 1];
};
/**
@ -882,6 +886,7 @@ ScriptInterpreter.prototype.getResult = function getResult() {
return castBool(this.stack[this.stack.length - 1]);
};
// Use ScriptInterpreter.verifyFull instead
ScriptInterpreter.verify =
function verify(scriptSig, scriptPubKey, txTo, n, hashType, callback) {
if ("function" !== typeof callback) {
@ -912,8 +917,8 @@ ScriptInterpreter.verify =
return si;
};
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy) {
ScriptInterpreter.prototype.verifyStep4 = function(scriptSig, scriptPubKey,
txTo, nIn, hashType, callback, siCopy) {
if (siCopy.stack.length == 0) {
callback(null, false);
return;
@ -922,19 +927,19 @@ function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
callback(null, castBool(siCopy.stackBack()));
}
function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy) {
if (si.stack.length == 0) {
ScriptInterpreter.prototype.verifyStep3 = function(scriptSig,
scriptPubKey, txTo, nIn, hashType, callback, siCopy) {
if (this.stack.length == 0) {
callback(null, false);
return;
}
if (castBool(si.stackBack()) == false) {
if (castBool(this.stackBack()) == false) {
callback(null, false);
return;
}
// if not P2SH, we're done
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
if (!this.opts.verifyP2SH || !scriptPubKey.isP2SH()) {
callback(null, true);
return;
}
@ -949,46 +954,48 @@ function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
var subscript = new Script(siCopy.stackPop());
ok = true;
var that = this;
siCopy.eval(subscript, txTo, nIn, hashType, function(err) {
if (err)
callback(err);
else
verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
if (err) callback(err);
else that.verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, callback, siCopy);
});
}
};
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy) {
if (opts.verifyP2SH) {
si.stack.forEach(function(item) {
ScriptInterpreter.prototype.verifyStep2 = function(scriptSig, scriptPubKey,
txTo, nIn, hashType, callback, siCopy) {
if (this.opts.verifyP2SH) {
this.stack.forEach(function(item) {
siCopy.stack.push(item);
});
}
si.eval(scriptPubKey, txTo, nIn, hashType, function(err) {
if (err)
callback(err);
else
verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
var that = this;
this.eval(scriptPubKey, txTo, nIn, hashType, function(err) {
if (err) callback(err);
else that.verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, callback, siCopy);
});
}
};
ScriptInterpreter.verifyFull =
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
opts, callback) {
var si = new ScriptInterpreter();
var siCopy = new ScriptInterpreter();
var si = new ScriptInterpreter(opts);
si.verifyFull(scriptSig, scriptPubKey,
txTo, nIn, hashType, callback);
};
ScriptInterpreter.prototype.verifyFull = function(scriptSig, scriptPubKey,
txTo, nIn, hashType, callback) {
var siCopy = new ScriptInterpreter(this.opts);
var that = this;
this.eval(scriptSig, txTo, nIn, hashType, function(err) {
if (err) callback(err);
else that.verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, callback, siCopy);
});
si.eval(scriptSig, txTo, nIn, hashType, function(err) {
if (err)
callback(err);
else
verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
};
var checkSig = ScriptInterpreter.checkSig =
@ -1019,68 +1026,70 @@ var checkSig = ScriptInterpreter.checkSig =
}
};
var isCanonicalSignature = ScriptInterpreter.isCanonicalSignature = function(sig, opts) {
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
// Where R and S are not negative (their first byte has its highest bit not set), and not
// excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
// in which case a single 0 byte is necessary and even required).
if (!Buffer.isBuffer(sig))
throw new Error("arg should be a Buffer");
ScriptInterpreter.prototype.isCanonicalSignature = function(sig) {
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
// Where R and S are not negative (their first byte has its highest bit not set), and not
// excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
// in which case a single 0 byte is necessary and even required).
opts = opts || {};
if (!Buffer.isBuffer(sig))
throw new Error("arg should be a Buffer");
var l = sig.length;
if (l < 9) throw new Error("Non-canonical signature: too short");
if (l > 73) throw new Error("Non-canonical signature: too long");
// TODO: change to opts.verifyStrictEnc to make the default
// behavior not verify, as in bitcoin core
if (this.opts.dontVerifyStrictEnc) return true;
var nHashType = sig[l-1] & (~(SIGHASH_ANYONECANPAY));
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
throw new Error("Non-canonical signature: unknown hashtype byte");
var l = sig.length;
if (l < 9) throw new Error("Non-canonical signature: too short");
if (l > 73) throw new Error("Non-canonical signature: too long");
if (sig[0] !== 0x30)
throw new Error("Non-canonical signature: wrong type");
if (sig[1] !== l-3)
throw new Error("Non-canonical signature: wrong length marker");
var nHashType = sig[l - 1] & (~(SIGHASH_ANYONECANPAY));
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
throw new Error("Non-canonical signature: unknown hashtype byte");
var nLenR = sig[3];
if (5 + nLenR >= l)
throw new Error("Non-canonical signature: S length misplaced");
if (sig[0] !== 0x30)
throw new Error("Non-canonical signature: wrong type");
if (sig[1] !== l - 3)
throw new Error("Non-canonical signature: wrong length marker");
var nLenS = sig[5+nLenR];
if ( (nLenR+nLenS+7) !== l)
throw new Error("Non-canonical signature: R+S length mismatch");
var rPos = 4;
var R = new Buffer(nLenR);
sig.copy(R, 0, rPos, rPos+ nLenR);
if (sig[rPos-2] !== 0x02)
throw new Error("Non-canonical signature: R value type mismatch");
if (nLenR == 0)
throw new Error("Non-canonical signature: R length is zero");
if (R[0] & 0x80)
throw new Error("Non-canonical signature: R value negative");
if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80))
throw new Error("Non-canonical signature: R value excessively padded");
var nLenR = sig[3];
if (5 + nLenR >= l)
throw new Error("Non-canonical signature: S length misplaced");
var sPos = 6 + nLenR;
var S = new Buffer(nLenS);
sig.copy(S, 0, sPos, sPos+ nLenS);
if (sig[sPos-2] != 0x02)
throw new Error("Non-canonical signature: S value type mismatch");
if (nLenS == 0)
throw new Error("Non-canonical signature: S length is zero");
if (S[0] & 0x80)
throw new Error("Non-canonical signature: S value negative");
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80))
throw new Error("Non-canonical signature: S value excessively padded");
var nLenS = sig[5 + nLenR];
if ((nLenR + nLenS + 7) !== l)
throw new Error("Non-canonical signature: R+S length mismatch");
if (opts.verifyEvenS) {
if (S[nLenS-1] & 1)
throw new Error("Non-canonical signature: S value odd");
}
return true;
var rPos = 4;
var R = new Buffer(nLenR);
sig.copy(R, 0, rPos, rPos + nLenR);
if (sig[rPos - 2] !== 0x02)
throw new Error("Non-canonical signature: R value type mismatch");
if (nLenR == 0)
throw new Error("Non-canonical signature: R length is zero");
if (R[0] & 0x80)
throw new Error("Non-canonical signature: R value negative");
if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80))
throw new Error("Non-canonical signature: R value excessively padded");
var sPos = 6 + nLenR;
var S = new Buffer(nLenS);
sig.copy(S, 0, sPos, sPos + nLenS);
if (sig[sPos - 2] != 0x02)
throw new Error("Non-canonical signature: S value type mismatch");
if (nLenS == 0)
throw new Error("Non-canonical signature: S length is zero");
if (S[0] & 0x80)
throw new Error("Non-canonical signature: S value negative");
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80))
throw new Error("Non-canonical signature: S value excessively padded");
if (this.opts.verifyEvenS) {
if (S[nLenS - 1] & 1)
throw new Error("Non-canonical signature: S value odd");
}
return true;
};
module.exports = require('soop')(ScriptInterpreter);

View File

@ -259,10 +259,10 @@ Transaction.prototype.verify = function verify(txCache, blockChain, callback) {
}
return txout;
};
}
Step(
function verifyInputs() {
function verifyInputs(opts) {
var group = this.group();
if (self.isCoinBase()) {
@ -278,7 +278,7 @@ Transaction.prototype.verify = function verify(txCache, blockChain, callback) {
outpoints.push(txin.o);
self.verifyInput(n, txout.getScript(), group());
self.verifyInput(n, txout.getScript(), opts, group());
});
},
@ -351,11 +351,14 @@ Transaction.prototype.verify = function verify(txCache, blockChain, callback) {
);
};
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) {
return ScriptInterpreter.verify(this.ins[n].getScript(),
scriptPubKey,
this, n, 0,
callback);
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, opts, callback) {
var valid = ScriptInterpreter.verifyFull(
this.ins[n].getScript(),
scriptPubKey,
this, n, 0,
opts,
callback);
return valid;
};
/**

View File

@ -81,9 +81,10 @@ describe('ScriptInterpreter', function() {
isHex = 1;
} catch (e) {}
if (isHex)
ScriptInterpreter.isCanonicalSignature.bind(sig).should.
throw ();
// ignore non-hex strings
if (isHex) {
ScriptInterpreter.isCanonicalSignature.bind(sig).should.throw();
}
});
});

View File

@ -6,8 +6,7 @@ var bitcore = bitcore || require('../bitcore');
var should = chai.should();
var TransactionModule = bitcore.Transaction;
var Transaction;
var Transaction = bitcore.Transaction;
var In;
var Out;
var Script = bitcore.Script;
@ -40,7 +39,7 @@ function parse_test_transaction(entry) {
});
var raw = new Buffer(entry[1], 'hex');
var tx = new TransactionModule();
var tx = new Transaction();
tx.parse(raw);
// Sanity check transaction has been parsed correctly
@ -53,10 +52,6 @@ function parse_test_transaction(entry) {
describe('Transaction', function() {
it('should initialze the main object', function() {
should.exist(TransactionModule);
});
it('should be able to create class', function() {
Transaction = TransactionModule;
should.exist(Transaction);
In = Transaction.In;
Out = Transaction.Out;
@ -72,7 +67,7 @@ describe('Transaction', function() {
it('#selectUnspent should be able to select utxos', function() {
var u = Transaction.selectUnspent(testdata.dataUnspent,1.0, true);
var u = Transaction.selectUnspent(testdata.dataUnspent, 1.0, true);
u.length.should.equal(3);
should.exist(u[0].amount);
@ -80,37 +75,37 @@ describe('Transaction', function() {
should.exist(u[0].scriptPubKey);
should.exist(u[0].vout);
u = Transaction.selectUnspent(testdata.dataUnspent,0.5, true);
u = Transaction.selectUnspent(testdata.dataUnspent, 0.5, true);
u.length.should.equal(3);
u = Transaction.selectUnspent(testdata.dataUnspent,0.1, true);
u = Transaction.selectUnspent(testdata.dataUnspent, 0.1, true);
u.length.should.equal(2);
u = Transaction.selectUnspent(testdata.dataUnspent,0.05, true);
u = Transaction.selectUnspent(testdata.dataUnspent, 0.05, true);
u.length.should.equal(2);
u = Transaction.selectUnspent(testdata.dataUnspent,0.015, true);
u = Transaction.selectUnspent(testdata.dataUnspent, 0.015, true);
u.length.should.equal(2);
u = Transaction.selectUnspent(testdata.dataUnspent,0.01, true);
u = Transaction.selectUnspent(testdata.dataUnspent, 0.01, true);
u.length.should.equal(1);
});
it('#selectUnspent should return null if not enough utxos', function() {
var u = Transaction.selectUnspent(testdata.dataUnspent,1.12);
var u = Transaction.selectUnspent(testdata.dataUnspent, 1.12);
should.not.exist(u);
});
it('#selectUnspent should check confirmations', function() {
var u = Transaction.selectUnspent(testdata.dataUnspent,0.9);
var u = Transaction.selectUnspent(testdata.dataUnspent, 0.9);
should.not.exist(u);
var u = Transaction.selectUnspent(testdata.dataUnspent,0.9,true);
u = Transaction.selectUnspent(testdata.dataUnspent, 0.9, true);
u.length.should.equal(3);
var u = Transaction.selectUnspent(testdata.dataUnspent,0.11);
u = Transaction.selectUnspent(testdata.dataUnspent, 0.11);
u.length.should.equal(2);
var u = Transaction.selectUnspent(testdata.dataUnspent,0.111);
u = Transaction.selectUnspent(testdata.dataUnspent, 0.111);
should.not.exist(u);
});
@ -121,8 +116,11 @@ describe('Transaction', function() {
};
it('#create should be able to create instance', function() {
var utxos =testdata.dataUnspent;
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.08}];
var utxos = testdata.dataUnspent;
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.08
}];
var ret = Transaction.create(utxos, outs, opts);
should.exist(ret.tx);
@ -143,24 +141,35 @@ describe('Transaction', function() {
});
it('#create should fail if not enough inputs ', function() {
var utxos =testdata.dataUnspent;
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:80}];
var utxos = testdata.dataUnspent;
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 80
}];
Transaction
.create
.bind(utxos, outs, opts)
.should.throw();
.should.
throw ();
var outs2 = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.5}];
should.exist( Transaction.create(utxos, outs2, opts));
var outs2 = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.5
}];
should.exist(Transaction.create(utxos, outs2, opts));
// do not allow unconfirmed
Transaction.create.bind(utxos, outs2).should.throw();
Transaction.create.bind(utxos, outs2).should.
throw ();
});
it('#create should create same output as bitcoind createrawtransaction ', function() {
var utxos =testdata.dataUnspent;
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.08}];
var utxos = testdata.dataUnspent;
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.08
}];
var ret = Transaction.create(utxos, outs, opts);
var tx = ret.tx;
@ -170,10 +179,15 @@ describe('Transaction', function() {
});
it('#create should create same output as bitcoind createrawtransaction wo remainder', function() {
var utxos =testdata.dataUnspent;
var utxos = testdata.dataUnspent;
// no remainder
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.08}];
var ret = Transaction.create(utxos, outs, {fee:0.03} );
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.08
}];
var ret = Transaction.create(utxos, outs, {
fee: 0.03
});
var tx = ret.tx;
// string output generated from: bitcoind createrawtransaction '[{"txid": "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1","vout":1},{"txid":"2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc2","vout":0} ]' '{"mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE":0.08}'
@ -182,15 +196,21 @@ describe('Transaction', function() {
});
it('#createAndSign should sign a tx', function() {
var utxos =testdata.dataUnspentSign.unspent;
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.08}];
var utxos = testdata.dataUnspentSign.unspent;
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.08
}];
var ret = Transaction.createAndSign(utxos, outs, testdata.dataUnspentSign.keyStrings, opts);
var tx = ret.tx;
tx.isComplete().should.equal(true);
tx.ins.length.should.equal(1);
tx.outs.length.should.equal(2);
var outs2 = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:16}];
var outs2 = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 16
}];
var ret2 = Transaction.createAndSign(utxos, outs2, testdata.dataUnspentSign.keyStrings, opts);
var tx2 = ret2.tx;
tx2.isComplete().should.equal(true);
@ -200,8 +220,11 @@ describe('Transaction', function() {
it('#createAndSign should sign an incomplete tx ', function() {
var keys = ['cNpW8B7XPAzCdRR9RBWxZeveSNy3meXgHD8GuhcqUyDuy8ptCDzJ'];
var utxos =testdata.dataUnspentSign.unspent;
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.08}];
var utxos = testdata.dataUnspentSign.unspent;
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.08
}];
var ret = Transaction.createAndSign(utxos, outs, keys, opts);
var tx = ret.tx;
tx.ins.length.should.equal(1);
@ -209,8 +232,11 @@ describe('Transaction', function() {
});
it('#isComplete should return TX signature status', function() {
var keys = ['cNpW8B7XPAzCdRR9RBWxZeveSNy3meXgHD8GuhcqUyDuy8ptCDzJ'];
var utxos =testdata.dataUnspentSign.unspent;
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.08}];
var utxos = testdata.dataUnspentSign.unspent;
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.08
}];
var ret = Transaction.createAndSign(utxos, outs, keys, opts);
var tx = ret.tx;
tx.isComplete().should.equal(false);
@ -219,31 +245,37 @@ describe('Transaction', function() {
});
it('#sign should sign a tx in multiple steps (case1)', function() {
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:1.08}];
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 1.08
}];
var ret = Transaction.create(testdata.dataUnspentSign.unspent, outs, opts);
var tx = ret.tx;
var tx = ret.tx;
var selectedUtxos = ret.selectedUtxos;
var k1 = testdata.dataUnspentSign.keyStrings.slice(0,1);
var k1 = testdata.dataUnspentSign.keyStrings.slice(0, 1);
tx.isComplete().should.equal(false);
tx.sign(selectedUtxos, k1).should.equal(false);
var k23 = testdata.dataUnspentSign.keyStrings.slice(1,3);
var k23 = testdata.dataUnspentSign.keyStrings.slice(1, 3);
tx.sign(selectedUtxos, k23).should.equal(true);
tx.isComplete().should.equal(true);
});
it('#sign should sign a tx in multiple steps (case2)', function() {
var outs = [{address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:16}];
var outs = [{
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 16
}];
var ret = Transaction.create(testdata.dataUnspentSign.unspent, outs, opts);
var tx = ret.tx;
var tx = ret.tx;
var selectedUtxos = ret.selectedUtxos;
var k1 = testdata.dataUnspentSign.keyStrings.slice(0,1);
var k2 = testdata.dataUnspentSign.keyStrings.slice(1,2);
var k3 = testdata.dataUnspentSign.keyStrings.slice(2,3);
var k1 = testdata.dataUnspentSign.keyStrings.slice(0, 1);
var k2 = testdata.dataUnspentSign.keyStrings.slice(1, 2);
var k3 = testdata.dataUnspentSign.keyStrings.slice(2, 3);
tx.sign(selectedUtxos, k1).should.equal(false);
tx.sign(selectedUtxos, k2).should.equal(false);
tx.sign(selectedUtxos, k3).should.equal(true);
@ -253,11 +285,14 @@ describe('Transaction', function() {
it('#createAndSign: should generate dynamic fee and readjust (and not) the selected UTXOs', function() {
//this cases exceeds the input by 1mbtc AFTEr calculating the dynamic fee,
//so, it should trigger adding a new 10BTC utxo
var utxos =testdata.dataUnspentSign.unspent;
var utxos = testdata.dataUnspentSign.unspent;
var outs = [];
var n =101;
for (var i=0; i<n; i++) {
outs.push({address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.01});
var n = 101;
for (var i = 0; i < n; i++) {
outs.push({
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.01
});
}
var ret = Transaction.createAndSign(utxos, outs, testdata.dataUnspentSign.keyStrings, opts);
@ -275,15 +310,18 @@ describe('Transaction', function() {
//this is the complementary case, it does not trigger a new utxo
var utxos =testdata.dataUnspentSign.unspent;
var outs = [];
var n =100;
for (var i=0; i<n; i++) {
outs.push({address:'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', amount:0.01});
utxos = testdata.dataUnspentSign.unspent;
outs = [];
n = 100;
for (i = 0; i < n; i++) {
outs.push({
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
amount: 0.01
});
}
var ret = Transaction.createAndSign(utxos, outs, testdata.dataUnspentSign.keyStrings, opts);
var tx = ret.tx;
ret = Transaction.createAndSign(utxos, outs, testdata.dataUnspentSign.keyStrings, opts);
tx = ret.tx;
tx.getSize().should.equal(3485);
// ins = 1.0101 BTC (1 inputs: 1.0101);
@ -297,21 +335,30 @@ describe('Transaction', function() {
});
/*
* Bitcoin core transaction tests
*/
// Verify that known valid transactions are intepretted correctly
testdata.dataTxValid.forEach(function(datum) {
var testTx = parse_test_transaction(datum);
if (!testTx) return;
var verifyP2SH = datum[2];
var transactionString = buffertools.toHex(
testTx.transaction.serialize());
it.skip('valid tx=' + transactionString, function() {
it('valid tx=' + transactionString, function() {
// Verify that all inputs are valid
testTx.inputs.forEach(function(input) {
testTx.transaction.verifyInput(input.index, input.scriptPubKey,
testTx.transaction.verifyInput(
input.index,
input.scriptPubKey,
{ verifyP2SH: verifyP2SH, dontVerifyStrictEnc: true},
function(err, results) {
// Exceptions raised inside this function will be handled
// ...by this function, so ignore if that is the case
if (err && err.constructor.name === "AssertionError") return;
if (err && err.constructor.name === 'AssertionError') return;
should.not.exist(err);
should.exist(results);
@ -328,14 +375,14 @@ describe('Transaction', function() {
var transactionString = buffertools.toHex(
testTx.transaction.serialize());
it.skip('valid tx=' + transactionString, function() {
it('valid tx=' + transactionString, function() {
// Verify that all inputs are invalid
testTx.inputs.forEach(function(input) {
testTx.transaction.verifyInput(input.index, input.scriptPubKey,
function(err, results) {
// Exceptions raised inside this function will be handled
// ...by this function, so ignore if that is the case
if (err && err.constructor.name === "AssertionError") return;
if (err && err.constructor.name === 'AssertionError') return;
// There should either be an error, or the results should be false.
(err !== null || (!err && results === false)).should.equal(true);

View File

@ -15,8 +15,8 @@ var examples = [
];
describe('Examples', function() {
before(mute);
after(unmute);
//before(mute);
//after(unmute);
examples.forEach(function(example) {
it('valid '+example, function() {
var ex = require('../examples/'+example);