wallet work. consistency.

This commit is contained in:
Christopher Jeffrey 2016-02-02 16:09:48 -08:00
parent f3fd85354e
commit 2deccde29e
10 changed files with 491 additions and 278 deletions

View File

@ -87,8 +87,8 @@ function Address(options) {
this.addKey(key); this.addKey(key);
}, this); }, this);
if (options.redeem) if (options.redeem || options.script)
this.setRedeem(options.redeem); this.setRedeem(options.redeem || options.script);
this.prefix = 'bt/address/' + this.getKeyAddress() + '/'; this.prefix = 'bt/address/' + this.getKeyAddress() + '/';
} }
@ -104,7 +104,7 @@ Address.prototype.setRedeem = function setRedeem(redeem) {
this.type = 'scripthash'; this.type = 'scripthash';
this.subtype = null; this.subtype = null;
this.redeem = redeem; this.redeem = redeem;
this.emit('scriptaddress', old, this.getScriptAddress()); this.emit('update script', old, this.getScriptAddress());
}; };
Address.prototype.addKey = function addKey(key) { Address.prototype.addKey = function addKey(key) {
@ -124,10 +124,15 @@ Address.prototype.addKey = function addKey(key) {
this.keys = utils.sortKeys(this.keys); this.keys = utils.sortKeys(this.keys);
delete this._scriptAddress;
delete this._scriptHash;
delete this._script;
this.getScriptAddress();
cur = this.getScriptAddress(); cur = this.getScriptAddress();
if (old !== cur) if (old !== cur)
this.emit('scriptaddress', old, cur); this.emit('update script', old, cur);
}; };
Address.prototype.removeKey = function removeKey(key) { Address.prototype.removeKey = function removeKey(key) {
@ -149,10 +154,15 @@ Address.prototype.removeKey = function removeKey(key) {
this.keys = utils.sortKeys(this.keys); this.keys = utils.sortKeys(this.keys);
delete this._scriptAddress;
delete this._scriptHash;
delete this._script;
this.getScriptAddress();
cur = this.getScriptAddress(); cur = this.getScriptAddress();
if (old !== cur) if (old !== cur)
this.emit('scriptaddress', old, this.getScriptAddress()); this.emit('update script', old, cur);
}; };
Address.prototype.getPrivateKey = function getPrivateKey(enc) { Address.prototype.getPrivateKey = function getPrivateKey(enc) {
@ -171,51 +181,82 @@ Address.prototype.getScript = function getScript() {
if (this.type !== 'scripthash') if (this.type !== 'scripthash')
return; return;
if (this._script)
return this._script;
if (this.redeem) if (this.redeem)
return this.redeem.slice(); return this._script = this.redeem.slice();
if (this.subtype === 'pubkey') if (this.subtype === 'pubkey')
return bcoin.script.encode([this.getPublicKey(), 'checksig']); this._script = bcoin.script.createPubkey(this.getPublicKey());
else if (this.subtype === 'pubkeyhash' || this.keys.length < this.n)
this._script = bcoin.script.createPubkeyhash(this.getKeyHash());
else if (this.subtype === 'multisig')
this._script = bcoin.script.createMultisig(this.keys, this.m, this.n);
else
assert(false);
if (this.subtype === 'pubkeyhash' || this.keys.length < this.n) { this._script = bcoin.script.encode(this._script);
return bcoin.script.encode([
'dup',
'hash160',
this.getKeyHash(),
'equalverify',
'checksig'
]);
}
return bcoin.script.encode( return this._script;
bcoin.script.createMultisig(this.keys, this.m, this.n)
);
}; };
Address.prototype.getScriptHash = function getScriptHash() { Address.prototype.getScriptHash = function getScriptHash() {
if (this.type !== 'scripthash') if (this.type !== 'scripthash')
return; return;
return utils.ripesha(this.getScript()); if (this._scriptHash)
return this._scriptHash;
this._scriptHash = utils.ripesha(this.getScript());
return this._scriptHash;
}; };
Address.prototype.getScriptAddress = function getScriptAddress() { Address.prototype.getScriptAddress = function getScriptAddress() {
if (this.type !== 'scripthash') if (this.type !== 'scripthash')
return; return;
return Address.hash2addr(this.getScriptHash(), this.type); if (this._scriptAddress)
return this._scriptAddress;
this._scriptAddress = Address.hash2addr(this.getScriptHash(), this.type);
return this._scriptAddress;
}; };
Address.prototype.getPublicKey = function getPublicKey(enc) { Address.prototype.getPublicKey = function getPublicKey(enc) {
if (!this.key.priv)
return;
if (!enc) {
if (this._pub)
return this._pub;
this._pub = this.key.getPublic();
return this._pub;
}
return this.key.getPublic(enc); return this.key.getPublic(enc);
}; };
Address.prototype.getKeyHash = function getKeyHash() { Address.prototype.getKeyHash = function getKeyHash() {
return Address.key2hash(this.getPublicKey()); if (this._hash)
return this._hash;
this._hash = Address.key2hash(this.getPublicKey());
return this._hash;
}; };
Address.prototype.getKeyAddress = function getKeyAddress() { Address.prototype.getKeyAddress = function getKeyAddress() {
return Address.hash2addr(this.getKeyHash(), 'pubkeyhash'); if (this._address)
return this._address;
this._address = Address.hash2addr(this.getKeyHash(), 'pubkeyhash');
return this._address;
}; };
Address.prototype.getHash = function getHash() { Address.prototype.getHash = function getHash() {
@ -248,6 +289,10 @@ Address.hash2addr = function hash2addr(hash, prefix) {
return utils.toBase58(addr); return utils.toBase58(addr);
}; };
Address.key2addr = function key2addr(key, prefix) {
return Address.hash2addr(Address.key2hash(key), prefix);
};
Address.__defineGetter__('prefixes', function() { Address.__defineGetter__('prefixes', function() {
if (Address._prefixes) if (Address._prefixes)
return Address._prefixes; return Address._prefixes;
@ -286,7 +331,7 @@ Address.addr2hash = function addr2hash(addr, prefix) {
return addr.slice(1, -4); return addr.slice(1, -4);
}; };
Address.validate = function validateAddress(addr, prefix) { Address.validate = function validate(addr, prefix) {
if (!addr || typeof addr !== 'string') if (!addr || typeof addr !== 'string')
return false; return false;
@ -298,12 +343,13 @@ Address.validate = function validateAddress(addr, prefix) {
Address.validateAddress = Address.validate; Address.validateAddress = Address.validate;
Address.prototype.ownOutput = function ownOutput(tx, index) { Address.prototype.ownOutput = function ownOutput(tx, index) {
var scripthash = this.getScriptHash(); var scriptHash = this.getScriptHash();
var hash = this.getKeyHash(); var hash = this.getKeyHash();
var key = this.getPublicKey(); var key = this.getPublicKey();
var keys = this.keys; var keys = this.keys;
var outputs;
var outputs = tx.outputs.filter(function(output, i) { outputs = tx.outputs.filter(function(output, i) {
var s = output.script; var s = output.script;
if (index != null && index !== i) if (index != null && index !== i)
@ -318,8 +364,8 @@ Address.prototype.ownOutput = function ownOutput(tx, index) {
if (bcoin.script.isMultisig(s, keys)) if (bcoin.script.isMultisig(s, keys))
return true; return true;
if (scripthash) { if (scriptHash) {
if (bcoin.script.isScripthash(s, scripthash)) if (bcoin.script.isScripthash(s, scriptHash))
return true; return true;
} }
@ -333,13 +379,14 @@ Address.prototype.ownOutput = function ownOutput(tx, index) {
}; };
Address.prototype.ownInput = function ownInput(tx, index) { Address.prototype.ownInput = function ownInput(tx, index) {
var scripthash = this.getScriptHash(); var scriptHash = this.getScriptHash();
var hash = this.getKeyHash(); var hash = this.getKeyHash();
var key = this.getPublicKey(); var key = this.getPublicKey();
var redeem = this.getScript(); var redeem = this.getScript();
var keys = this.keys; var keys = this.keys;
var inputs;
var inputs = tx.inputs.filter(function(input, i) { inputs = tx.inputs.filter(function(input, i) {
var s; var s;
if (!input.prevout.tx && this.tx._all[input.prevout.hash]) if (!input.prevout.tx && this.tx._all[input.prevout.hash])
@ -376,8 +423,8 @@ Address.prototype.ownInput = function ownInput(tx, index) {
if (bcoin.script.isMultisig(s, keys)) if (bcoin.script.isMultisig(s, keys))
return true; return true;
if (scripthash) { if (scriptHash) {
if (bcoin.script.isScripthash(s, scripthash)) if (bcoin.script.isScripthash(s, scriptHash))
return true; return true;
} }
@ -390,6 +437,108 @@ Address.prototype.ownInput = function ownInput(tx, index) {
return inputs; return inputs;
}; };
Address.prototype.scriptInputs = function scriptInputs(tx) {
var self = this;
var pub = this.getPublicKey();
var redeem = this.getScript();
return tx.inputs.reduce(function(total, input, i) {
if (!input.prevout.tx)
return total;
if (!self.ownOutput(input.prevout.tx, input.prevout.index))
return total;
if (tx.scriptInput(i, pub, redeem))
total++;
return total;
}, 0);
};
Address.prototype.signInputs = function signInputs(tx, type) {
var self = this;
var key = this.key;
var total = 0;
if (!key.priv)
return 0;
return tx.inputs.reduce(function(total, input, i) {
if (!input.prevout.tx)
return total;
if (!self.ownOutput(input.prevout.tx, input.prevout.index))
return total;
if (tx.signInput(i, key, type))
total++;
return total;
}, 0);
};
Address.prototype.sign = function sign(tx, type) {
var self = this;
var pub = this.getPublicKey();
var redeem = this.getScript();
var key = this.key;
if (!key.priv)
return 0;
// Add signature script to each input
return tx.inputs.reduce(function(total, input, i) {
// Filter inputs that this wallet own
if (!input.prevout.tx)
return total;
if (!self.ownOutput(input.prevout.tx, input.prevout.index))
return total;
if (tx.scriptSig(i, key, pub, redeem, type))
total++;
return total;
}, 0);
};
Address.prototype.__defineGetter__('script', function() {
return this.getScript();
});
Address.prototype.__defineGetter__('scriptHash', function() {
return this.getScriptHash();
});
Address.prototype.__defineGetter__('scriptAddress', function() {
return this.getScriptAddress();
});
Address.prototype.__defineGetter__('privateKey', function() {
return this.getPrivateKey();
});
Address.prototype.__defineGetter__('publicKey', function() {
return this.getPublicKey();
});
Address.prototype.__defineGetter__('keyHash', function() {
return this.getKeyHash();
});
Address.prototype.__defineGetter__('keyAddress', function() {
return this.getKeyAddress();
});
Address.prototype.__defineGetter__('hash', function() {
return this.getHash();
});
Address.prototype.__defineGetter__('address', function() {
return this.getAddress();
});
Address.prototype.toJSON = function toJSON(encrypt) { Address.prototype.toJSON = function toJSON(encrypt) {
return { return {
v: 1, v: 1,
@ -398,7 +547,7 @@ Address.prototype.toJSON = function toJSON(encrypt) {
label: this.label, label: this.label,
change: this.change, change: this.change,
address: this.getKeyAddress(), address: this.getKeyAddress(),
scriptaddress: this.getScriptAddress(), scriptAddress: this.getScriptAddress(),
key: this.key.toJSON(encrypt), key: this.key.toJSON(encrypt),
type: this.type, type: this.type,
subtype: this.subtype, subtype: this.subtype,

View File

@ -21,6 +21,8 @@ function Input(options) {
prevout = options.prevout || options.out; prevout = options.prevout || options.out;
this.tx = options.tx;
this.prevout = { this.prevout = {
tx: prevout.tx || null, tx: prevout.tx || null,
hash: prevout.hash, hash: prevout.hash,
@ -66,8 +68,10 @@ Input.prototype.__defineGetter__('data', function() {
data = Input.getData(this); data = Input.getData(this);
if (this.script.length && this.prevout.tx) if (!this.tx || this.tx.ps === 0) {
utils.hidden(this, '_data', data); if (this.script.length && this.prevout.tx)
utils.hidden(this, '_data', data);
}
return data; return data;
}); });
@ -89,11 +93,11 @@ Input.prototype.__defineGetter__('key', function() {
}); });
Input.prototype.__defineGetter__('hash', function() { Input.prototype.__defineGetter__('hash', function() {
return this.data.scripthash || this.hashes[0]; return this.data.scriptHash || this.hashes[0];
}); });
Input.prototype.__defineGetter__('address', function() { Input.prototype.__defineGetter__('address', function() {
return this.data.scriptaddress || this.addresses[0] || this.getID(); return this.data.scriptAddress || this.addresses[0] || this.getID();
}); });
Input.prototype.__defineGetter__('signatures', function() { Input.prototype.__defineGetter__('signatures', function() {
@ -116,12 +120,12 @@ Input.prototype.__defineGetter__('redeem', function() {
return this.data.redeem; return this.data.redeem;
}); });
Input.prototype.__defineGetter__('scripthash', function() { Input.prototype.__defineGetter__('scriptHash', function() {
return this.data.scripthash; return this.data.scriptHash;
}); });
Input.prototype.__defineGetter__('scriptaddress', function() { Input.prototype.__defineGetter__('scriptAddress', function() {
return this.data.scriptaddress; return this.data.scriptAddress;
}); });
Input.prototype.__defineGetter__('m', function() { Input.prototype.__defineGetter__('m', function() {
@ -132,10 +136,10 @@ Input.prototype.__defineGetter__('n', function() {
return this.data.n || this.m; return this.data.n || this.m;
}); });
Input.prototype.__defineGetter__('lockTime', function() { Input.prototype.__defineGetter__('locktime', function() {
if (!this.output) if (!this.output)
return 0; return 0;
return this.output.lockTime; return this.output.locktime;
}); });
Input.prototype.__defineGetter__('flags', function() { Input.prototype.__defineGetter__('flags', function() {
@ -187,7 +191,7 @@ Input.prototype.__defineGetter__('sigs', function() {
}); });
Input.prototype.__defineGetter__('scriptaddr', function() { Input.prototype.__defineGetter__('scriptaddr', function() {
return this.scriptaddress; return this.scriptAddress;
}); });
// Schema and defaults for data object: // Schema and defaults for data object:
@ -200,14 +204,14 @@ Input.prototype.__defineGetter__('scriptaddr', function() {
// hashes: Array, // hashes: Array,
// addresses: Array, // addresses: Array,
// redeem: Array, // redeem: Array,
// scripthash: Array, // scriptHash: Array,
// scriptaddress: String, // scriptAddress: String,
// m: Number, // m: Number,
// n: Number, // n: Number,
// height: Number, // height: Number,
// flags: Array, // flags: Array,
// text: String, // text: String,
// lockTime: Number, // locktime: Number,
// value: bn, // value: bn,
// script: Array, // script: Array,
// seq: Number, // seq: Number,
@ -281,6 +285,49 @@ Input.prototype.getLocktime = function getLocktime() {
return bcoin.script.getLocktime(redeem); return bcoin.script.getLocktime(redeem);
}; };
Input.prototype.createScript = function createScript(pub, redeem) {
return this.tx.scriptInput(this, pub, redeem);
};
Input.prototype.signatureHash = function signatureHash(s, type) {
return this.tx.signatureHash(this, s, type);
};
Input.prototype.createSignature = function createSignature(key, type) {
return this.tx.createSignature(this, key, type);
};
Input.prototype.sign = function sign(key, type) {
return this.tx.signInput(this, key, type);
};
Input.prototype.scriptSig = function scriptSig(key, pub, redeem, type) {
return this.tx.scriptSig(this, key, pub, redeem, type);
};
Input.prototype.isSigned = function isSigned(required) {
return this.tx.isSigned(this, required);
};
Input.prototype.verify = function verify(force, flags) {
return this.tx.verify(this, force, flags);
};
Input.prototype.isCoinbase = function isCoinbase() {
return this.tx.isCoinbase();
};
Input.prototype.test = function test(addressTable, collect) {
return this.tx.testInputs(addressTable, this, collect);
};
Input.prototype.getSigops = function getSigops(scriptHash, accurate) {
var n = bcoin.script.getSigops(this.script, accurate);
if (scriptHash && !this.tx.isCoinbase())
n += bcoin.script.getScripthashSigops(this.script);
return n;
};
Input.prototype.inspect = function inspect() { Input.prototype.inspect = function inspect() {
var output = this.output var output = this.output
? this.output.inspect() ? this.output.inspect()
@ -297,10 +344,10 @@ Input.prototype.inspect = function inspect() {
keys: this.keys.map(utils.toHex), keys: this.keys.map(utils.toHex),
hashes: this.hashes.map(utils.toHex), hashes: this.hashes.map(utils.toHex),
addresses: this.addresses, addresses: this.addresses,
scriptaddress: this.scriptaddress, scriptAddress: this.scriptAddress,
signatures: this.signatures.map(utils.toHex), signatures: this.signatures.map(utils.toHex),
text: this.text, text: this.text,
lockTime: this.lockTime, locktime: this.locktime,
value: utils.btc(output.value), value: utils.btc(output.value),
script: bcoin.script.format(this.script)[0], script: bcoin.script.format(this.script)[0],
redeem: this.redeem ? bcoin.script.format(this.redeem)[0] : null, redeem: this.redeem ? bcoin.script.format(this.redeem)[0] : null,

View File

@ -25,6 +25,7 @@ function Output(options) {
if (typeof value === 'number' && (value | 0) === value) if (typeof value === 'number' && (value | 0) === value)
value = new bn(value); value = new bn(value);
this.tx = options.tx;
this.value = utils.satoshi(value || new bn(0)); this.value = utils.satoshi(value || new bn(0));
this.script = options.script ? options.script.slice() : []; this.script = options.script ? options.script.slice() : [];
@ -47,8 +48,10 @@ Output.prototype.__defineGetter__('data', function() {
data = Output.getData(this); data = Output.getData(this);
if (this.script.length && this.value.cmpn(0) !== 0) if (!this.tx || this.tx.ps === 0) {
utils.hidden(this, '_data', data); if (this.script.length && this.value.cmpn(0) > 0)
utils.hidden(this, '_data', data);
}
return data; return data;
}); });
@ -66,11 +69,11 @@ Output.prototype.__defineGetter__('key', function() {
}); });
Output.prototype.__defineGetter__('hash', function() { Output.prototype.__defineGetter__('hash', function() {
return this.data.scripthash || this.hashes[0]; return this.data.scriptHash || this.hashes[0];
}); });
Output.prototype.__defineGetter__('address', function() { Output.prototype.__defineGetter__('address', function() {
return this.data.scriptaddress || this.addresses[0] || this.getID(); return this.data.scriptAddress || this.addresses[0] || this.getID();
}); });
Output.prototype.__defineGetter__('signatures', function() { Output.prototype.__defineGetter__('signatures', function() {
@ -89,12 +92,12 @@ Output.prototype.__defineGetter__('addresses', function() {
return this.data.addresses || []; return this.data.addresses || [];
}); });
Output.prototype.__defineGetter__('scripthash', function() { Output.prototype.__defineGetter__('scriptHash', function() {
return this.data.scripthash; return this.data.scriptHash;
}); });
Output.prototype.__defineGetter__('scriptaddress', function() { Output.prototype.__defineGetter__('scriptAddress', function() {
return this.data.scriptaddress; return this.data.scriptAddress;
}); });
Output.prototype.__defineGetter__('m', function() { Output.prototype.__defineGetter__('m', function() {
@ -105,8 +108,8 @@ Output.prototype.__defineGetter__('n', function() {
return this.data.n || this.m; return this.data.n || this.m;
}); });
Output.prototype.__defineGetter__('lockTime', function() { Output.prototype.__defineGetter__('locktime', function() {
return bcoin.script.getLockTime(this.script); return bcoin.script.getLocktime(this.script);
}); });
Output.prototype.__defineGetter__('flags', function() { Output.prototype.__defineGetter__('flags', function() {
@ -117,6 +120,7 @@ Output.prototype.__defineGetter__('text', function() {
return this.data.text; return this.data.text;
}); });
// Legacy
Output.prototype.__defineGetter__('addr', function() { Output.prototype.__defineGetter__('addr', function() {
return this.address; return this.address;
}); });
@ -142,7 +146,7 @@ Output.prototype.__defineGetter__('sigs', function() {
}); });
Output.prototype.__defineGetter__('scriptaddr', function() { Output.prototype.__defineGetter__('scriptaddr', function() {
return this.scriptaddress; return this.scriptAddress;
}); });
// Schema and defaults for data object: // Schema and defaults for data object:
@ -155,14 +159,14 @@ Output.prototype.__defineGetter__('scriptaddr', function() {
// hashes: Array, // hashes: Array,
// addresses: Array, // addresses: Array,
// redeem: Array, // redeem: Array,
// scripthash: Array, // scriptHash: Array,
// scriptaddress: String, // scriptAddress: String,
// m: Number, // m: Number,
// n: Number, // n: Number,
// height: Number, // height: Number,
// flags: Array, // flags: Array,
// text: String, // text: String,
// lockTime: Number, // locktime: Number,
// value: bn, // value: bn,
// script: Array, // script: Array,
// seq: Number, // seq: Number,
@ -192,6 +196,18 @@ Output.prototype.getID = function getID() {
return '[' + this.type + ':' + hash.slice(0, 7) + ']'; return '[' + this.type + ':' + hash.slice(0, 7) + ']';
}; };
Output.prototype.createScript = function createScript(options) {
return this.tx.scriptOutput(this, options);
};
Output.prototype.test = function test(addressTable, collect) {
return this.tx.testOutputs(addressTable, this, collect);
};
Output.prototype.getSigops = function getSigops(accurate) {
return bcoin.script.getSigops(this.script, accurate);
};
Output.prototype.inspect = function inspect() { Output.prototype.inspect = function inspect() {
return { return {
type: this.type, type: this.type,
@ -199,11 +215,11 @@ Output.prototype.inspect = function inspect() {
keys: this.keys.map(utils.toHex), keys: this.keys.map(utils.toHex),
hashes: this.hashes.map(utils.toHex), hashes: this.hashes.map(utils.toHex),
addresses: this.addresses, addresses: this.addresses,
scriptaddress: this.scriptaddress, scriptAddress: this.scriptAddress,
m: this.m, m: this.m,
n: this.n, n: this.n,
text: this.text, text: this.text,
lockTime: this.lockTime, locktime: this.locktime,
value: utils.btc(this.value), value: utils.btc(this.value),
script: bcoin.script.format(this.script)[0] script: bcoin.script.format(this.script)[0]
}; };

View File

@ -301,7 +301,7 @@ Framer.tx = function tx(tx) {
off += utils.writeIntv(p, s.length, off); off += utils.writeIntv(p, s.length, off);
off += utils.copy(s, p, off, true); off += utils.copy(s, p, off, true);
} }
off += utils.writeU32(p, tx.lockTime, off); off += utils.writeU32(p, tx.locktime, off);
return p; return p;
}; };

View File

@ -461,7 +461,7 @@ Parser.prototype.parseTX = function parseTX(p) {
version: utils.read32(p, 0), version: utils.read32(p, 0),
inputs: txIn, inputs: txIn,
outputs: txOut, outputs: txOut,
lockTime: utils.readU32(p, off), locktime: utils.readU32(p, off),
_off: off + 4, _off: off + 4,
_size: p.length _size: p.length
}; };

View File

@ -386,7 +386,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
var key, sig, type, subscript, hash; var key, sig, type, subscript, hash;
var keys, i, j, m; var keys, i, j, m;
var succ; var succ;
var lockTime, threshold; var locktime, threshold;
var evalScript; var evalScript;
stack.alt = stack.alt || []; stack.alt = stack.alt || [];
@ -934,28 +934,28 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
if (!tx || stack.length === 0) if (!tx || stack.length === 0)
return false; return false;
lockTime = stack[stack.length - 1]; locktime = stack[stack.length - 1];
if (!Array.isArray(lockTime)) if (!Array.isArray(locktime))
return false; return false;
if (lockTime.length > 6) if (locktime.length > 6)
return false; return false;
lockTime = script.num(lockTime, true); locktime = script.num(locktime, true);
if (lockTime < 0) if (locktime < 0)
return false; return false;
threshold = constants.locktimeThreshold; threshold = constants.locktimeThreshold;
if (!( if (!(
(tx.lockTime < threshold && lockTime < threshold) (tx.locktime < threshold && locktime < threshold)
|| (tx.lockTime >= threshold && lockTime >= threshold) || (tx.locktime >= threshold && locktime >= threshold)
)) { )) {
return false; return false;
} }
if (lockTime > tx.lockTime) if (locktime > tx.locktime)
return false; return false;
if (!tx.inputs[index] || tx.inputs[index].seq === 0xffffffff) if (!tx.inputs[index] || tx.inputs[index].seq === 0xffffffff)
@ -1158,6 +1158,20 @@ script.checkPush = function checkPush(op, value, flags) {
return true; return true;
}; };
script.createPubkey = function createPubkey(key) {
return [key, 'checksig'];
};
script.createPubkeyhash = function createPubkeyhash(hash) {
return [
'dup',
'hash160',
hash,
'equalverify',
'checksig'
];
};
script.createMultisig = function createMultisig(keys, m, n) { script.createMultisig = function createMultisig(keys, m, n) {
if (keys.length !== n) if (keys.length !== n)
throw new Error(n + ' keys are required to generate multisig script'); throw new Error(n + ' keys are required to generate multisig script');
@ -1171,15 +1185,21 @@ script.createMultisig = function createMultisig(keys, m, n) {
); );
}; };
script.createScripthash = function createScripthash(s) { script.createScripthash = function createScripthash(hash) {
assert(Array.isArray(s));
return [ return [
'hash160', 'hash160',
utils.ripesha(script.encode(s)), hash,
'equal' 'equal'
]; ];
}; };
script.createNulldata = function createNulldata(flags) {
return [
'return',
flags
];
};
script.getRedeem = function getRedeem(s) { script.getRedeem = function getRedeem(s) {
if (!Array.isArray(s[s.length - 1])) if (!Array.isArray(s[s.length - 1]))
return; return;
@ -1247,7 +1267,7 @@ script.isEncoded = function isEncoded(s) {
return true; return true;
}; };
script._lockTime = function _lockTime(s) { script._locktime = function _locktime(s) {
var i; var i;
if (s.length < 2) if (s.length < 2)
@ -1259,22 +1279,22 @@ script._lockTime = function _lockTime(s) {
} }
}; };
script.isLockTime = function isLockTime(s) { script.isLocktime = function isLocktime(s) {
return !!script._lockTime(s); return !!script._locktime(s);
}; };
script.getLockTime = function getLockTime(s) { script.getLocktime = function getLocktime(s) {
var lockTime = script._lockTime(s); var locktime = script._locktime(s);
if (!lockTime) if (!locktime)
return; return;
lockTime = script.num(lockTime, true); locktime = script.num(locktime, true);
if (lockTime < constants.locktimeThreshold) if (locktime < constants.locktimeThreshold)
return { type: 'height', value: lockTime }; return { type: 'height', value: locktime };
return { type: 'time', value: lockTime }; return { type: 'time', value: locktime };
}; };
script.getInputData = function getData(s, prev) { script.getInputData = function getData(s, prev) {
@ -1320,7 +1340,7 @@ script.getInputData = function getData(s, prev) {
}; };
script._getInputData = function _getInputData(s, type) { script._getInputData = function _getInputData(s, type) {
var sig, key, hash, raw, redeem, lockTime, hash, address, input, output; var sig, key, hash, raw, redeem, locktime, hash, address, input, output;
assert(typeof type === 'string'); assert(typeof type === 'string');
@ -1363,7 +1383,7 @@ script._getInputData = function _getInputData(s, type) {
if (type === 'scripthash') { if (type === 'scripthash') {
raw = s[s.length - 1]; raw = s[s.length - 1];
redeem = script.decode(raw); redeem = script.decode(raw);
lockTime = script.getLockTime(redeem); locktime = script.getLocktime(redeem);
hash = bcoin.wallet.key2hash(raw); hash = bcoin.wallet.key2hash(raw);
address = bcoin.wallet.hash2addr(hash, 'scripthash'); address = bcoin.wallet.hash2addr(hash, 'scripthash');
output = script.getOutputData(script.getSubscript(redeem)); output = script.getOutputData(script.getSubscript(redeem));
@ -1374,9 +1394,9 @@ script._getInputData = function _getInputData(s, type) {
side: 'input', side: 'input',
subtype: output.type, subtype: output.type,
redeem: redeem, redeem: redeem,
scripthash: hash, scriptHash: hash,
scriptaddress: address, scriptAddress: address,
lockTime: lockTime locktime: locktime
}); });
} }
@ -1433,8 +1453,8 @@ script.getOutputData = function getOutputData(s) {
return { return {
type: 'scripthash', type: 'scripthash',
side: 'output', side: 'output',
scripthash: hash, scriptHash: hash,
scriptaddress: bcoin.wallet.hash2addr(hash, 'scripthash') scriptAddress: bcoin.wallet.hash2addr(hash, 'scripthash')
}; };
} }

View File

@ -233,6 +233,19 @@ TXPool.prototype._removeTX = function _removeTX(tx, noWrite) {
}); });
}; };
TXPool.prototype.prune = function prune(pruneOrphans) {
var unspent = Object.keys(this._unspent).reduce(function(key) {
out[key.split('/')[0]] = true;
return out;
}, {});
Object.keys(this._all).forEach(function(key) {
if (!unspent[key])
delete this._all[key];
});
if (pruneOrphans)
this._orphans = {};
};
TXPool.prototype.getAll = function getAll() { TXPool.prototype.getAll = function getAll() {
return Object.keys(this._all).map(function(key) { return Object.keys(this._all).map(function(key) {
return this._all[key]; return this._all[key];
@ -250,43 +263,6 @@ TXPool.prototype.getUnspent = function getUnspent() {
}, this); }, this);
}; };
TXPool.prototype.hasUnspent = function hasUnspent(hash, unspent) {
var has;
if (utils.isBuffer(hash) && hash.length && typeof hash[0] !== 'number') {
unspent = this.getUnspent();
has = hash.map(function(hash) {
var h = this.hasUnspent(hash, unspent);
if (!h)
return false;
return h[0];
}, this).filter(Boolean);
if (has.length !== hash.length)
return null;
return has;
}
if (utils.isBuffer(hash))
hash = utils.toHex(hash);
else if (hash.prevout)
hash = hash.prevout.hash;
else if (hash.tx)
hash = hash.tx.hash('hex');
else if (hash instanceof bcoin.tx)
hash = hash.hash('hex');
unspent = unspent || this.getUnspent();
has = unspent.filter(function(item) {
return item.tx.hash('hex') === hash;
});
if (!has.length)
return null;
return has;
};
TXPool.prototype.getPending = function getPending() { TXPool.prototype.getPending = function getPending() {
return Object.keys(this._all).map(function(key) { return Object.keys(this._all).map(function(key) {
return this._all[key]; return this._all[key];

View File

@ -26,14 +26,14 @@ function TX(data, block) {
this.version = data.version || 1; this.version = data.version || 1;
this.inputs = []; this.inputs = [];
this.outputs = []; this.outputs = [];
this.lockTime = data.lockTime || 0; this.locktime = data.locktime || 0;
this.ts = data.ts || 0; this.ts = data.ts || 0;
this.block = data.block || null; this.block = data.block || null;
this._hash = null; this._hash = null;
// Legacy // Legacy
if (data.lock != null) if (data.lock != null)
this.lockTime = data.lock; this.locktime = data.lock;
this._raw = data._raw || null; this._raw = data._raw || null;
this._size = data._size || 0; this._size = data._size || 0;
@ -73,19 +73,23 @@ function TX(data, block) {
// ps = Pending Since // ps = Pending Since
this.ps = this.ts === 0 ? utils.now() : 0; this.ps = this.ts === 0 ? utils.now() : 0;
// Discourage fee snipping a la bitcoind
// if (data.lockTime == null && data.lock == null)
// this.avoidFeeSnipping();
} }
// Legacy // Legacy
TX.prototype.__defineSetter__('lock', function(lockTime) { TX.prototype.__defineSetter__('lock', function(locktime) {
return this.lockTime = lockTime; return this.locktime = locktime;
}); });
TX.prototype.__defineGetter__('lock', function() { TX.prototype.__defineGetter__('lock', function() {
return this.lockTime; return this.locktime;
});
TX.prototype.__defineSetter__('lockTime', function(locktime) {
return this.locktime = locktime;
});
TX.prototype.__defineGetter__('lockTime', function() {
return this.locktime;
}); });
TX.prototype.clone = function clone() { TX.prototype.clone = function clone() {
@ -530,10 +534,9 @@ TX.prototype.signInput = function signInput(index, key, type) {
TX.prototype.scriptSig = function scriptSig(index, key, pub, redeem, type) { TX.prototype.scriptSig = function scriptSig(index, key, pub, redeem, type) {
var input; var input;
if (typeof index !== 'number') if (index && typeof index === 'object')
index = this.inputs.indexOf(index); index = this.inputs.indexOf(index);
// Get the input
input = this.inputs[index]; input = this.inputs[index];
assert(input); assert(input);
@ -551,6 +554,12 @@ TX.prototype.scriptSig = function scriptSig(index, key, pub, redeem, type) {
TX.prototype.isSigned = function isSigned(index, required) { TX.prototype.isSigned = function isSigned(index, required) {
var i, input, s, len, m, j, total; var i, input, s, len, m, j, total;
if (index && typeof index === 'object')
index = this.inputs.indexOf(index);
if (index != null)
assert(this.inputs[index]);
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i]; input = this.inputs[i];
@ -716,25 +725,19 @@ TX.prototype.scriptOutput = function scriptOutput(index, options) {
return; return;
script = bcoin.script.createMultisig(keys, m, n); script = bcoin.script.createMultisig(keys, m, n);
} else if (bcoin.wallet.validateAddress(options.address, 'scripthash')) { } else if (bcoin.address.validate(options.address, 'scripthash')) {
// P2SH Transaction // P2SH Transaction
// https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki // https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
// hash160 [20-byte-redeemscript-hash] equal // hash160 [20-byte-redeemscript-hash] equal
script = [ script = bcoin.script.createScripthash(
'hash160', bcoin.wallet.addr2hash(options.address, 'scripthash')
bcoin.wallet.addr2hash(options.address, 'scripthash'), );
'equal'
];
} else if (options.address) { } else if (options.address) {
// P2PKH Transaction // P2PKH Transaction
// dup hash160 [pubkey-hash] equalverify checksig // dup hash160 [pubkey-hash] equalverify checksig
script = [ script = bcoin.script.createPubkeyhash(
'dup', bcoin.wallet.addr2hash(options.address, 'pubkeyhash')
'hash160', );
bcoin.wallet.addr2hash(options.address, 'pubkeyhash'),
'equalverify',
'checksig'
];
} else if (options.key) { } else if (options.key) {
// P2PK Transaction // P2PK Transaction
// [pubkey] checksig // [pubkey] checksig
@ -750,36 +753,37 @@ TX.prototype.scriptOutput = function scriptOutput(index, options) {
flags = utils.ascii2array(flags); flags = utils.ascii2array(flags);
assert(utils.isBuffer(flags)); assert(utils.isBuffer(flags));
assert(flags.length <= constants.script.maxOpReturn); assert(flags.length <= constants.script.maxOpReturn);
script = [ script = bcoin.script.createNulldata(flags);
'return',
flags
];
} }
// P2SH Transaction // P2SH Transaction
// hash160 [hash] eq // hash160 [hash] eq
if (options.scripthash) { if (options.scripthash) {
if (options.lockTime != null) { if (options.locktime != null) {
script = [ script = [
bcoin.script.array(options.lockTime), bcoin.script.array(options.locktime),
'checklocktimeverify', 'checklocktimeverify',
'drop', 'drop',
'codeseparator' 'codeseparator'
].concat(script); ].concat(script);
} }
hash = utils.ripesha(bcoin.script.encode(script)); hash = utils.ripesha(bcoin.script.encode(script));
script = [ script = bcoin.script.createScripthash(hash);
'hash160',
hash,
'equal'
];
} }
output.script = script; output.script = script;
}; };
TX.prototype.getSubscript = function getSubscript(index) { TX.prototype.getSubscript = function getSubscript(index) {
var script = this.outputs[index].script; var script;
if (typeof index !== 'number')
index = this.outputs.indexOf(index);
assert(this.outputs[index]);
script = this.outputs[index].script;
return bcoin.script.getSubscript(script); return bcoin.script.getSubscript(script);
}; };
@ -877,8 +881,10 @@ TX.prototype.tbsHash = function tbsHash(enc, force) {
return this.hash(enc); return this.hash(enc);
if (!this._tbsHash || force) { if (!this._tbsHash || force) {
for (i = 0; i < copy.inputs.length; i++) for (i = 0; i < copy.inputs.length; i++) {
copy.inputs[i].script = []; if (!copy.isCoinbase())
copy.inputs[i].script = [];
}
this._tbsHash = utils.dsha256(copy.render(true)); this._tbsHash = utils.dsha256(copy.render(true));
} }
@ -896,10 +902,16 @@ TX.prototype.verify = function verify(index, force, flags) {
if (this.inputs.length === 0) if (this.inputs.length === 0)
return false; return false;
if (index && typeof index === 'object')
index = this.inputs.indexOf(index);
if (index != null)
assert(this.inputs[index]);
return this.inputs.every(function(input, i) { return this.inputs.every(function(input, i) {
var output; var output;
if (index != null && index !== i) if (index != null && i !== index)
return true; return true;
if (!input.prevout.tx) if (!input.prevout.tx)
@ -1248,24 +1260,24 @@ TX.prototype.funds = TX.prototype.getFunds;
TX.prototype.getTargetTime = function getTargetTime() { TX.prototype.getTargetTime = function getTargetTime() {
var bestValue = 0; var bestValue = 0;
var i, lockTime, bestType; var i, locktime, bestType;
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
lockTime = this.inputs[i].getLocktime(); locktime = this.inputs[i].getLocktime();
if (!lockTime) if (!locktime)
continue; continue;
// Incompatible types // Incompatible types
if (bestType && bestType !== lockTime.type) if (bestType && bestType !== locktime.type)
return; return;
bestType = lockTime.type; bestType = locktime.type;
if (lockTime.value < bestValue) if (locktime.value < bestValue)
continue; continue;
bestValue = lockTime.value; bestValue = locktime.value;
} }
return { return {
@ -1288,6 +1300,12 @@ TX.prototype.testInputs = function testInputs(addressTable, index, collect) {
}, {}); }, {});
} }
if (index && typeof index === 'object')
index = this.inputs.indexOf(index);
if (index != null)
assert(this.inputs[index]);
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
if (index != null && i !== index) if (index != null && i !== index)
continue; continue;
@ -1311,8 +1329,8 @@ TX.prototype.testInputs = function testInputs(addressTable, index, collect) {
} }
} }
if (data.scriptaddress) { if (data.scriptAddress) {
if (addressTable[data.scriptaddress] != null) { if (addressTable[data.scriptAddress] != null) {
if (!collect) if (!collect)
return true; return true;
inputs.push(input); inputs.push(input);
@ -1343,6 +1361,12 @@ TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) {
}, {}); }, {});
} }
if (index && typeof index === 'object')
index = this.outputs.indexOf(index);
if (index != null)
assert(this.outputs[index]);
for (i = 0; i < this.outputs.length; i++) { for (i = 0; i < this.outputs.length; i++) {
if (index != null && i !== index) if (index != null && i !== index)
continue; continue;
@ -1361,8 +1385,8 @@ TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) {
} }
} }
if (data.scriptaddress) { if (data.scriptAddress) {
if (addressTable[data.scriptaddress] != null) { if (addressTable[data.scriptAddress] != null) {
if (!collect) if (!collect)
return true; return true;
outputs.push(output); outputs.push(output);
@ -1383,16 +1407,16 @@ TX.prototype.avoidFeeSnipping = function avoidFeeSnipping() {
if (!this.chain) if (!this.chain)
return; return;
this.lockTime = this.chain.height(); this.locktime = this.chain.height();
if ((Math.random() * 10 | 0) === 0) if ((Math.random() * 10 | 0) === 0)
this.lockTime = Math.max(0, this.lockTime - (Math.random() * 100 | 0)); this.locktime = Math.max(0, this.locktime - (Math.random() * 100 | 0));
}; };
TX.prototype.setLockTime = function setLockTime(lockTime) { TX.prototype.setLocktime = function setLocktime(locktime) {
var i, input; var i, input;
this.lockTime = lockTime; this.locktime = locktime;
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i]; input = this.inputs[i];
@ -1489,10 +1513,10 @@ TX.prototype.isFinal = function isFinal(height, ts) {
if (!this.chain) if (!this.chain)
return true; return true;
if (this.lockTime === 0) if (this.locktime === 0)
return true; return true;
if (this.lockTime < (this.lockTime < threshold ? height : ts)) if (this.locktime < (this.locktime < threshold ? height : ts))
return true; return true;
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
@ -1503,11 +1527,11 @@ TX.prototype.isFinal = function isFinal(height, ts) {
return true; return true;
}; };
TX.prototype.getSigops = function getSigops(scripthash, accurate) { TX.prototype.getSigops = function getSigops(scriptHash, accurate) {
var n = 0; var n = 0;
this.inputs.forEach(function(input) { this.inputs.forEach(function(input) {
n += bcoin.script.getSigops(input.script, accurate); n += bcoin.script.getSigops(input.script, accurate);
if (scripthash && !this.isCoinbase()) if (scriptHash && !this.isCoinbase())
n += bcoin.script.getScripthashSigops(input.script); n += bcoin.script.getScripthashSigops(input.script);
}, this); }, this);
this.outputs.forEach(function(output) { this.outputs.forEach(function(output) {

View File

@ -133,7 +133,7 @@ Wallet.prototype._init = function init() {
}); });
}; };
Wallet.prototype.__defineGetter__('address', function() { Wallet.prototype.__defineGetter__('primary', function() {
return this.addresses[0]; return this.addresses[0];
}); });
@ -233,7 +233,7 @@ Wallet.prototype.addAddress = function addAddress(address) {
index = this.addresses.push(address) - 1; index = this.addresses.push(address) - 1;
address.on('scriptaddress', address._onUpdate = function(old, cur) { address.on('update script', address._onUpdate = function(old, cur) {
self._addressTable[cur] = self._addressTable[old]; self._addressTable[cur] = self._addressTable[old];
delete self._addressTable[old]; delete self._addressTable[old];
self.emit('add address', address); self.emit('add address', address);
@ -267,7 +267,7 @@ Wallet.prototype.removeAddress = function removeAddress(address) {
this.addresses.splice(i, 1); this.addresses.splice(i, 1);
address.removeListener('scriptaddress', address._onUpdate); address.removeListener('update script', address._onUpdate);
this._addressTable = this._getAddressTable(); this._addressTable = this._getAddressTable();
@ -283,47 +283,51 @@ Wallet.prototype.removeAddress = function removeAddress(address) {
}; };
Wallet.prototype.addKey = function addKey(key, i) { Wallet.prototype.addKey = function addKey(key, i) {
return this.address.addKey(key); return this.primary.addKey(key);
}; };
Wallet.prototype.removeKey = function removeKey(key) { Wallet.prototype.removeKey = function removeKey(key) {
return this.address.removeKey(key); return this.primary.removeKey(key);
}; };
Wallet.prototype.getPrivateKey = function getPrivateKey(enc) { Wallet.prototype.getPrivateKey = function getPrivateKey(enc) {
return this.address.getPrivateKey(enc); return this.primary.getPrivateKey(enc);
}; };
Wallet.prototype.getScript = function getScript() { Wallet.prototype.getScript = function getScript() {
return this.address.getScript(); return this.primary.getScript();
}; };
Wallet.prototype.getScriptHash = function getScriptHash() { Wallet.prototype.getScriptHash =
return this.address.getScriptHash(); Wallet.prototype.getScripthash = function getScripthash() {
return this.primary.getScriptHash();
}; };
Wallet.prototype.getScriptAddress = function getScriptAddress() { Wallet.prototype.getScriptAddress =
return this.address.getScriptAddress(); Wallet.prototype.getScriptaddress = function getScriptaddress() {
return this.primary.getScriptAddress();
}; };
Wallet.prototype.getPublicKey = function getPublicKey(enc) { Wallet.prototype.getPublicKey = function getPublicKey(enc) {
return this.address.getPublicKey(enc); return this.primary.getPublicKey(enc);
}; };
Wallet.prototype.getKeyHash = function getKeyHash() { Wallet.prototype.getKeyHash =
return this.address.getKeyHash(); Wallet.prototype.getKeyhash = function getKeyhash() {
return this.primary.getKeyHash();
}; };
Wallet.prototype.getKeyAddress = function getKeyAddress() { Wallet.prototype.getKeyAddress =
return this.address.getKeyAddress(); Wallet.prototype.getKeyaddress = function getKeyaddress() {
return this.primary.getKeyAddress();
}; };
Wallet.prototype.getHash = function getHash() { Wallet.prototype.getHash = function getHash() {
return this.address.getHash(); return this.primary.getHash();
}; };
Wallet.prototype.getAddress = function getAddress() { Wallet.prototype.getAddress = function getAddress() {
return this.address.getAddress(); return this.primary.getAddress();
}; };
Wallet.prototype.ownInput = function ownInput(tx, index) { Wallet.prototype.ownInput = function ownInput(tx, index) {
@ -347,12 +351,12 @@ Wallet.prototype.fill = function fill(tx, address, fee) {
items = unspent.filter(function(item) { items = unspent.filter(function(item) {
var output = item.tx.outputs[item.index]; var output = item.tx.outputs[item.index];
if (bcoin.script.isScripthash(output.script)) { if (bcoin.script.isScripthash(output.script)) {
if (this.address.type === 'scripthash') if (this.primary.type === 'scripthash')
return true; return true;
return false; return false;
} }
if (bcoin.script.isMultisig(output.script)) { if (bcoin.script.isMultisig(output.script)) {
if (this.address.n > 1) if (this.primary.n > 1)
return true; return true;
return false; return false;
} }
@ -405,7 +409,7 @@ Wallet.prototype.createTX = function createTX(outputs, fee) {
return; return;
if (target.value > 0) if (target.value > 0)
tx.setLockTime(target.value); tx.setLocktime(target.value);
else else
tx.avoidFeeSnipping(); tx.avoidFeeSnipping();
@ -415,83 +419,23 @@ Wallet.prototype.createTX = function createTX(outputs, fee) {
}; };
Wallet.prototype.scriptInputs = function scriptInputs(tx) { Wallet.prototype.scriptInputs = function scriptInputs(tx) {
var self = this; this.fillPrevout(tx);
return this.addresses.reduce(function(total, address) { return this.addresses.reduce(function(total, address) {
var pub = address.getPublicKey(); return total + address.signInputs(tx);
var redeem = address.getScript();
tx.inputs.forEach(function(input, i) {
if (!input.prevout.tx && self.tx._all[input.prevout.hash])
input.prevout.tx = self.tx._all[input.prevout.hash];
if (!input.prevout.tx)
return;
if (!address.ownOutput(input.prevout.tx, input.prevout.index))
return;
if (tx.scriptInput(i, pub, redeem))
total++;
});
return total;
}, 0); }, 0);
}; };
Wallet.prototype.signInputs = function signInputs(tx, type) { Wallet.prototype.signInputs = function signInputs(tx, type) {
var self = this; this.fillPrevout(tx);
return this.addresses.reduce(function(total, address) { return this.addresses.reduce(function(total, address) {
if (!address.key.priv) return total + address.signInputs(tx, type);
return total;
tx.inputs.forEach(function(input, i) {
if (!input.prevout.tx && self.tx._all[input.prevout.hash])
input.prevout.tx = self.tx._all[input.prevout.hash];
if (!input.prevout.tx)
return;
if (!address.ownOutput(input.prevout.tx, input.prevout.index))
return;
if (tx.signInput(i, address.key, type))
total++;
});
return total;
}, 0); }, 0);
}; };
Wallet.prototype.sign = function sign(tx, type) { Wallet.prototype.sign = function sign(tx, type) {
var self = this; this.fillPrevout(tx);
return this.addresses.reduce(function(total, address) { return this.addresses.reduce(function(total, address) {
var pub = address.getPublicKey(); return total + address.sign(tx, type);
var redeem = address.getScript();
var key = address.key;
if (!key.priv)
return total;
// Add signature script to each input
tx.inputs.forEach(function(input, i) {
if (!input.prevout.tx && self.tx._all[input.prevout.hash])
input.prevout.tx = self.tx._all[input.prevout.hash];
// Filter inputs that this wallet own
if (!input.prevout.tx)
return;
if (!address.ownOutput(input.prevout.tx, input.prevout.index))
return;
if (tx.scriptSig(i, key, pub, redeem, type))
total++;
});
return total;
}, 0); }, 0);
}; };
@ -552,6 +496,42 @@ Wallet.prototype.toAddress = function toAddress() {
}; };
}; };
Wallet.prototype.__defineGetter__('script', function() {
return this.getScript();
});
Wallet.prototype.__defineGetter__('scriptHash', function() {
return this.getScriptHash();
});
Wallet.prototype.__defineGetter__('scriptAddress', function() {
return this.getScriptAddress();
});
Wallet.prototype.__defineGetter__('privateKey', function() {
return this.getPrivateKey();
});
Wallet.prototype.__defineGetter__('publicKey', function() {
return this.getPublicKey();
});
Wallet.prototype.__defineGetter__('keyHash', function() {
return this.getKeyHash();
});
Wallet.prototype.__defineGetter__('keyAddress', function() {
return this.getKeyAddress();
});
Wallet.prototype.__defineGetter__('hash', function() {
return this.getHash();
});
Wallet.prototype.__defineGetter__('address', function() {
return this.getAddress();
});
Wallet.prototype.toJSON = function toJSON(encrypt) { Wallet.prototype.toJSON = function toJSON(encrypt) {
return { return {
v: 3, v: 3,

View File

@ -286,6 +286,7 @@ describe('Wallet', function() {
n: 3 n: 3
} }
}); });
w3 = bcoin.wallet.fromJSON(w3.toJSON());
var receive = bcoin.wallet(); var receive = bcoin.wallet();