add p2sh support and test
This commit is contained in:
parent
d8f49e87ae
commit
f6f7a01efc
18
Script.js
18
Script.js
|
@ -490,7 +490,25 @@ Script.prototype.toHumanReadable = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
Script.prototype.countMissingSignatures = function() {
|
||||||
|
var ret = 0;
|
||||||
|
if (!Buffer.isBuffer(this.chunks[0]) && this.chunks[0] ===0) {
|
||||||
|
// Multisig, skip first 0x0
|
||||||
|
for (var i = 1; i < this.chunks.length; i++) {
|
||||||
|
if (this.chunks[i]===0
|
||||||
|
|| buffertools.compare(this.chunks[i], util.EMPTY_BUFFER) === 0){
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (buffertools.compare(this.getBuffer(), util.EMPTY_BUFFER) === 0) {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.stringToBuffer = function(s) {
|
Script.stringToBuffer = function(s) {
|
||||||
|
|
|
@ -552,28 +552,28 @@ Transaction.prototype.getSize = function getHash() {
|
||||||
return this.size;
|
return this.size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Transaction.prototype.countInputMissingSignatures = function(index) {
|
||||||
|
var ret = 0;
|
||||||
|
var script = new Script(this.ins[index].s);
|
||||||
|
return script.countMissingSignatures();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Transaction.prototype.isInputComplete = function(index) {
|
||||||
|
return this.countInputMissingSignatures(index)===0;
|
||||||
|
};
|
||||||
|
|
||||||
Transaction.prototype.isComplete = function() {
|
Transaction.prototype.isComplete = function() {
|
||||||
var ret = true;
|
var ret = true;
|
||||||
var l = this.ins.length;
|
var l = this.ins.length;
|
||||||
|
|
||||||
for (var i = 0; i < l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
var script = new Script(this.ins[i].s);
|
if (!this.isInputComplete(i)){
|
||||||
// Multisig?
|
|
||||||
if (!Buffer.isBuffer(script.chunks[0]) && script.chunks[0] ===0) {
|
|
||||||
for (var i = 1; i < script.chunks.length; i++) {
|
|
||||||
if (buffertools.compare(script.chunks[i], util.EMPTY_BUFFER) === 0){
|
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (buffertools.compare(this.ins[i].s, util.EMPTY_BUFFER) === 0) {
|
|
||||||
ret = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
|
@ -115,12 +115,12 @@ function TransactionBuilder(opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _scriptForAddress
|
* scriptForAddress
|
||||||
*
|
*
|
||||||
* Returns a scriptPubKey for the given address type
|
* Returns a scriptPubKey for the given address type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TransactionBuilder._scriptForAddress = function(addressString) {
|
TransactionBuilder.scriptForAddress = function(addressString) {
|
||||||
|
|
||||||
var livenet = networks.livenet;
|
var livenet = networks.livenet;
|
||||||
var testnet = networks.testnet;
|
var testnet = networks.testnet;
|
||||||
|
@ -154,7 +154,7 @@ TransactionBuilder._scriptForPubkeys = function(out) {
|
||||||
TransactionBuilder._scriptForOut = function(out) {
|
TransactionBuilder._scriptForOut = function(out) {
|
||||||
var ret;
|
var ret;
|
||||||
if (out.address)
|
if (out.address)
|
||||||
ret = this._scriptForAddress(out.address);
|
ret = this.scriptForAddress(out.address);
|
||||||
else if (out.pubkeys || out.nreq || out.nreq > 1)
|
else if (out.pubkeys || out.nreq || out.nreq > 1)
|
||||||
ret = this._scriptForPubkeys(out);
|
ret = this._scriptForPubkeys(out);
|
||||||
else
|
else
|
||||||
|
@ -201,8 +201,7 @@ TransactionBuilder.prototype._setInputMap = function() {
|
||||||
' Type:' + scriptPubKey.getRawOutType());
|
' Type:' + scriptPubKey.getRawOutType());
|
||||||
|
|
||||||
inputMap.push({
|
inputMap.push({
|
||||||
address: utxo.address, //TODO que pasa en multisig normal?
|
address: utxo.address,
|
||||||
scriptPubKeyHex: utxo.scriptPubKey,
|
|
||||||
scriptPubKey: scriptPubKey,
|
scriptPubKey: scriptPubKey,
|
||||||
scriptType: scriptType,
|
scriptType: scriptType,
|
||||||
i: i,
|
i: i,
|
||||||
|
@ -394,7 +393,6 @@ TransactionBuilder.prototype.setOutputs = function(outs) {
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder._mapKeys = function(keys) {
|
TransactionBuilder._mapKeys = function(keys) {
|
||||||
|
|
||||||
//prepare keys
|
//prepare keys
|
||||||
var walletKeyMap = {};
|
var walletKeyMap = {};
|
||||||
var l = keys.length;
|
var l = keys.length;
|
||||||
|
@ -437,10 +435,43 @@ TransactionBuilder.prototype._checkTx = function() {
|
||||||
throw new Error('tx is not defined');
|
throw new Error('tx is not defined');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TransactionBuilder.prototype._multiFindKey = function(walletKeyMap,pubKeyHash) {
|
||||||
|
var wk;
|
||||||
|
[ networks.livenet, networks.testnet].forEach(function(n) {
|
||||||
|
[ n.addressPubkey, n.addressScript].forEach(function(v) {
|
||||||
|
var a = new Address(v,pubKeyHash);
|
||||||
|
if (!wk && walletKeyMap[a]) {
|
||||||
|
wk = walletKeyMap[a];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return wk;
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionBuilder.prototype._findWalletKey = function(walletKeyMap, input) {
|
||||||
|
var wk;
|
||||||
|
|
||||||
|
if (input.address) {
|
||||||
|
wk = walletKeyMap[input.address];
|
||||||
|
}
|
||||||
|
else if (input.pubKeyHash) {
|
||||||
|
wk = this._multiFindKey(walletKeyMap, input.pubKeyHash);
|
||||||
|
}
|
||||||
|
else if (input.pubKeyBuf) {
|
||||||
|
var pubKeyHash = util.sha256ripe160(input.pubKeyBuf);
|
||||||
|
wk = this._multiFindKey(walletKeyMap, pubKeyHash);
|
||||||
|
} else {
|
||||||
|
throw new Error('no infomation at input to find keys');
|
||||||
|
}
|
||||||
|
return wk;
|
||||||
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._signPubKey = function(walletKeyMap, input, txSigHash) {
|
TransactionBuilder.prototype._signPubKey = function(walletKeyMap, input, txSigHash) {
|
||||||
if (this.tx.ins[input.i].s.length > 0) return {};
|
if (this.tx.ins[input.i].s.length > 0) return {};
|
||||||
|
|
||||||
var wk = walletKeyMap[input.address];
|
var wk = this._findWalletKey(walletKeyMap, input);
|
||||||
if (!wk) return;
|
if (!wk) return;
|
||||||
|
|
||||||
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
||||||
|
@ -451,14 +482,14 @@ TransactionBuilder.prototype._signPubKey = function(walletKeyMap, input, txSigHa
|
||||||
var scriptSig = new Script();
|
var scriptSig = new Script();
|
||||||
scriptSig.chunks.push(sig);
|
scriptSig.chunks.push(sig);
|
||||||
scriptSig.updateBuffer();
|
scriptSig.updateBuffer();
|
||||||
return {isFullySigned: true, script: scriptSig.getBuffer()};
|
return {isFullySigned: true, signaturesAdded: true, script: scriptSig.getBuffer()};
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._signPubKeyHash = function(walletKeyMap, input, txSigHash) {
|
TransactionBuilder.prototype._signPubKeyHash = function(walletKeyMap, input, txSigHash) {
|
||||||
|
|
||||||
if (this.tx.ins[input.i].s.length > 0) return {};
|
if (this.tx.ins[input.i].s.length > 0) return {};
|
||||||
|
|
||||||
var wk = walletKeyMap[input.address];
|
var wk = this._findWalletKey(walletKeyMap, input);
|
||||||
if (!wk) return;
|
if (!wk) return;
|
||||||
|
|
||||||
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
||||||
|
@ -470,18 +501,16 @@ TransactionBuilder.prototype._signPubKeyHash = function(walletKeyMap, input, txS
|
||||||
scriptSig.chunks.push(sig);
|
scriptSig.chunks.push(sig);
|
||||||
scriptSig.chunks.push(wk.privKey.public);
|
scriptSig.chunks.push(wk.privKey.public);
|
||||||
scriptSig.updateBuffer();
|
scriptSig.updateBuffer();
|
||||||
return {isFullySigned: true, script: scriptSig.getBuffer()};
|
return {isFullySigned: true, signaturesAdded: true, script: scriptSig.getBuffer()};
|
||||||
};
|
};
|
||||||
|
|
||||||
// FOR TESTING
|
// FOR TESTING
|
||||||
/*
|
// var _dumpChunks = function (scriptSig, label) {
|
||||||
var _dumpChunks = function (scriptSig, label) {
|
// console.log('## DUMP: ' + label + ' ##');
|
||||||
console.log('## DUMP: ' + label + ' ##');
|
// for(var i=0; i<scriptSig.chunks.length; i++) {
|
||||||
for(var i=0; i<scriptSig.chunks.length; i++) {
|
// console.log('\tCHUNK ', i, scriptSig.chunks[i]);
|
||||||
console.log('\tCHUNK ', i, scriptSig.chunks[i]);
|
// }
|
||||||
}
|
// };
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._initMultiSig = function(scriptSig, nreq) {
|
TransactionBuilder.prototype._initMultiSig = function(scriptSig, nreq) {
|
||||||
var wasUpdated = false;
|
var wasUpdated = false;
|
||||||
|
@ -514,6 +543,13 @@ TransactionBuilder.prototype._chunkIsEmpty = function(chunk) {
|
||||||
buffertools.compare(chunk, util.EMPTY_BUFFER) === 0;
|
buffertools.compare(chunk, util.EMPTY_BUFFER) === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TransactionBuilder.prototype._chunkIsSignature = function(chunk) {
|
||||||
|
return chunk.length
|
||||||
|
buffertools.compare(chunk, util.EMPTY_BUFFER) === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._updateMultiSig = function(wk, scriptSig, txSigHash, nreq) {
|
TransactionBuilder.prototype._updateMultiSig = function(wk, scriptSig, txSigHash, nreq) {
|
||||||
var wasUpdated = this._initMultiSig(scriptSig, nreq);
|
var wasUpdated = this._initMultiSig(scriptSig, nreq);
|
||||||
|
|
||||||
|
@ -540,40 +576,6 @@ TransactionBuilder.prototype._updateMultiSig = function(wk, scriptSig, txSigHash
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._multiFindKey = function(walletKeyMap,pubKeyHash) {
|
|
||||||
var wk;
|
|
||||||
[ networks.livenet, networks.testnet].forEach(function(n) {
|
|
||||||
[ n.addressPubkey, n.addressScript].forEach(function(v) {
|
|
||||||
var a = new Address(v,pubKeyHash);
|
|
||||||
if (!wk && walletKeyMap[a]) {
|
|
||||||
wk = walletKeyMap[a];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return wk;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._countMultiSig = function(script) {
|
|
||||||
var nsigs = 0;
|
|
||||||
for (var i = 1; i < script.chunks.length; i++)
|
|
||||||
if (!this._chunkIsEmpty(script.chunks[i]))
|
|
||||||
nsigs++;
|
|
||||||
|
|
||||||
return nsigs;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
TransactionBuilder.prototype.countInputMultiSig = function(i) {
|
|
||||||
var s = new Script(this.tx.ins[i].s);
|
|
||||||
if (!s.chunks.length || s.chunks[0] !== 0)
|
|
||||||
return 0; // does not seems multisig
|
|
||||||
|
|
||||||
return this._countMultiSig(s);
|
|
||||||
};
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSigHash) {
|
TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSigHash) {
|
||||||
var pubkeys = input.scriptPubKey.capture(),
|
var pubkeys = input.scriptPubKey.capture(),
|
||||||
nreq = input.scriptPubKey.chunks[0] - 80, //see OP_2-OP_16
|
nreq = input.scriptPubKey.chunks[0] - 80, //see OP_2-OP_16
|
||||||
|
@ -581,76 +583,96 @@ TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSig
|
||||||
originalScriptBuf = this.tx.ins[input.i].s;
|
originalScriptBuf = this.tx.ins[input.i].s;
|
||||||
|
|
||||||
var scriptSig = new Script (originalScriptBuf);
|
var scriptSig = new Script (originalScriptBuf);
|
||||||
|
var signaturesAdded = false;
|
||||||
|
|
||||||
for(var j=0; j<l && this._countMultiSig(scriptSig)<nreq; j++) {
|
for(var j=0; j<l && scriptSig.countMissingSignatures(); j++) {
|
||||||
|
var wk = this._findWalletKey(walletKeyMap, {pubKeyBuf: pubkeys[j]});
|
||||||
var pubKeyHash = util.sha256ripe160(pubkeys[j]);
|
|
||||||
var wk = this._multiFindKey(walletKeyMap, pubKeyHash);
|
|
||||||
if (!wk) continue;
|
if (!wk) continue;
|
||||||
|
|
||||||
var newScriptSig = this._updateMultiSig(wk, scriptSig, txSigHash, nreq);
|
var newScriptSig = this._updateMultiSig(wk, scriptSig, txSigHash, nreq);
|
||||||
if (newScriptSig)
|
if (newScriptSig) {
|
||||||
scriptSig = newScriptSig;
|
scriptSig = newScriptSig;
|
||||||
|
signaturesAdded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isFullySigned: this._countMultiSig(scriptSig) === nreq,
|
isFullySigned: scriptSig.countMissingSignatures() === 0,
|
||||||
|
signaturesAdded: signaturesAdded,
|
||||||
script: scriptSig.getBuffer(),
|
script: scriptSig.getBuffer(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var fnToSign = {};
|
var fnToSign = {};
|
||||||
|
|
||||||
|
TransactionBuilder.prototype._scriptIsAppended = function(script, scriptToAddBuf) {
|
||||||
|
var len = script.chunks.length;
|
||||||
|
|
||||||
|
if (script.chunks[len-1] === undefined)
|
||||||
|
return false;
|
||||||
|
if (typeof script.chunks[len-1] === 'number')
|
||||||
|
return false;
|
||||||
|
if (buffertools.compare(script.chunks[len-1] , scriptToAddBuf) !==0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionBuilder.prototype._addScript = function(scriptBuf, scriptToAddBuf) {
|
||||||
|
var s = new Script(scriptBuf);
|
||||||
|
|
||||||
|
if (!this._scriptIsAppended(s, scriptToAddBuf)) {
|
||||||
|
s.chunks.push(scriptToAddBuf);
|
||||||
|
s.updateBuffer();
|
||||||
|
}
|
||||||
|
return s.getBuffer();
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionBuilder.prototype._getInputForP2sh = function(script, index) {
|
||||||
|
var scriptType = script.classify();
|
||||||
|
// pubKeyHash is needed for TX_PUBKEYHASH and TX_PUBKEY to retrieve the keys.
|
||||||
|
var pubKeyHash;
|
||||||
|
switch(scriptType) {
|
||||||
|
case Script.TX_PUBKEYHASH:
|
||||||
|
pubKeyHash = script.captureOne();
|
||||||
|
break;
|
||||||
|
case Script.TX_PUBKEY:
|
||||||
|
var chunk = script.captureOne();
|
||||||
|
pubKeyHash = util.sha256ripe160(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
i: index,
|
||||||
|
pubKeyHash: pubKeyHash,
|
||||||
|
scriptPubKey: script,
|
||||||
|
scriptType: scriptType,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._signScriptHash = function(walletKeyMap, input, txSigHash) {
|
TransactionBuilder.prototype._signScriptHash = function(walletKeyMap, input, txSigHash) {
|
||||||
var originalScriptBuf = this.tx.ins[input.i].s;
|
var originalScriptBuf = this.tx.ins[input.i].s;
|
||||||
|
|
||||||
|
|
||||||
if (!this.hashToScriptMap)
|
if (!this.hashToScriptMap)
|
||||||
throw new Error('hashToScriptMap not set');
|
throw new Error('hashToScriptMap not set');
|
||||||
|
|
||||||
var scriptHex = this.hashToScriptMap[input.address];
|
var scriptHex = this.hashToScriptMap[input.address];
|
||||||
if (!scriptHex) return;
|
if (!scriptHex) return;
|
||||||
|
|
||||||
var script = new Script(new Buffer(scriptHex,'hex'));
|
var scriptBuf = new Buffer(scriptHex,'hex');
|
||||||
|
var script = new Script(scriptBuf);
|
||||||
var scriptType = script.classify();
|
var scriptType = script.classify();
|
||||||
var scriptPubKeyHex = script.getBuffer().toString('hex');
|
|
||||||
|
|
||||||
if (!fnToSign[scriptType])
|
if (!fnToSign[scriptType] || scriptType === Script.TX_SCRIPTHASH)
|
||||||
throw new Error('dont know how to sign p2sh script type'+ script.getRawOutType());
|
throw new Error('dont know how to sign p2sh script type:'+ script.getRawOutType());
|
||||||
|
|
||||||
var newInput = {
|
var newInput = this._getInputForP2sh(script, input.i);
|
||||||
address: 'TODO', // if p2pkubkeyhash -> get the address
|
var newTxSigHash = this.tx.hashForSignature( script, newInput.i, this.signhash);
|
||||||
i: input.i,
|
var ret = fnToSign[scriptType].call(this, walletKeyMap, newInput, newTxSigHash);
|
||||||
scriptPubKey: script,
|
|
||||||
scriptPubKeyHex: scriptPubKeyHex ,
|
|
||||||
scriptType: scriptType,
|
|
||||||
};
|
|
||||||
|
|
||||||
var txSigHash2 = this.tx.hashForSignature( script, input.i, this.signhash);
|
if (ret && ret.script && ret.signaturesAdded) {
|
||||||
var ret = fnToSign[scriptType].call(this, walletKeyMap, newInput, txSigHash2);
|
ret.script = this._addScript(ret.script, scriptBuf);
|
||||||
|
|
||||||
var rc =1; //TODO : si alguno firmó...
|
|
||||||
if (ret.script) {
|
|
||||||
|
|
||||||
console.log('[TransactionBuilder.js.634] IN'); //TODO
|
|
||||||
var scriptSig = new Script(originalScriptBuf);
|
|
||||||
var len = scriptSig.chunks.length;
|
|
||||||
var scriptBufNotAlreadyAppended = scriptSig.chunks[len-1] !== undefined && (typeof scriptSig.chunks[len-1] == "number" || scriptSig.chunks[len-1].toString('hex') != scriptBuf.toString('hex'));
|
|
||||||
if (rc > 0 && scriptBufNotAlreadyAppended) {
|
|
||||||
scriptSig.chunks.push(scriptBuf);
|
|
||||||
scriptSig.updateBuffer();
|
|
||||||
ret.script = scriptSig.getBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scriptType == Script.TX_MULTISIG && scriptSig.finishedMultiSig())
|
|
||||||
{
|
|
||||||
scriptSig.removePlaceHolders();
|
|
||||||
scriptSig.prependOp0();
|
|
||||||
ret.script = scriptSig.getBuffer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -676,17 +698,16 @@ TransactionBuilder.prototype.sign = function(keys) {
|
||||||
|
|
||||||
var ret = fnToSign[input.scriptType].call(this, walletKeyMap, input, txSigHash);
|
var ret = fnToSign[input.scriptType].call(this, walletKeyMap, input, txSigHash);
|
||||||
if (ret && ret.script) {
|
if (ret && ret.script) {
|
||||||
tx.ins[i].s = ret.script; //esto no aqui TODO
|
tx.ins[i].s = ret.script;
|
||||||
if (ret.isFullySigned) this.inputsSigned++;
|
if (ret.isFullySigned) this.inputsSigned++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
// [addr -> script]
|
// [ { address:scriptHex }]
|
||||||
TransactionBuilder.prototype.setHashToScriptMap = function(hashToScriptMap) {
|
TransactionBuilder.prototype.setHashToScriptMap = function(hashToScriptMap) {
|
||||||
this.hashToScriptMap= hashToScriptMap;
|
this.hashToScriptMap= hashToScriptMap;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@ var run = function() {
|
||||||
var utxos = [
|
var utxos = [
|
||||||
{
|
{
|
||||||
address: input.addr,
|
address: input.addr,
|
||||||
txid: "a2a1b0bfbbe769253787d83c097adf61e6d77088e295249e9c3f1ca8a035c639",
|
txid: "39c71ebda371f75f4b854a720eaf9898b237facf3c2b101b58cd4383a44a6adc",
|
||||||
vout: 0,
|
vout: 1,
|
||||||
ts: 1396288753,
|
ts: 1396288753,
|
||||||
scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac",
|
scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac",
|
||||||
amount: 0.63,
|
amount: 0.4296,
|
||||||
confirmations: 2
|
confirmations: 2
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -50,7 +50,7 @@ var run = function() {
|
||||||
.build();
|
.build();
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
console.log('1) SEND TO MULSISIG TX: ', txHex);
|
console.log('1) SEND TO MULSISIG TX: ', txHex);
|
||||||
console.log('[this example originally generated TXID: ff5c8b4912f6d056f0cf8431ec27032a73df22c167726267dd4cc0d7817a1e7d on testnet]\n\n\thttp://test.bitcore.io/tx/ff5c8b4912f6d056f0cf8431ec27032a73df22c167726267dd4cc0d7817a1e7d\n\n');
|
console.log('[this example originally generated TXID: e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5 on testnet]\n\n\thttp://test.bitcore.io/tx/e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5\n\n');
|
||||||
|
|
||||||
|
|
||||||
//save scriptPubKey
|
//save scriptPubKey
|
||||||
|
@ -63,7 +63,7 @@ var run = function() {
|
||||||
var utxos2 = [
|
var utxos2 = [
|
||||||
{
|
{
|
||||||
address: input.addr,
|
address: input.addr,
|
||||||
txid: "ff5c8b4912f6d056f0cf8431ec27032a73df22c167726267dd4cc0d7817a1e7d",
|
txid: "e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5",
|
||||||
vout: 0,
|
vout: 0,
|
||||||
ts: 1396288753,
|
ts: 1396288753,
|
||||||
scriptPubKey: scriptPubKey,
|
scriptPubKey: scriptPubKey,
|
||||||
|
@ -84,9 +84,9 @@ var run = function() {
|
||||||
|
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
console.log('2) REDEEM SCRIPT: ', txHex);
|
console.log('2) REDEEM SCRIPT: ', txHex);
|
||||||
console.log('=> Is signed status:', b.isFullySigned(), b.countInputMultiSig(0) );
|
console.log('=> Is signed status:', b.isFullySigned(), tx.countInputMissingSignatures(0) );
|
||||||
|
|
||||||
console.log('[this example originally generated TXID: 2813c5a670d2c9d0527718f9d0ea896c78c3c8fc57b409e67308744fc7a7a98e on testnet]\n\n\thttp://test.bitcore.io/tx/2813c5a670d2c9d0527718f9d0ea896c78c3c8fc57b409e67308744fc7a7a98e');
|
console.log('[this example originally generated TXID: 1eb388977b2de99562eb0fbcc661a100eaffed99c53bfcfebe5a087002039b83 on testnet]\n\n\thttp://test.bitcore.io/tx/1eb388977b2de99562eb0fbcc661a100eaffed99c53bfcfebe5a087002039b83');
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,11 @@ var run = function() {
|
||||||
var utxos = [
|
var utxos = [
|
||||||
{
|
{
|
||||||
address: "n2hoFVbPrYQf7RJwiRy1tkbuPPqyhAEfbp",
|
address: "n2hoFVbPrYQf7RJwiRy1tkbuPPqyhAEfbp",
|
||||||
txid: "ba20653648a896ae95005b8f52847935a7313da06cd7295bb2cfc8b5c1b36c71",
|
txid: "e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5",
|
||||||
vout: 1,
|
vout: 1,
|
||||||
ts: 1396290442,
|
ts: 1396290442,
|
||||||
scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac",
|
scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac",
|
||||||
amount: 0.5298,
|
amount: 0.3795,
|
||||||
confirmations: 7
|
confirmations: 7
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -57,12 +57,13 @@ var run = function() {
|
||||||
.setOutputs(outs)
|
.setOutputs(outs)
|
||||||
.sign([input.priv])
|
.sign([input.priv])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
|
|
||||||
|
|
||||||
console.log('p2sh address: ' + p2shAddress); //TODO
|
console.log('## p2sh address: ' + p2shAddress); //TODO
|
||||||
console.log('1) SEND TO P2SH TX: ', txHex);
|
console.log('\n1) SEND TO P2SH TX: ', txHex);
|
||||||
console.log('[this example originally generated TXID: 8675a1f7ab0c2eeec2ff2def539446d1942efffd468319107429b894e60ecac3 on testnet]\n\n\thttp://test.bitcore.io/tx/8675a1f7ab0c2eeec2ff2def539446d1942efffd468319107429b894e60ecac3\n\n');
|
console.log('[this example originally generated TXID: c2e50d1c8c581d8c4408378b751633f7eb86687fc5f0502be7b467173f275ae7 on testnet]\n\n\thttp://test.bitcore.io/tx/c2e50d1c8c581d8c4408378b751633f7eb86687fc5f0502be7b467173f275ae7\n\n');
|
||||||
|
|
||||||
//save scriptPubKey
|
//save scriptPubKey
|
||||||
var scriptPubKey = tx.outs[0].s.toString('hex');
|
var scriptPubKey = tx.outs[0].s.toString('hex');
|
||||||
|
@ -74,12 +75,12 @@ var run = function() {
|
||||||
var utxos2 = [
|
var utxos2 = [
|
||||||
{
|
{
|
||||||
address: p2shAddress,
|
address: p2shAddress,
|
||||||
txid: "ba20653648a896ae95005b8f52847935a7313da06cd7295bb2cfc8b5c1b36c71",
|
txid: "c2e50d1c8c581d8c4408378b751633f7eb86687fc5f0502be7b467173f275ae7",
|
||||||
vout: 0,
|
vout: 0,
|
||||||
ts: 1396288753,
|
ts: 1396375187,
|
||||||
scriptPubKey: scriptPubKey,
|
scriptPubKey: scriptPubKey,
|
||||||
amount: 0.05,
|
amount: 0.05,
|
||||||
confirmations: 2
|
confirmations: 1
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -94,18 +95,42 @@ var run = function() {
|
||||||
.setOutputs(outs)
|
.setOutputs(outs)
|
||||||
.sign(privs);
|
.sign(privs);
|
||||||
|
|
||||||
|
|
||||||
tx= b.build();
|
tx= b.build();
|
||||||
|
|
||||||
|
|
||||||
|
console.log('Builder:');
|
||||||
|
console.log('\tSignatures:' + tx.countInputMissingSignatures(0) );
|
||||||
|
console.log('\t#isFullySigned:' + b.isFullySigned() );
|
||||||
|
|
||||||
|
console.log('TX:');
|
||||||
|
console.log('\t #isComplete:' + tx.isComplete() );
|
||||||
|
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
console.log('2) REDEEM SCRIPT: ', txHex);
|
console.log('2) REDEEM SCRIPT: ', txHex);
|
||||||
console.log('=> Is signed status:', b.isFullySigned(), b.countInputMultiSig(0) );
|
console.log('[this example originally generated TXID: 8284aa3b6f9c71c35ecb1d61d05ae78c8ca1f36940eaa615b50584dfc3d95cb7 on testnet]\n\n\thttp://test.bitcore.io/tx/8284aa3b6f9c71c35ecb1d61d05ae78c8ca1f36940eaa615b50584dfc3d95cb7\n\n');
|
||||||
|
|
||||||
console.log('[this example originally generated TXID: 2813c5a670d2c9d0527718f9d0ea896c78c3c8fc57b409e67308744fc7a7a98e on testnet]\n\n\thttp://test.bitcore.io/tx/2813c5a670d2c9d0527718f9d0ea896c78c3c8fc57b409e67308744fc7a7a98e');
|
/*
|
||||||
|
// To send TX with RPC:
|
||||||
|
var RpcClient = bitcore.RpcClient;
|
||||||
|
var config = {
|
||||||
|
protocol: 'http',
|
||||||
|
user: 'user',
|
||||||
|
pass: 'pass',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: '18332',
|
||||||
|
};
|
||||||
|
var rpc = new RpcClient(config);
|
||||||
|
rpc.sendRawTransaction(txHex, function(err, ret) {
|
||||||
|
console.log('err', err); //TODO
|
||||||
|
console.log('ret', ret); //TODO
|
||||||
|
process.exit(-1);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// This is just for browser & mocha compatibility
|
// This is just for browser & mocha compatibility
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports.run = run;
|
module.exports.run = run;
|
||||||
|
@ -115,6 +140,3 @@ if (typeof module !== 'undefined') {
|
||||||
} else {
|
} else {
|
||||||
run();
|
run();
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ var run = function() {
|
||||||
|
|
||||||
//Generate from private Key WIF. Compressed status taken from WIF.
|
//Generate from private Key WIF. Compressed status taken from WIF.
|
||||||
var wk2 = new WalletKey(opts);
|
var wk2 = new WalletKey(opts);
|
||||||
wk2.fromObj({priv:'cS62Ej4SobZnpFQYN1PEEBr2KWf5sgRYYnELtumcG6WVCfxno39V'});
|
wk2.fromObj({priv:'cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA'});
|
||||||
print(wk2);
|
print(wk2);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,23 @@
|
||||||
"cUkYub4jtFVYymHh38yMMW36nJB4pXG5Pzd5QjResq79kAndkJcg",
|
"cUkYub4jtFVYymHh38yMMW36nJB4pXG5Pzd5QjResq79kAndkJcg",
|
||||||
"cMyBgowsyrJRufoKWob73rMQB1PBqDdwFt8z4TJ6APN2HkmX1Ttm",
|
"cMyBgowsyrJRufoKWob73rMQB1PBqDdwFt8z4TJ6APN2HkmX1Ttm",
|
||||||
"cN9yZCom6hAZpHtCp8ovE1zFa7RqDf3Cr4W6AwH2tp59Jjh9JcXu"
|
"cN9yZCom6hAZpHtCp8ovE1zFa7RqDf3Cr4W6AwH2tp59Jjh9JcXu"
|
||||||
|
],
|
||||||
|
"unspentP2sh": [
|
||||||
|
{
|
||||||
|
"address": "2Mwswt6Eih28xH8611fexpqKqJCLJMomveK",
|
||||||
|
"scriptPubKey": "a91432d272ce8a9b482b363408a0b1dd28123d59c63387",
|
||||||
|
"txid": "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1",
|
||||||
|
"vout": 1,
|
||||||
|
"amount": 1,
|
||||||
|
"confirmations":7
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"keyStringsP2sh": [
|
||||||
|
"cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA",
|
||||||
|
"cVf32m9MR4vxcPwKNJuPepUe8XrHD2z63eCk76d6njRGyCkXpkSM",
|
||||||
|
"cQ2sVRFX4jQYMLhWyzz6jTQ2xju51P36968ecXnPhRLKLH677eKR",
|
||||||
|
"cSw7x9ERcmeWCU3yVBT6Nz7b9JiZ5yjUB7JMhBUv9UM7rSaDpwX9",
|
||||||
|
"cRQBM8qM4ZXJGP1De4D5RtJm7Q6FNWQSMx7YExxzgn2ehjM3haxW"
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,9 @@ var TransactionBuilder = bitcore.TransactionBuilder;
|
||||||
var In;
|
var In;
|
||||||
var Out;
|
var Out;
|
||||||
var Script = bitcore.Script;
|
var Script = bitcore.Script;
|
||||||
|
var WalletKey = bitcore.WalletKey;
|
||||||
var util = bitcore.util;
|
var util = bitcore.util;
|
||||||
|
var networks = bitcore.networks;
|
||||||
var buffertools = require('buffertools');
|
var buffertools = require('buffertools');
|
||||||
var testdata = testdata || require('./testdata');
|
var testdata = testdata || require('./testdata');
|
||||||
|
|
||||||
|
@ -484,16 +486,26 @@ describe('TransactionBuilder', function() {
|
||||||
var k2 = testdata.dataUnspentSign.keyStringsMulti.slice(1,2);
|
var k2 = testdata.dataUnspentSign.keyStringsMulti.slice(1,2);
|
||||||
var k3 = testdata.dataUnspentSign.keyStringsMulti.slice(2,3);
|
var k3 = testdata.dataUnspentSign.keyStringsMulti.slice(2,3);
|
||||||
|
|
||||||
b.countInputMultiSig(0).should.equal(0);
|
var tx = b.build();
|
||||||
|
|
||||||
|
b.isFullySigned().should.equal(false);
|
||||||
|
|
||||||
|
// This is cumbersome. Before sign, missing is 1. Need to be changed in the future
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(1);
|
||||||
|
b.sign(['cSq7yo4fvsbMyWVN945VUGUWMaSazZPWqBVJZyoGsHmNq6W4HVBV']);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(1);
|
||||||
|
|
||||||
b.sign(k1);
|
b.sign(k1);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
b.isFullySigned().should.equal(false);
|
b.isFullySigned().should.equal(false);
|
||||||
b.countInputMultiSig(0).should.equal(1);
|
|
||||||
b.sign(k2);
|
b.sign(k2);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(1);
|
||||||
b.isFullySigned().should.equal(false);
|
b.isFullySigned().should.equal(false);
|
||||||
b.countInputMultiSig(0).should.equal(2);
|
|
||||||
b.sign(k3);
|
b.sign(k3);
|
||||||
|
tx.countInputMissingSignatures(0).should.equal(0);
|
||||||
b.isFullySigned().should.equal(true);
|
b.isFullySigned().should.equal(true);
|
||||||
b.countInputMultiSig(0).should.equal(3);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -511,20 +523,162 @@ describe('TransactionBuilder', function() {
|
||||||
|
|
||||||
var k1 = testdata.dataUnspentSign.keyStringsMulti.slice(0,1);
|
var k1 = testdata.dataUnspentSign.keyStringsMulti.slice(0,1);
|
||||||
var k23 = testdata.dataUnspentSign.keyStringsMulti.slice(1,3);
|
var k23 = testdata.dataUnspentSign.keyStringsMulti.slice(1,3);
|
||||||
|
var tx = b.build();
|
||||||
|
|
||||||
b.countInputMultiSig(0).should.equal(0);
|
tx.countInputMissingSignatures(0).should.equal(1);
|
||||||
b.sign(k1);
|
b.sign(k1);
|
||||||
b.isFullySigned().should.equal(false);
|
b.isFullySigned().should.equal(false);
|
||||||
b.countInputMultiSig(0).should.equal(1);
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
b.sign(k1);
|
b.sign(k1);
|
||||||
b.isFullySigned().should.equal(false);
|
b.isFullySigned().should.equal(false);
|
||||||
b.countInputMultiSig(0).should.equal(1);
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
b.sign(k1);
|
b.sign(k1);
|
||||||
b.isFullySigned().should.equal(false);
|
b.isFullySigned().should.equal(false);
|
||||||
b.countInputMultiSig(0).should.equal(1);
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
|
||||||
b.sign(k23);
|
b.sign(k23);
|
||||||
b.isFullySigned().should.equal(true);
|
b.isFullySigned().should.equal(true);
|
||||||
b.countInputMultiSig(0).should.equal(3);
|
tx.countInputMissingSignatures(0).should.equal(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var getInfoForP2sh = function () {
|
||||||
|
var privs = testdata.dataUnspentSign.keyStringsP2sh;
|
||||||
|
var pubkeys = [];
|
||||||
|
privs.forEach(function(p) {
|
||||||
|
var wk = new WalletKey({network: networks.testnet});
|
||||||
|
wk.fromObj({priv: p});
|
||||||
|
pubkeys.push(bitcore.buffertools.toHex(wk.privKey.public));
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
privkeys: privs,
|
||||||
|
pubkeys: pubkeys,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var getP2shBuilder = function(setMap) {
|
||||||
|
var network = 'testnet';
|
||||||
|
var opts = {
|
||||||
|
remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'},
|
||||||
|
};
|
||||||
|
var data = getInfoForP2sh();
|
||||||
|
// multisig p2sh
|
||||||
|
var p2shOpts = {nreq:3, pubkeys:data.pubkeys, amount:0.05};
|
||||||
|
var info = TransactionBuilder.infoForP2sh(p2shOpts, network);
|
||||||
|
|
||||||
|
var outs = outs || [{
|
||||||
|
address: info.address,
|
||||||
|
amount: 0.08
|
||||||
|
}];
|
||||||
|
var b = new TransactionBuilder(opts)
|
||||||
|
.setUnspent(testdata.dataUnspentSign.unspentP2sh)
|
||||||
|
.setOutputs(outs);
|
||||||
|
|
||||||
|
if (setMap) {
|
||||||
|
var hashMap = {};
|
||||||
|
hashMap[info.address]=info.scriptBufHex;
|
||||||
|
b.setHashToScriptMap(hashMap);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should fail to sign a p2sh/multisign tx if none script map was given', function() {
|
||||||
|
var b = getP2shBuilder();
|
||||||
|
(function() {b.sign(testdata.dataUnspentSign.keyStringsP2sh);}).should.throw();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sign a p2sh/multisign tx', function() {
|
||||||
|
var b = getP2shBuilder(1);
|
||||||
|
b.sign(testdata.dataUnspentSign.keyStringsP2sh);
|
||||||
|
b.isFullySigned().should.equal(true);
|
||||||
|
var tx = b.build();
|
||||||
|
tx.ins.length.should.equal(1);
|
||||||
|
tx.outs.length.should.equal(2);
|
||||||
|
tx.isComplete().should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should sign in steps a p2sh/multisign tx', function() {
|
||||||
|
var b = getP2shBuilder(1);
|
||||||
|
|
||||||
|
var k1 = testdata.dataUnspentSign.keyStringsP2sh.slice(0,1);
|
||||||
|
var k2 = testdata.dataUnspentSign.keyStringsP2sh.slice(1,2);
|
||||||
|
var k5 = testdata.dataUnspentSign.keyStringsP2sh.slice(4,5);
|
||||||
|
b.isFullySigned().should.equal(false);
|
||||||
|
|
||||||
|
b.sign(k1);
|
||||||
|
b.isFullySigned().should.equal(false);
|
||||||
|
|
||||||
|
var tx = b.build();
|
||||||
|
tx.ins.length.should.equal(1);
|
||||||
|
tx.outs.length.should.equal(2);
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
|
||||||
|
// Sign with the same
|
||||||
|
b.sign(k1);
|
||||||
|
b.isFullySigned().should.equal(false);
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
|
||||||
|
// Sign with k5
|
||||||
|
b.sign(k5);
|
||||||
|
///
|
||||||
|
b.isFullySigned().should.equal(false);
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
|
||||||
|
// Sign with same
|
||||||
|
b.sign(k5);
|
||||||
|
b.isFullySigned().should.equal(false);
|
||||||
|
tx.isComplete().should.equal(false);
|
||||||
|
|
||||||
|
|
||||||
|
// Sign k2
|
||||||
|
b.sign(k2);
|
||||||
|
b.isFullySigned().should.equal(true);
|
||||||
|
tx.isComplete().should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sign in steps a p2sh/p2pubkeyhash tx', function() {
|
||||||
|
var priv = 'cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA';
|
||||||
|
var network = 'testnet';
|
||||||
|
var opts = {
|
||||||
|
remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'},
|
||||||
|
};
|
||||||
|
// p2hash/ p2sh
|
||||||
|
var p2shOpts = {address:'mgwqzy6pF5BSc72vxHBFSnnhNEBcV4TJzV', amount:0.05};
|
||||||
|
var info = TransactionBuilder.infoForP2sh(p2shOpts, network);
|
||||||
|
|
||||||
|
//addr: 2NAwCQ1jPYPrSsyBQvfP6AJ6d6SSxnHsZ4e
|
||||||
|
//hash: de09d4a9c7e53e08043efc74d14490dbcf03b0ba
|
||||||
|
//
|
||||||
|
var outs = outs || [{
|
||||||
|
address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE',
|
||||||
|
amount: 0.08
|
||||||
|
}];
|
||||||
|
//info.scriptBufHex,
|
||||||
|
|
||||||
|
var s = TransactionBuilder.scriptForAddress(info.address)
|
||||||
|
.getBuffer().toString('hex');
|
||||||
|
|
||||||
|
var b = new TransactionBuilder(opts)
|
||||||
|
.setUnspent([{
|
||||||
|
"address": info.address,
|
||||||
|
"scriptPubKey": s,
|
||||||
|
"txid": "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1",
|
||||||
|
"vout": 1,
|
||||||
|
"amount": 1,
|
||||||
|
"confirmations":7
|
||||||
|
}])
|
||||||
|
.setOutputs(outs);
|
||||||
|
|
||||||
|
var hashMap = {};
|
||||||
|
hashMap[info.address]=info.scriptBufHex;
|
||||||
|
b.setHashToScriptMap(hashMap);
|
||||||
|
b.sign([priv]);
|
||||||
|
b.isFullySigned().should.equal(true);
|
||||||
|
var tx = b.build();
|
||||||
|
tx.ins.length.should.equal(1);
|
||||||
|
tx.outs.length.should.equal(2);
|
||||||
|
tx.isComplete().should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue