improve p2sh building. change wallet key/redeem methods.
This commit is contained in:
parent
871e36c426
commit
442c984c12
@ -949,29 +949,29 @@ Pool.prototype.removeWallet = function removeWallet(w) {
|
||||
Pool.prototype.watchWallet = function watchWallet(w) {
|
||||
if (w.type === 'scripthash') {
|
||||
// For the redeem script hash in outputs:
|
||||
this.watch(w.getFullHash());
|
||||
this.watch(w.getScriptHash());
|
||||
// For the redeem script in inputs:
|
||||
this.watch(w.getFullPublicKey());
|
||||
this.watch(w.getScript());
|
||||
}
|
||||
|
||||
// For the pubkey hash in outputs:
|
||||
this.watch(w.getOwnHash());
|
||||
this.watch(w.getKeyHash());
|
||||
// For the pubkey in inputs:
|
||||
this.watch(w.getOwnPublicKey());
|
||||
this.watch(w.getPublicKey());
|
||||
};
|
||||
|
||||
Pool.prototype.unwatchWallet = function unwatchWallet(w) {
|
||||
if (w.type === 'scripthash') {
|
||||
// For the redeem script hash in p2sh outputs:
|
||||
this.unwatch(w.getFullHash());
|
||||
this.unwatch(w.getScriptHash());
|
||||
// For the redeem script in p2sh inputs:
|
||||
this.unwatch(w.getFullPublicKey());
|
||||
this.unwatch(w.getScript());
|
||||
}
|
||||
|
||||
// For the pubkey hash in p2pk/multisig outputs:
|
||||
this.unwatch(w.getOwnHash());
|
||||
this.unwatch(w.getKeyHash());
|
||||
// For the pubkey in p2pkh inputs:
|
||||
this.unwatch(w.getOwnPublicKey());
|
||||
this.unwatch(w.getPublicKey());
|
||||
};
|
||||
|
||||
Pool.prototype.searchWallet = function(w) {
|
||||
|
||||
@ -982,6 +982,26 @@ script.size = function size(s) {
|
||||
return bcoin.script.encode(s).length;
|
||||
};
|
||||
|
||||
script.normalize = function normalize(s) {
|
||||
var bytes = true;
|
||||
var i;
|
||||
|
||||
for (i = 0; bytes && i < s.length; i++) {
|
||||
if (typeof s[i] !== 'number')
|
||||
bytes = false;
|
||||
}
|
||||
|
||||
if (bytes)
|
||||
s = script.decode(s);
|
||||
|
||||
s = script.subscript(s);
|
||||
|
||||
if (script.lockTime(s))
|
||||
s = s.slice(3);
|
||||
|
||||
return s;
|
||||
};
|
||||
|
||||
script.lockTime = function lockTime(s) {
|
||||
var lock = s[0];
|
||||
var res = s.length > 3
|
||||
|
||||
130
lib/bcoin/tx.js
130
lib/bcoin/tx.js
@ -157,8 +157,8 @@ TX.prototype._inputIndex = function _inputIndex(hash, index) {
|
||||
};
|
||||
|
||||
// Build the scriptSigs for inputs, excluding the signatures
|
||||
TX.prototype.scriptInput = function scriptInput(index, pub) {
|
||||
var input, s, n, i, redeem;
|
||||
TX.prototype.scriptInput = function scriptInput(index, pub, redeem) {
|
||||
var input, s, standard, n, i;
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
@ -174,26 +174,25 @@ TX.prototype.scriptInput = function scriptInput(index, pub) {
|
||||
if (input.script.length)
|
||||
return;
|
||||
|
||||
// P2PK
|
||||
// P2SH
|
||||
if (bcoin.script.isScripthash(s)) {
|
||||
assert(redeem);
|
||||
s = bcoin.script.normalize(redeem);
|
||||
} else {
|
||||
redeem = null;
|
||||
}
|
||||
|
||||
if (bcoin.script.isPubkey(s)) {
|
||||
// P2PK
|
||||
input.script = [ [] ];
|
||||
this._recalculateFee();
|
||||
return;
|
||||
}
|
||||
|
||||
// P2PKH
|
||||
if (bcoin.script.isPubkeyhash(s)) {
|
||||
} else if (bcoin.script.isPubkeyhash(s)) {
|
||||
// P2PKH
|
||||
input.script = [ [], pub ];
|
||||
this._recalculateFee();
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE for multisig: Technically we should create m signature slots,
|
||||
// but we create n signature slots so we can order the signatures properly.
|
||||
|
||||
// Multisig
|
||||
// raw format: OP_FALSE [sig-1] [sig-2] ...
|
||||
if (bcoin.script.isMultisig(s)) {
|
||||
} else if (bcoin.script.isMultisig(s)) {
|
||||
// Bare Multisig
|
||||
// Technically we should create m signature slots,
|
||||
// but we create n signature slots so we can order
|
||||
// the signatures properly.
|
||||
input.script = [ [] ];
|
||||
n = s[s.length - 2];
|
||||
// If using pushdata instead of OP_1-16:
|
||||
@ -201,34 +200,19 @@ TX.prototype.scriptInput = function scriptInput(index, pub) {
|
||||
n = n[0] || 0;
|
||||
for (i = 0; i < n; i++)
|
||||
input.script[i + 1] = [];
|
||||
this._recalculateFee();
|
||||
return;
|
||||
}
|
||||
|
||||
// P2SH multisig
|
||||
// p2sh format: OP_FALSE [sig-1] [sig-2] ... [redeem-script]
|
||||
if (bcoin.script.isScripthash(s)) {
|
||||
input.script = [ [] ];
|
||||
redeem = bcoin.script.decode(pub);
|
||||
n = redeem[redeem.length - 2];
|
||||
// If using pushdata instead of OP_1-16:
|
||||
if (Array.isArray(n))
|
||||
n = n[0] || 0;
|
||||
for (i = 0; i < n; i++)
|
||||
input.script[i + 1] = [];
|
||||
// P2SH requires the redeem script after signatures
|
||||
input.script.push(pub);
|
||||
this._recalculateFee();
|
||||
return;
|
||||
}
|
||||
// P2SH requires the redeem script after signatures
|
||||
if (redeem)
|
||||
input.script.push(redeem);
|
||||
|
||||
throw new Error('scriptInput(): Could not identify prev_out type');
|
||||
this._recalculateFee();
|
||||
};
|
||||
|
||||
// Sign the now-built scriptSigs
|
||||
TX.prototype.signInput = function signInput(index, key, type) {
|
||||
var input, s, hash, signature;
|
||||
var len, redeem, m, keys, pub, pubn, ki, totalSigs, i;
|
||||
var len, redeem, m, keys, pub, pubn, ki, signatures, i;
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
@ -262,33 +246,30 @@ TX.prototype.signInput = function signInput(index, key, type) {
|
||||
// Add the sighash as a single byte to the signature
|
||||
signature = signature.concat(type);
|
||||
|
||||
// P2PK
|
||||
// Script length, needed for multisig
|
||||
len = input.script.length;
|
||||
|
||||
// P2SH
|
||||
if (bcoin.script.isScripthash(s)) {
|
||||
s = bcoin.script.normalize(redeem);
|
||||
// Decrement `len` to avoid the redeem script
|
||||
len--;
|
||||
}
|
||||
|
||||
if (bcoin.script.isPubkey(s)) {
|
||||
// P2PK
|
||||
input.script[0] = signature;
|
||||
return;
|
||||
}
|
||||
|
||||
// P2PKH
|
||||
if (bcoin.script.isPubkeyhash(s)) {
|
||||
} else if (bcoin.script.isPubkeyhash(s)) {
|
||||
// P2PKH
|
||||
input.script[0] = signature;
|
||||
return;
|
||||
}
|
||||
|
||||
// Multisig
|
||||
// raw format: OP_FALSE [sig-1] [sig-2] ...
|
||||
// p2sh format: OP_FALSE [sig-1] [sig-2] ... [redeem-script]
|
||||
if (bcoin.script.isMultisig(s) || bcoin.script.isScripthash(s)) {
|
||||
len = input.script.length;
|
||||
|
||||
if (bcoin.script.isScripthash(s))
|
||||
len--;
|
||||
|
||||
m = redeem[0];
|
||||
} else if (bcoin.script.isMultisig(s)) {
|
||||
// Multisig
|
||||
m = s[0];
|
||||
// If using pushdata instead of OP_1-16:
|
||||
if (Array.isArray(m))
|
||||
m = m[0] || 0;
|
||||
|
||||
keys = redeem.slice(1, -2);
|
||||
keys = s.slice(1, -2);
|
||||
pub = key.getPublic(true, 'array');
|
||||
pubn = key.getPublic(false, 'array');
|
||||
|
||||
@ -309,44 +290,35 @@ TX.prototype.signInput = function signInput(index, key, type) {
|
||||
|
||||
// Add our signature to the correct slot
|
||||
// and count the total number of signatures.
|
||||
totalSigs = 0;
|
||||
signatures = 0;
|
||||
for (i = 1; i < len; i++) {
|
||||
if (Array.isArray(input.script[i]) && input.script[i].length) {
|
||||
totalSigs++;
|
||||
signatures++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i - 1 === ki) {
|
||||
if (totalSigs >= m)
|
||||
if (signatures >= m)
|
||||
continue;
|
||||
input.script[i] = signature;
|
||||
totalSigs++;
|
||||
signatures++;
|
||||
}
|
||||
}
|
||||
|
||||
// All signatures added. Finalize by removing empty slots.
|
||||
if (totalSigs >= m) {
|
||||
if (signatures >= m) {
|
||||
for (i = len - 1; i >= 1; i--) {
|
||||
if (Array.isArray(input.script[i]) && !input.script[i].length)
|
||||
input.script.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('signInput(): Could not identify prev_out type');
|
||||
};
|
||||
|
||||
// Build the scriptSig and sign it
|
||||
TX.prototype.scriptSig = function scriptSig(index, key, pub, type) {
|
||||
TX.prototype.scriptSig = function scriptSig(index, key, pub, redeem, type) {
|
||||
var input;
|
||||
|
||||
if (!utils.isBuffer(pub)) {
|
||||
type = pub;
|
||||
pub = key.getPublic(true, 'array');
|
||||
}
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
|
||||
@ -355,7 +327,7 @@ TX.prototype.scriptSig = function scriptSig(index, key, pub, type) {
|
||||
assert(input);
|
||||
|
||||
// Build script for input
|
||||
this.scriptInput(index, pub);
|
||||
this.scriptInput(index, pub, redeem);
|
||||
|
||||
// Sign input
|
||||
this.signInput(index, key, type);
|
||||
@ -523,7 +495,7 @@ TX.prototype.getSubscript = function getSubscript(index) {
|
||||
|
||||
TX.prototype.subscriptHash = function subscriptHash(index, s, type) {
|
||||
var copy = this.clone();
|
||||
var verifyStr, hash;
|
||||
var msg, hash;
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
@ -573,11 +545,11 @@ TX.prototype.subscriptHash = function subscriptHash(index, s, type) {
|
||||
copy.inputs[0].script = s;
|
||||
}
|
||||
|
||||
verifyStr = copy.render(true);
|
||||
msg = copy.render(true);
|
||||
|
||||
utils.writeU32(verifyStr, type, verifyStr.length);
|
||||
utils.writeU32(msg, type, msg.length);
|
||||
|
||||
hash = utils.dsha256(verifyStr);
|
||||
hash = utils.dsha256(msg);
|
||||
|
||||
return hash;
|
||||
};
|
||||
|
||||
@ -81,7 +81,7 @@ function Wallet(options, passphrase) {
|
||||
this.m = 1;
|
||||
this.n = 1;
|
||||
|
||||
this.prefix = 'bt/wallet/' + this.getOwnAddress() + '/';
|
||||
this.prefix = 'bt/wallet/' + this.getKeyAddress() + '/';
|
||||
|
||||
this.multisig(options.multisig || {});
|
||||
|
||||
@ -126,7 +126,7 @@ Wallet.prototype._init = function init() {
|
||||
};
|
||||
|
||||
Wallet.prototype.multisig = function multisig(options) {
|
||||
var pub = this.getOwnPublicKey();
|
||||
var pub = this.getPublicKey();
|
||||
|
||||
options.type = options.type || options.prefix;
|
||||
options.keys = options.keys || options.pubkeys || [];
|
||||
@ -235,21 +235,21 @@ Wallet.prototype.getPrivateKey = function getPrivateKey(enc) {
|
||||
return priv;
|
||||
};
|
||||
|
||||
Wallet.prototype.getFullPublicKey = function getFullPublicKey(enc) {
|
||||
var pub = this.getOwnPublicKey();
|
||||
|
||||
if (this.type === 'scripthash')
|
||||
pub = bcoin.script.encode(bcoin.script.redeem(this.keys, this.m, this.n));
|
||||
|
||||
if (enc === 'base58')
|
||||
return utils.toBase58(pub);
|
||||
else if (enc === 'hex')
|
||||
return utils.toHex(pub);
|
||||
else
|
||||
return pub;
|
||||
Wallet.prototype.getScript = function getScript(enc) {
|
||||
if (this.redeem)
|
||||
return this.redeem.slice();
|
||||
return bcoin.script.encode(bcoin.script.redeem(this.keys, this.m, this.n));
|
||||
};
|
||||
|
||||
Wallet.prototype.getOwnPublicKey = function getOwnPublicKey(enc) {
|
||||
Wallet.prototype.getScriptHash = function getScriptHash() {
|
||||
return utils.ripesha(this.getScript());
|
||||
};
|
||||
|
||||
Wallet.prototype.getScriptAddress = function getScriptAddress() {
|
||||
return Wallet.hash2addr(this.getScriptHash(), this.type);
|
||||
};
|
||||
|
||||
Wallet.prototype.getPublicKey = function getPublicKey(enc) {
|
||||
var pub = this.key.getPublic(this.compressed, 'array');
|
||||
|
||||
if (enc === 'base58')
|
||||
@ -260,32 +260,24 @@ Wallet.prototype.getOwnPublicKey = function getOwnPublicKey(enc) {
|
||||
return pub;
|
||||
};
|
||||
|
||||
Wallet.prototype.getPublicKey = function getPublicKey(enc) {
|
||||
return this.getFullPublicKey(enc);
|
||||
Wallet.prototype.getKeyHash = function getKeyHash() {
|
||||
return Wallet.key2hash(this.getPublicKey());
|
||||
};
|
||||
|
||||
Wallet.prototype.getFullHash = function getFullHash() {
|
||||
return Wallet.key2hash(this.getFullPublicKey());
|
||||
};
|
||||
|
||||
Wallet.prototype.getFullAddress = function getFullAddress() {
|
||||
return Wallet.hash2addr(this.getFullHash(), this.type);
|
||||
};
|
||||
|
||||
Wallet.prototype.getOwnHash = function getOwnHash() {
|
||||
return Wallet.key2hash(this.getOwnPublicKey());
|
||||
};
|
||||
|
||||
Wallet.prototype.getOwnAddress = function getOwnAddress() {
|
||||
return Wallet.hash2addr(this.getOwnHash(), 'pubkeyhash');
|
||||
Wallet.prototype.getKeyAddress = function getKeyAddress() {
|
||||
return Wallet.hash2addr(this.getKeyHash(), 'pubkeyhash');
|
||||
};
|
||||
|
||||
Wallet.prototype.getHash = function getHash() {
|
||||
return Wallet.key2hash(this.getFullPublicKey());
|
||||
if (this.type === 'scripthash')
|
||||
return this.getScriptHash();
|
||||
return this.getKeyHash();
|
||||
};
|
||||
|
||||
Wallet.prototype.getAddress = function getAddress() {
|
||||
return Wallet.hash2addr(this.getFullHash(), this.type);
|
||||
if (this.type === 'scripthash')
|
||||
return this.getScriptAddress();
|
||||
return this.getKeyAddress();
|
||||
};
|
||||
|
||||
Wallet.key2hash = function key2hash(key) {
|
||||
@ -351,9 +343,9 @@ Wallet.validateAddress = function validateAddress(addr, prefix) {
|
||||
};
|
||||
|
||||
Wallet.prototype.ownOutput = function ownOutput(tx, index) {
|
||||
var scriptHash = this.getFullHash();
|
||||
var hash = this.getOwnHash();
|
||||
var key = this.getOwnPublicKey();
|
||||
var scripthash = this.getScriptHash();
|
||||
var hash = this.getKeyHash();
|
||||
var key = this.getPublicKey();
|
||||
var keys = this.keys;
|
||||
|
||||
var outputs = tx.outputs.filter(function(output, i) {
|
||||
@ -371,7 +363,7 @@ Wallet.prototype.ownOutput = function ownOutput(tx, index) {
|
||||
if (bcoin.script.isMultisig(s, keys))
|
||||
return true;
|
||||
|
||||
if (bcoin.script.isScripthash(s, scriptHash))
|
||||
if (bcoin.script.isScripthash(s, scripthash))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -384,10 +376,10 @@ Wallet.prototype.ownOutput = function ownOutput(tx, index) {
|
||||
};
|
||||
|
||||
Wallet.prototype.ownInput = function ownInput(tx, index) {
|
||||
var scriptHash = this.getFullHash();
|
||||
var hash = this.getOwnHash();
|
||||
var key = this.getOwnPublicKey();
|
||||
var redeem = this.getFullPublicKey();
|
||||
var scripthash = this.getScriptHash();
|
||||
var hash = this.getKeyHash();
|
||||
var key = this.getPublicKey();
|
||||
var redeem = this.getScript();
|
||||
var keys = this.keys;
|
||||
|
||||
var inputs = tx.inputs.filter(function(input, i) {
|
||||
@ -425,7 +417,7 @@ Wallet.prototype.ownInput = function ownInput(tx, index) {
|
||||
if (bcoin.script.isMultisig(s, keys))
|
||||
return true;
|
||||
|
||||
if (bcoin.script.isScripthash(s, scriptHash))
|
||||
if (bcoin.script.isScripthash(s, scripthash))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -445,12 +437,13 @@ Wallet.prototype.scriptOutputs = function scriptOutputs(tx, options) {
|
||||
};
|
||||
|
||||
Wallet.prototype.fillUnspent = function fillUnspent(tx, changeAddress) {
|
||||
changeAddress = changeAddress || this.changeAddress || this.getFullAddress();
|
||||
changeAddress = changeAddress || this.changeAddress || this.getAddress();
|
||||
return tx.fillUnspent(this.unspent(), changeAddress);
|
||||
};
|
||||
|
||||
Wallet.prototype.scriptInputs = function scriptInputs(tx) {
|
||||
var pub = this.getFullPublicKey();
|
||||
var pub = this.getPublicKey();
|
||||
var redeem = this.getScript();
|
||||
var inputs = tx.inputs;
|
||||
|
||||
inputs = inputs.filter(function(input, i) {
|
||||
@ -461,7 +454,7 @@ Wallet.prototype.scriptInputs = function scriptInputs(tx) {
|
||||
if (!input.out.tx || !this.ownOutput(input.out.tx))
|
||||
return false;
|
||||
|
||||
tx.scriptInput(i, pub);
|
||||
tx.scriptInput(i, pub, redeem);
|
||||
|
||||
return true;
|
||||
}, this);
|
||||
@ -495,7 +488,8 @@ Wallet.prototype.sign = function sign(tx, type) {
|
||||
if (!type)
|
||||
type = 'all';
|
||||
|
||||
var pub = this.getFullPublicKey();
|
||||
var pub = this.getPublicKey();
|
||||
var redeem = this.getScript();
|
||||
var key = this.key;
|
||||
var inputs = tx.inputs;
|
||||
|
||||
@ -508,7 +502,7 @@ Wallet.prototype.sign = function sign(tx, type) {
|
||||
if (!input.out.tx || !this.ownOutput(input.out.tx))
|
||||
return false;
|
||||
|
||||
tx.scriptSig(i, key, pub, type);
|
||||
tx.scriptSig(i, key, pub, redeem, type);
|
||||
|
||||
return true;
|
||||
}, this);
|
||||
@ -584,8 +578,8 @@ Wallet.prototype.toAddress = function toAddress() {
|
||||
});
|
||||
|
||||
return {
|
||||
address: this.getFullAddress(),
|
||||
hash: utils.toHex(this.getFullHash()),
|
||||
address: this.getAddress(),
|
||||
hash: utils.toHex(this.getHash()),
|
||||
received: received,
|
||||
sent: sent,
|
||||
balance: this.balance(),
|
||||
@ -602,7 +596,7 @@ Wallet.prototype.toJSON = function toJSON(encrypt) {
|
||||
label: this.label,
|
||||
address: this.getAddress(),
|
||||
balance: utils.toBTC(this.balance()),
|
||||
pub: this.getOwnPublicKey('base58'),
|
||||
pub: this.getPublicKey('base58'),
|
||||
priv: encrypt
|
||||
? encrypt(this.getPrivateKey('base58'))
|
||||
: this.getPrivateKey('base58'),
|
||||
|
||||
@ -81,7 +81,7 @@ describe('Wallet', function() {
|
||||
});
|
||||
var k2 = w.getPublicKey().concat(1);
|
||||
w.addKey(k2);
|
||||
assert.equal(w.getOwnAddress(), w.getFullAddress());
|
||||
assert.equal(w.getKeyAddress(), w.getAddress());
|
||||
|
||||
// Input transcation
|
||||
var src = bcoin.tx({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user