remove txobj from this! #merge WIP
This commit is contained in:
parent
185ebe8ebb
commit
52d47bf30e
|
@ -94,12 +94,7 @@ var FEE_PER_1000B_SAT = parseInt(0.0001 * util.COIN);
|
||||||
|
|
||||||
function TransactionBuilder(opts) {
|
function TransactionBuilder(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
this.txobj = {};
|
this.lockTime = opts.lockTime || 0;
|
||||||
this.txobj.version = 1;
|
|
||||||
this.txobj.lock_time = opts.lockTime || 0;
|
|
||||||
this.txobj.ins = [];
|
|
||||||
this.txobj.outs = [];
|
|
||||||
|
|
||||||
this.spendUnconfirmed = opts.spendUnconfirmed || false;
|
this.spendUnconfirmed = opts.spendUnconfirmed || false;
|
||||||
|
|
||||||
if (opts.fee || opts.feeSat) {
|
if (opts.fee || opts.feeSat) {
|
||||||
|
@ -265,12 +260,12 @@ TransactionBuilder.prototype._selectUnspent = function(neededAmountSat) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._setInputs = function() {
|
TransactionBuilder.prototype._setInputs = function(txobj) {
|
||||||
var ins = this.selectedUtxos;
|
var ins = this.selectedUtxos;
|
||||||
var l = ins.length;
|
var l = ins.length;
|
||||||
var valueInSat = bignum(0);
|
var valueInSat = bignum(0);
|
||||||
|
|
||||||
this.txobj.ins=[];
|
txobj.ins=[];
|
||||||
for (var i = 0; i < l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
valueInSat = valueInSat.add(util.parseValue(ins[i].amount));
|
valueInSat = valueInSat.add(util.parseValue(ins[i].amount));
|
||||||
|
|
||||||
|
@ -286,7 +281,7 @@ TransactionBuilder.prototype._setInputs = function() {
|
||||||
voutBuf.writeUInt32LE(vout, 0);
|
voutBuf.writeUInt32LE(vout, 0);
|
||||||
|
|
||||||
txin.o = Buffer.concat([hashReversed, voutBuf]);
|
txin.o = Buffer.concat([hashReversed, voutBuf]);
|
||||||
this.txobj.ins.push(txin);
|
txobj.ins.push(txin);
|
||||||
}
|
}
|
||||||
this.valueInSat = valueInSat;
|
this.valueInSat = valueInSat;
|
||||||
return this;
|
return this;
|
||||||
|
@ -309,7 +304,7 @@ TransactionBuilder.prototype._setFee = function(feeSat) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._setRemainder = function(remainderIndex) {
|
TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) {
|
||||||
|
|
||||||
if ( typeof this.valueInSat === 'undefined' ||
|
if ( typeof this.valueInSat === 'undefined' ||
|
||||||
typeof this.valueOutSat === 'undefined')
|
typeof this.valueOutSat === 'undefined')
|
||||||
|
@ -317,12 +312,12 @@ TransactionBuilder.prototype._setRemainder = function(remainderIndex) {
|
||||||
|
|
||||||
// add remainder (without modifying outs[])
|
// add remainder (without modifying outs[])
|
||||||
var remainderSat = this.valueInSat.sub(this.valueOutSat).sub(this.feeSat);
|
var remainderSat = this.valueInSat.sub(this.valueOutSat).sub(this.feeSat);
|
||||||
var l =this.txobj.outs.length;
|
var l =txobj.outs.length;
|
||||||
this.remainderSat = bignum(0);
|
this.remainderSat = bignum(0);
|
||||||
|
|
||||||
//remove old remainder?
|
//remove old remainder?
|
||||||
if (l > remainderIndex) {
|
if (l > remainderIndex) {
|
||||||
this.txobj.outs.pop();
|
txobj.outs.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainderSat.cmp(0) > 0) {
|
if (remainderSat.cmp(0) > 0) {
|
||||||
|
@ -333,18 +328,17 @@ TransactionBuilder.prototype._setRemainder = function(remainderIndex) {
|
||||||
v: value,
|
v: value,
|
||||||
s: script.getBuffer(),
|
s: script.getBuffer(),
|
||||||
};
|
};
|
||||||
this.txobj.outs.push(txout);
|
txobj.outs.push(txout);
|
||||||
this.remainderSat = remainderSat;
|
this.remainderSat = remainderSat;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._setFeeAndRemainder = function() {
|
TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
|
||||||
|
|
||||||
//starting size estimation
|
//starting size estimation
|
||||||
var size = 500, maxSizeK, remainderIndex = this.txobj.outs.length;
|
var size = 500, maxSizeK, remainderIndex = txobj.outs.length;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// based on https://en.bitcoin.it/wiki/Transaction_fees
|
// based on https://en.bitcoin.it/wiki/Transaction_fees
|
||||||
maxSizeK = parseInt(size / 1000) + 1;
|
maxSizeK = parseInt(size / 1000) + 1;
|
||||||
|
@ -355,12 +349,12 @@ TransactionBuilder.prototype._setFeeAndRemainder = function() {
|
||||||
var neededAmountSat = this.valueOutSat.add(feeSat);
|
var neededAmountSat = this.valueOutSat.add(feeSat);
|
||||||
|
|
||||||
this._selectUnspent(neededAmountSat)
|
this._selectUnspent(neededAmountSat)
|
||||||
._setInputs()
|
._setInputs(txobj)
|
||||||
._setFee(feeSat)
|
._setFee(feeSat)
|
||||||
._setRemainder(remainderIndex);
|
._setRemainder(txobj, remainderIndex);
|
||||||
|
|
||||||
|
|
||||||
size = new Transaction(this.txobj).getSize();
|
size = new Transaction(txobj).getSize();
|
||||||
} while (size > (maxSizeK + 1) * 1000);
|
} while (size > (maxSizeK + 1) * 1000);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -368,9 +362,13 @@ TransactionBuilder.prototype._setFeeAndRemainder = function() {
|
||||||
TransactionBuilder.prototype.setOutputs = function(outs) {
|
TransactionBuilder.prototype.setOutputs = function(outs) {
|
||||||
var valueOutSat = bignum(0);
|
var valueOutSat = bignum(0);
|
||||||
|
|
||||||
this.txobj.outs = [];
|
var txobj = {};
|
||||||
var l =outs.length;
|
txobj.version = 1;
|
||||||
|
txobj.lock_time = this.lockTime || 0;
|
||||||
|
txobj.ins = [];
|
||||||
|
txobj.outs = [];
|
||||||
|
|
||||||
|
var l =outs.length;
|
||||||
for (var i = 0; i < l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
var amountSat = outs[i].amountSat || util.parseValue(outs[i].amount);
|
var amountSat = outs[i].amountSat || util.parseValue(outs[i].amount);
|
||||||
var value = util.bigIntToValue(amountSat);
|
var value = util.bigIntToValue(amountSat);
|
||||||
|
@ -379,7 +377,7 @@ TransactionBuilder.prototype.setOutputs = function(outs) {
|
||||||
v: value,
|
v: value,
|
||||||
s: script.getBuffer(),
|
s: script.getBuffer(),
|
||||||
};
|
};
|
||||||
this.txobj.outs.push(txout);
|
txobj.outs.push(txout);
|
||||||
|
|
||||||
var sat = outs[i].amountSat || util.parseValue(outs[i].amount);
|
var sat = outs[i].amountSat || util.parseValue(outs[i].amount);
|
||||||
valueOutSat = valueOutSat.add(sat);
|
valueOutSat = valueOutSat.add(sat);
|
||||||
|
@ -387,9 +385,9 @@ TransactionBuilder.prototype.setOutputs = function(outs) {
|
||||||
|
|
||||||
this.valueOutSat = valueOutSat;
|
this.valueOutSat = valueOutSat;
|
||||||
|
|
||||||
this._setFeeAndRemainder();
|
this._setFeeAndRemainder(txobj);
|
||||||
|
|
||||||
this.tx = new Transaction(this.txobj);
|
this.tx = new Transaction(txobj);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -736,7 +734,6 @@ TransactionBuilder.prototype.toObj = function() {
|
||||||
spendUnconfirmed : this.spendUnconfirmed,
|
spendUnconfirmed : this.spendUnconfirmed,
|
||||||
|
|
||||||
inputMap : this.inputMap,
|
inputMap : this.inputMap,
|
||||||
txobj : this.txobj,
|
|
||||||
};
|
};
|
||||||
if (this.tx) {
|
if (this.tx) {
|
||||||
data.tx =this.tx.serialize().toString('hex');
|
data.tx =this.tx.serialize().toString('hex');
|
||||||
|
@ -762,18 +759,79 @@ TransactionBuilder.fromObj = function(data) {
|
||||||
b.spendUnconfirmed = data.spendUnconfirmed;
|
b.spendUnconfirmed = data.spendUnconfirmed;
|
||||||
|
|
||||||
b.inputMap = data.inputMap;
|
b.inputMap = data.inputMap;
|
||||||
b.txobj = data.txobj;
|
|
||||||
|
|
||||||
if (data.tx) {
|
if (data.tx) {
|
||||||
|
// Tx may have signatures, that are not on txobj
|
||||||
var t = new Transaction();
|
var t = new Transaction();
|
||||||
t.parse(new Buffer(data.tx,'hex'));
|
t.parse(new Buffer(data.tx,'hex'));
|
||||||
b.tx = t;
|
b.tx = t;
|
||||||
}
|
}
|
||||||
else if (b.txobj)
|
|
||||||
b.tx = new Transaction(b.txobj);
|
|
||||||
return b;
|
return b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TransactionBuilder.merge = function(b) {
|
||||||
|
// Builder should have the same params
|
||||||
|
['valueInSat', 'valueOutSat', 'feeSat', 'remainderSat', 'signhash', 'spendUnconfirmed']
|
||||||
|
.forEach(function (k) {
|
||||||
|
if (this[k] !== b[k])
|
||||||
|
throw new Error('mismatch at TransactionBuilder match: ' + k);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.hashToScriptMap) {
|
||||||
|
var err = 0;
|
||||||
|
if(! b.hashToScriptMap) err=1;
|
||||||
|
Object.keys(this.hashToScriptMap).forEach(function(k) {
|
||||||
|
if (!b.hashToScriptMap[k]) err=1;
|
||||||
|
if (this.hashToScriptMap[k] !== b.hashToScriptMap[k]) err=1;
|
||||||
|
});
|
||||||
|
if (err)
|
||||||
|
throw new Error('mismatch at TransactionBuilder hashToScriptMap');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var err = 0, i=0;;
|
||||||
|
this.selectedUtxos.forEach(function(u) {
|
||||||
|
if (!err) {
|
||||||
|
var v=b.selectedUtxos[i++];
|
||||||
|
if (!v) err=1;
|
||||||
|
// confirmations could differ
|
||||||
|
['address', 'hash', 'scriptPubKey', 'vout', 'amount'].forEach(function(k) {
|
||||||
|
if (u[k] !== v[k])
|
||||||
|
err=k;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (err)
|
||||||
|
throw new Error('mismatch at TransactionBuilder selectedUtxos #' + i-1+ ' Key:' + err);
|
||||||
|
|
||||||
|
|
||||||
|
err = 0; i=0;;
|
||||||
|
this.inputMap.forEach(function(u) {
|
||||||
|
if (!err) {
|
||||||
|
var v=b.inputMap[i++];
|
||||||
|
if (!v) err=1;
|
||||||
|
// confirmations could differ
|
||||||
|
['address', 'scriptType', 'scriptPubKey', 'i'].forEach(function(k) {
|
||||||
|
if (u[k] !== v[k])
|
||||||
|
err=k;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (err)
|
||||||
|
throw new Error('mismatch at TransactionBuilder inputMap #' + i-1 + ' Key:' + err);
|
||||||
|
|
||||||
|
|
||||||
|
// Does this tX have any signature already?
|
||||||
|
if (this.signaturesAdded) {
|
||||||
|
}
|
||||||
|
if (this.tx) {
|
||||||
|
}
|
||||||
|
// to be really merged
|
||||||
|
// signaturesAdded, inputsSigned
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = require('soop')(TransactionBuilder);
|
module.exports = require('soop')(TransactionBuilder);
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,9 @@ describe('TransactionBuilder', function() {
|
||||||
it('should be able to create instance with params', function() {
|
it('should be able to create instance with params', function() {
|
||||||
var t = new TransactionBuilder({spendUnconfirmed: true, lockTime: 10});
|
var t = new TransactionBuilder({spendUnconfirmed: true, lockTime: 10});
|
||||||
should.exist(t);
|
should.exist(t);
|
||||||
should.exist(t.txobj.version);
|
should.exist(t.lockTime);
|
||||||
t.spendUnconfirmed.should.equal(true);
|
t.spendUnconfirmed.should.equal(true);
|
||||||
t.txobj.lock_time.should.equal(10);
|
t.lockTime.should.equal(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,22 +84,24 @@ describe('TransactionBuilder', function() {
|
||||||
|
|
||||||
|
|
||||||
it('#_setInputs sets inputs', function() {
|
it('#_setInputs sets inputs', function() {
|
||||||
|
var txobj={};
|
||||||
var b = getBuilder()
|
var b = getBuilder()
|
||||||
.setUnspent(testdata.dataUnspent)
|
.setUnspent(testdata.dataUnspent)
|
||||||
._selectUnspent(0.1 * util.COIN)
|
._selectUnspent(0.1 * util.COIN)
|
||||||
._setInputs();
|
._setInputs(txobj);
|
||||||
|
|
||||||
should.exist(b.txobj.ins[0].s);
|
should.exist(txobj.ins[0].s);
|
||||||
should.exist(b.txobj.ins[0].q);
|
should.exist(txobj.ins[0].q);
|
||||||
should.exist(b.txobj.ins[0].o);
|
should.exist(txobj.ins[0].o);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('#_setInputMap set inputMap', function() {
|
it('#_setInputMap set inputMap', function() {
|
||||||
|
var txobj={};
|
||||||
var b = getBuilder()
|
var b = getBuilder()
|
||||||
.setUnspent(testdata.dataUnspent)
|
.setUnspent(testdata.dataUnspent)
|
||||||
._selectUnspent(0.1 * util.COIN)
|
._selectUnspent(0.1 * util.COIN)
|
||||||
._setInputs()
|
._setInputs(txobj)
|
||||||
._setInputMap();
|
._setInputMap(txobj);
|
||||||
|
|
||||||
should.exist(b.inputMap);
|
should.exist(b.inputMap);
|
||||||
b.inputMap.length.should.equal(2);
|
b.inputMap.length.should.equal(2);
|
||||||
|
|
Loading…
Reference in New Issue