wallets, now with reference counting.
This commit is contained in:
parent
ab9301ce7e
commit
390af13b14
@ -145,12 +145,12 @@ ldb.parseOptions = function parseOptions(options) {
|
||||
*/
|
||||
|
||||
ldb.destroy = function destroy(options, callback) {
|
||||
options = ldb.parseOptions(options);
|
||||
var backend = ldb.parseOptions(options).db;
|
||||
|
||||
if (!options.db.destroy)
|
||||
if (!backend.destroy)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
options.db.backend.destroy(options.location, callback);
|
||||
backend.destroy(options.location, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -160,12 +160,12 @@ ldb.destroy = function destroy(options, callback) {
|
||||
*/
|
||||
|
||||
ldb.repair = function repair(options, callback) {
|
||||
options = ldb.parseOptions(options);
|
||||
var backend = ldb.parseOptions(options).db;
|
||||
|
||||
if (!options.db.backend.repair)
|
||||
if (!backend.repair)
|
||||
return utils.asyncify(callback)(new Error('Cannot repair.'));
|
||||
|
||||
options.db.backend.repair(options.location, callback);
|
||||
backend.repair(options.location, callback);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@ -71,15 +71,19 @@ function Wallet(options) {
|
||||
|
||||
this.id = options.id || null;
|
||||
this.master = options.master || null;
|
||||
this.accountKey = options.accountKey || null;
|
||||
this.witness = options.witness || false;
|
||||
this.loaded = false;
|
||||
this.loading = false;
|
||||
|
||||
this.accountKey = options.accountKey || null;
|
||||
this.accountIndex = options.accountIndex || 0;
|
||||
this.receiveDepth = options.receiveDepth || 1;
|
||||
this.changeDepth = options.changeDepth || 1;
|
||||
this.receiveAddress = null;
|
||||
this.changeAddress = null;
|
||||
|
||||
this.lookahead = options.lookahead != null ? options.lookahead : 5;
|
||||
this.initialized = false;
|
||||
this.initialized = options.initialized || false;
|
||||
|
||||
this.type = options.type || 'pubkeyhash';
|
||||
this.compressed = options.compressed !== false;
|
||||
@ -107,6 +111,9 @@ function Wallet(options) {
|
||||
if (!this.id)
|
||||
this.id = this.getID();
|
||||
|
||||
if (options.passphrase)
|
||||
this.master.encrypt(options.passphrase);
|
||||
|
||||
// Non-alphanumeric IDs will break leveldb sorting.
|
||||
assert(/^[a-zA-Z0-9]+$/.test(this.id), 'Wallet IDs must be alphanumeric.');
|
||||
|
||||
@ -120,6 +127,80 @@ function Wallet(options) {
|
||||
|
||||
utils.inherits(Wallet, EventEmitter);
|
||||
|
||||
/**
|
||||
* Open the wallet, register with the database.
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Wallet.prototype.open = function open(callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
if (this.loaded)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
if (this.loading)
|
||||
return this.once('open', callback);
|
||||
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
this.db.register(this);
|
||||
} catch (e) {
|
||||
this.emit('error', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
this.init(function(err) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
self.loading = false;
|
||||
self.loaded = true;
|
||||
self.emit('open');
|
||||
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Close the wallet, unregister with the database.
|
||||
* @method
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Wallet.prototype.close =
|
||||
Wallet.prototype.destroy = function destroy(callback) {
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
if (!this.loaded)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
assert(!this.loading);
|
||||
|
||||
try {
|
||||
this.db.unregister(this);
|
||||
} catch (e) {
|
||||
this.emit('error', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
this.loaded = false;
|
||||
|
||||
return utils.nextTick(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to intialize the wallet (generating
|
||||
* the first addresses along with the lookahead
|
||||
* addresses). Called automatically from the
|
||||
* walletdb and open().
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Wallet.prototype.init = function init(callback) {
|
||||
var self = this;
|
||||
var addresses = [];
|
||||
@ -499,8 +580,6 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) {
|
||||
|
||||
address = new bcoin.keyring(options);
|
||||
|
||||
this.emit('add address', address);
|
||||
|
||||
this.cache.set(data.path, address);
|
||||
|
||||
return address;
|
||||
@ -552,10 +631,7 @@ Wallet.prototype.createPath = function createPath(change, index) {
|
||||
/**
|
||||
* Parse a path.
|
||||
* @param {String} path
|
||||
* @returns {Object} {
|
||||
* path: String,
|
||||
* change: Boolean, index: Number
|
||||
* }
|
||||
* @returns {Object} Contains `path`, `change`, and `index`.
|
||||
*/
|
||||
|
||||
Wallet.prototype.parsePath = function parsePath(path) {
|
||||
@ -678,7 +754,8 @@ Wallet.prototype.fill = function fill(tx, options, callback) {
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
assert(this.initialized);
|
||||
if (!this.initialized)
|
||||
return callback(new Error('Cannot use uninitialized wallet.'));
|
||||
|
||||
this.getCoins(function(err, coins) {
|
||||
if (err)
|
||||
@ -845,8 +922,6 @@ Wallet.prototype.deriveInputs = function deriveInputs(tx, callback) {
|
||||
*/
|
||||
|
||||
Wallet.prototype.getPath = function getPath(address, callback) {
|
||||
if (!address || typeof address !== 'string')
|
||||
return callback();
|
||||
this.db.getPath(this.id, address, callback);
|
||||
};
|
||||
|
||||
@ -863,6 +938,9 @@ Wallet.prototype.getInputPaths = function getInputPaths(tx, callback) {
|
||||
var i, input, address, path;
|
||||
|
||||
if (tx instanceof bcoin.input) {
|
||||
if (!tx.coin)
|
||||
return callback(new Error('Not all coins available.'));
|
||||
|
||||
return this.getPath(tx.coin.getHash(), function(err, path) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -891,7 +969,7 @@ Wallet.prototype.getInputPaths = function getInputPaths(tx, callback) {
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return next(err);
|
||||
return callback(err);
|
||||
return callback(null, utils.uniq(paths));
|
||||
});
|
||||
};
|
||||
@ -1487,8 +1565,9 @@ Wallet.prototype.__defineGetter__('address', function() {
|
||||
Wallet.prototype.inspect = function inspect() {
|
||||
return {
|
||||
id: this.id,
|
||||
type: this.type,
|
||||
network: this.network.type,
|
||||
initialized: this.initialized,
|
||||
type: this.type,
|
||||
m: this.m,
|
||||
n: this.n,
|
||||
keyAddress: this.initialized
|
||||
@ -1525,6 +1604,7 @@ Wallet.prototype.toJSON = function toJSON() {
|
||||
name: 'wallet',
|
||||
network: this.network.type,
|
||||
id: this.id,
|
||||
initialized: this.initialized,
|
||||
type: this.type,
|
||||
m: this.m,
|
||||
n: this.n,
|
||||
@ -1558,6 +1638,7 @@ Wallet.parseJSON = function parseJSON(json) {
|
||||
return {
|
||||
network: json.network,
|
||||
id: json.id,
|
||||
initialized: json.initialized,
|
||||
type: json.type,
|
||||
m: json.m,
|
||||
n: json.n,
|
||||
@ -1573,12 +1654,18 @@ Wallet.parseJSON = function parseJSON(json) {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize the wallet.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Wallet.prototype.toRaw = function toRaw(writer) {
|
||||
var p = new BufferWriter(writer);
|
||||
var i;
|
||||
|
||||
p.writeU32(this.network.magic);
|
||||
p.writeVarString(this.id, 'utf8');
|
||||
p.writeU8(this.initialized ? 1 : 0);
|
||||
p.writeU8(this.type === 'pubkeyhash' ? 0 : 1);
|
||||
p.writeU8(this.m);
|
||||
p.writeU8(this.n);
|
||||
@ -1599,14 +1686,19 @@ Wallet.prototype.toRaw = function toRaw(writer) {
|
||||
return p;
|
||||
};
|
||||
|
||||
Wallet.fromRaw = function fromRaw(data) {
|
||||
return new Wallet(Wallet.parseRaw(data));
|
||||
};
|
||||
/**
|
||||
* Parse a serialized wallet. Return a "naked"
|
||||
* wallet object, suitable for passing into
|
||||
* the wallet constructor.
|
||||
* @param {Buffer} data
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Wallet.parseRaw = function parseRaw(data) {
|
||||
var p = new BufferReader(data);
|
||||
var network = bcoin.network.fromMagic(p.readU32());
|
||||
var id = p.readVarString('utf8');
|
||||
var initialized = p.readU8() === 1;
|
||||
var type = p.readU8() === 0 ? 'pubkeyhash' : 'multisig';
|
||||
var m = p.readU8();
|
||||
var n = p.readU8();
|
||||
@ -1625,6 +1717,7 @@ Wallet.parseRaw = function parseRaw(data) {
|
||||
return {
|
||||
network: network.type,
|
||||
id: id,
|
||||
initialized: initialized,
|
||||
type: type,
|
||||
m: m,
|
||||
n: n,
|
||||
@ -1638,6 +1731,16 @@ Wallet.parseRaw = function parseRaw(data) {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate a wallet from serialized data.
|
||||
* @param {Buffer} data
|
||||
* @returns {Wallet}
|
||||
*/
|
||||
|
||||
Wallet.fromRaw = function fromRaw(data) {
|
||||
return new Wallet(Wallet.parseRaw(data));
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate a Wallet from a
|
||||
* jsonified wallet object.
|
||||
@ -1669,7 +1772,7 @@ function MasterKey(options) {
|
||||
if (!(this instanceof MasterKey))
|
||||
return new MasterKey(options);
|
||||
|
||||
this.encrypted = options.encrypted;
|
||||
this.encrypted = !!options.encrypted;
|
||||
this.xprivkey = options.xprivkey;
|
||||
this.phrase = options.phrase;
|
||||
this.passphrase = options.passphrase;
|
||||
@ -1696,6 +1799,8 @@ MasterKey.prototype.encrypt = function encrypt(passphrase) {
|
||||
if (this.encrypted)
|
||||
return;
|
||||
|
||||
assert(passphrase, 'Passphrase is required.');
|
||||
|
||||
this.key = null;
|
||||
this.encrypted = true;
|
||||
this.xprivkey = utils.encrypt(this.xprivkey, passphrase);
|
||||
@ -1812,181 +1917,12 @@ MasterKey.fromJSON = function fromJSON(json) {
|
||||
|
||||
MasterKey.isMasterKey = function isMasterKey(obj) {
|
||||
return obj
|
||||
&& obj.xprivkey
|
||||
&& typeof obj.encrypted === 'boolean'
|
||||
&& typeof obj.decrypt === 'function';
|
||||
};
|
||||
|
||||
/*
|
||||
* CWallet
|
||||
*/
|
||||
|
||||
function CWallet(id, db) {
|
||||
var i, key;
|
||||
|
||||
if (!(this instanceof CWallet))
|
||||
return new CWallet(id, db);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.network = db.network;
|
||||
this.db = db;
|
||||
this.id = id;
|
||||
this.loaded = false;
|
||||
}
|
||||
|
||||
utils.inherits(CWallet, EventEmitter);
|
||||
|
||||
CWallet.prototype.open = function open(callback) {
|
||||
var self = this;
|
||||
|
||||
if (this.loaded)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
this.loaded = true;
|
||||
|
||||
this.db.register(this.id, this);
|
||||
|
||||
return utils.nextTick(callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.close =
|
||||
CWallet.prototype.destroy = function destroy(callback) {
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
if (!this.db)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
this.db.unregister(this.id, this);
|
||||
this.db = null;
|
||||
|
||||
return utils.nextTick(callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.addKey = function addKey(key, callback) {
|
||||
this.db.addKey(this.id, key, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.removeKey = function removeKey(key, callback) {
|
||||
this.db.removeKey(this.id, key, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getID = function getID() {
|
||||
return this.id;
|
||||
};
|
||||
|
||||
CWallet.prototype.createReceive = function createReceive(callback) {
|
||||
return this.db.createAddress(this.id, false, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.createChange = function createChange(callback) {
|
||||
return this.db.createAddress(this.id, true, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.createAddress = function createAddress(change, callback) {
|
||||
return this.db.createAddress(this.id, change, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.hasAddress = function hasAddress(address, callback) {
|
||||
this.db.hasAddress(this.id, address, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.fill = function fill(tx, options, callback) {
|
||||
this.db.fill(this.id, tx, options, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.fillCoins = function fillCoins(tx, callback) {
|
||||
this.db.fillHistory(this.id, tx, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
this.db.getCoin(hash, index, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getTX = function getTX(hash, callback) {
|
||||
this.db.getTX(hash, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.createTX = function createTX(options, outputs, callback) {
|
||||
this.db.createTX(this.id, options, outputs, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getPath = function getPath(address, callback) {
|
||||
if (!address || typeof address !== 'string')
|
||||
return callback();
|
||||
this.db.getPath(this.id, address, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getRedeem = function getRedeem(hash, callback) {
|
||||
this.db.getRedeem(this.id, hash, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.zap = function zap(now, age, callback) {
|
||||
return this.db.zap(this.id, now, age, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.scriptInputs = function scriptInputs(tx, callback) {
|
||||
this.db.scriptInputs(this.id, tx, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.sign = function sign(tx, options, callback) {
|
||||
this.db.sign(this.id, tx, options, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.addTX = function addTX(tx, callback) {
|
||||
return this.db.addTX(tx, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getHistory = function getHistory(callback) {
|
||||
return this.db.getHistory(this.id, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getCoins = function getCoins(callback) {
|
||||
return this.db.getCoins(this.id, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getUnconfirmed = function getUnconfirmed(callback) {
|
||||
return this.db.getUnconfirmed(this.id, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getBalance = function getBalance(callback) {
|
||||
return this.db.getBalance(this.id, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getLastTime = function getLastTime(callback) {
|
||||
return this.db.getLastTime(this.id, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getLast = function getLast(limit, callback) {
|
||||
return this.db.getLast(this.id, limit, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getTimeRange = function getTimeRange(options, callback) {
|
||||
return this.db.getTimeRange(this.id, options, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getReceiveAddress = function getReceiveAddress(callback) {
|
||||
return this.db.getReceiveAddress(this.id, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.getInfo = function getInfo(callback) {
|
||||
return this.db.getInfo(this.id, callback);
|
||||
};
|
||||
|
||||
CWallet.prototype.inspect = function inspect() {
|
||||
return '<CWallet id=' + this.id + '>';
|
||||
};
|
||||
|
||||
CWallet.isCWallet = function isCWallet(obj) {
|
||||
return obj
|
||||
&& obj.db
|
||||
&& obj.id
|
||||
&& obj.getInfo === 'function';
|
||||
};
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = Wallet;
|
||||
module.exports.CWallet = CWallet;
|
||||
bcoin.cwallet = CWallet;
|
||||
|
||||
@ -16,7 +16,6 @@ var bcoin = require('./env');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var utils = require('./utils');
|
||||
var assert = utils.assert;
|
||||
var DUMMY = new Buffer([0]);
|
||||
var BufferReader = require('./reader');
|
||||
var BufferWriter = require('./writer');
|
||||
|
||||
@ -116,19 +115,6 @@ WalletDB.prototype._init = function _init() {
|
||||
useFilter: true
|
||||
});
|
||||
|
||||
this.db.open(function(err) {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
|
||||
self.tx._loadFilter(function(err) {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
|
||||
self.emit('open');
|
||||
self.loaded = true;
|
||||
});
|
||||
});
|
||||
|
||||
this.tx.on('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
@ -164,7 +150,7 @@ WalletDB.prototype._init = function _init() {
|
||||
|
||||
utils.forEachSerial(map.output, function(id, next) {
|
||||
if (self.listeners('balance').length === 0
|
||||
&& !self.hasListener(id, ' balance')) {
|
||||
&& !self.hasListener(id, 'balance')) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@ -186,6 +172,19 @@ WalletDB.prototype._init = function _init() {
|
||||
self.emit('balances', balances, map);
|
||||
});
|
||||
});
|
||||
|
||||
this.db.open(function(err) {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
|
||||
self.tx._loadFilter(function(err) {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
|
||||
self.emit('open');
|
||||
self.loaded = true;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.sync = function sync(tx, map, callback) {
|
||||
@ -220,173 +219,80 @@ WalletDB.prototype.destroy = function destroy(callback) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to get a wallet.
|
||||
* @private
|
||||
* Register a wallet with the walletdb.
|
||||
* @param {WalletID} id
|
||||
* @param {Function} errback
|
||||
* @param {Function} callback
|
||||
* @param {Wallet} wallet
|
||||
*/
|
||||
|
||||
WalletDB.prototype.fetchWallet = function fetchWallet(id, errback, callback) {
|
||||
var self = this;
|
||||
WalletDB.prototype.register = function register(wallet) {
|
||||
var id = wallet.id;
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
if (!this.watchers[id])
|
||||
this.watchers[id] = { wallet: wallet, refs: 0 };
|
||||
|
||||
this.get(id, function(err, _, wallet) {
|
||||
if (err)
|
||||
return errback(err);
|
||||
// Should never happen, and if it does, I will cry.
|
||||
assert(this.watchers[id].wallet === wallet, 'I\'m crying.');
|
||||
|
||||
if (!wallet)
|
||||
return errback(new Error('No wallet.'));
|
||||
|
||||
callback(wallet);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.syncOutputDepth = function syncOutputDepth(id, tx, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.syncOutputDepth(tx, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.createAddress = function createAddress(id, change, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.createAddress(change, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.getReceiveAddress = function getReceiveAddress(id, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
callback(null, wallet.receiveAddress);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.getChangeAddress = function getChangeAddress(id, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
callback(null, wallet.changeAddress);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.fill = function fill(id, tx, options, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.fill(tx, options, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.scriptInputs = function scriptInputs(id, tx, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.scriptInputs(tx, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.sign = function sign(id, tx, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (typeof options === 'string' || Buffer.isBuffer(options))
|
||||
options = { passphrase: options };
|
||||
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.sign(tx, options, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.createTX = function createTX(id, options, outputs, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.createTX(options, outputs, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.addKey = function addKey(id, key, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.addKey(key, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.removeKey = function removeKey(id, key, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.removeKey(key, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.getInfo = function getInfo(id, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
callback(null, wallet);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.getRedeem = function getRedeem(id, hash, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet) {
|
||||
wallet.getRedeem(hash, callback);
|
||||
});
|
||||
// We do some reference counting here
|
||||
// because we're thug like that (police
|
||||
// have a fit when your papers legit).
|
||||
this.watchers[id].refs++;
|
||||
};
|
||||
|
||||
/**
|
||||
* Save a "naked" (non-instantiated) wallet. Will
|
||||
* also index the address table.
|
||||
* @param {WalletID}
|
||||
* @param {Object} json - "Naked" wallet.
|
||||
* @param {Function} callback - Returns [Error, Object].
|
||||
* Unregister a wallet with the walletdb.
|
||||
* @param {WalletID} id
|
||||
* @param {Wallet} wallet
|
||||
*/
|
||||
|
||||
WalletDB.prototype.saveJSON = function saveJSON(id, json, callback) {
|
||||
this.db.put('w/' + id, json, callback);
|
||||
WalletDB.prototype.unregister = function unregister(wallet) {
|
||||
var id = wallet.id;
|
||||
var watcher = this.watchers[id];
|
||||
var i;
|
||||
|
||||
if (!watcher)
|
||||
return;
|
||||
|
||||
assert(watcher.wallet === wallet);
|
||||
assert(watcher.refs !== 0, '`wallet.destroy()` called twice!');
|
||||
|
||||
if (--watcher.refs === 0)
|
||||
delete this.watchers[id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove wallet from the database.
|
||||
* Fire an event for a registered wallet.
|
||||
* @param {WalletID} id
|
||||
* @param {Function} callback - Returns [Error, Object].
|
||||
* @param {...Object} args
|
||||
*/
|
||||
|
||||
WalletDB.prototype.removeJSON = function removeJSON(id, callback) {
|
||||
var self = this;
|
||||
WalletDB.prototype.fire = function fire(id) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var watcher = this.watchers[id];
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
if (!watcher)
|
||||
return;
|
||||
|
||||
this.getJSON(id, function(err, json) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.db.del('w/' + id, function(err) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
return callback(null, json);
|
||||
});
|
||||
});
|
||||
watcher.wallet.emit.apply(watcher.wallet, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve object from the database.
|
||||
* @private
|
||||
* Test for a listener on a registered wallet.
|
||||
* @param {WalletID} id
|
||||
* @param {Function} callback - Returns [Error, Object(nakedWallet)].
|
||||
* @param {String} event
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
WalletDB.prototype.getJSON = function getJSON(id, callback) {
|
||||
callback = utils.ensure(callback);
|
||||
WalletDB.prototype.hasListener = function hasListener(id, event) {
|
||||
var watcher = this.watchers[id];
|
||||
|
||||
if (!id)
|
||||
return callback();
|
||||
if (!watcher)
|
||||
return false;
|
||||
|
||||
this.db.get('w/' + id, function(err, json) {
|
||||
if (err && err.type === 'NotFoundError')
|
||||
return callback();
|
||||
if (watcher.wallet.listeners(event).length !== 0)
|
||||
return true;
|
||||
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
try {
|
||||
json = bcoin.wallet.parseRaw(json);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
return callback(null, json);
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -397,30 +303,39 @@ WalletDB.prototype.getJSON = function getJSON(id, callback) {
|
||||
|
||||
WalletDB.prototype.get = function get(id, callback) {
|
||||
var self = this;
|
||||
var wallet;
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
if (!id)
|
||||
return callback();
|
||||
|
||||
return this.getJSON(id, function(err, json) {
|
||||
var wallet;
|
||||
if (this.watchers[id]) {
|
||||
this.watchers[id].refs++;
|
||||
return callback(null, this.watchers[id].wallet);
|
||||
}
|
||||
|
||||
this.db.get('w/' + id, function(err, data) {
|
||||
if (err && err.type === 'NotFoundError')
|
||||
return callback();
|
||||
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!json)
|
||||
if (!data)
|
||||
return callback();
|
||||
|
||||
try {
|
||||
json.db = self;
|
||||
wallet = new bcoin.wallet(json);
|
||||
data = bcoin.wallet.parseRaw(data);
|
||||
data.db = self;
|
||||
wallet = new bcoin.wallet(data);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
wallet.init(function(err) {
|
||||
wallet.open(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, new bcoin.cwallet(wallet.id, self), wallet);
|
||||
return callback(null, wallet);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -432,13 +347,7 @@ WalletDB.prototype.get = function get(id, callback) {
|
||||
*/
|
||||
|
||||
WalletDB.prototype.save = function save(wallet, callback) {
|
||||
var self = this;
|
||||
if (Array.isArray(wallet)) {
|
||||
return utils.forEachSerial(wallet, function(wallet, next) {
|
||||
self.save(wallet, next);
|
||||
}, callback);
|
||||
}
|
||||
this.saveJSON(wallet.id, wallet.toRaw(), callback);
|
||||
this.db.put('w/' + wallet.id, wallet.toRaw(), callback);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -448,13 +357,12 @@ WalletDB.prototype.save = function save(wallet, callback) {
|
||||
*/
|
||||
|
||||
WalletDB.prototype.remove = function remove(id, callback) {
|
||||
var self = this;
|
||||
if (Array.isArray(wallet)) {
|
||||
return utils.forEachSerial(id, function(id, next) {
|
||||
self.remove(id, next);
|
||||
}, callback);
|
||||
}
|
||||
return this.removeJSON(id, callback);
|
||||
this.db.del('w/' + id, function(err) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -477,6 +385,8 @@ WalletDB.prototype.create = function create(options, callback) {
|
||||
if (exists)
|
||||
return callback(new Error('Wallet already exists.'));
|
||||
|
||||
options = utils.merge({}, options);
|
||||
|
||||
if (self.network.witness)
|
||||
options.witness = options.witness !== false;
|
||||
|
||||
@ -484,11 +394,11 @@ WalletDB.prototype.create = function create(options, callback) {
|
||||
options.db = self;
|
||||
wallet = new bcoin.wallet(options);
|
||||
|
||||
wallet.init(function(err) {
|
||||
wallet.open(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, new bcoin.cwallet(wallet.id, self), wallet);
|
||||
return callback(null, wallet);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -515,12 +425,12 @@ WalletDB.prototype.has = function has(id, callback) {
|
||||
|
||||
WalletDB.prototype.ensure = function ensure(options, callback) {
|
||||
var self = this;
|
||||
return this.get(options.id, function(err, cwallet, wallet) {
|
||||
return this.get(options.id, function(err, wallet) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (cwallet)
|
||||
return callback(null, cwallet, wallet);
|
||||
if (wallet)
|
||||
return callback(null, wallet);
|
||||
|
||||
self.create(options, callback);
|
||||
});
|
||||
@ -611,6 +521,9 @@ WalletDB.prototype.hasAddress = function hasAddress(id, address, callback) {
|
||||
*/
|
||||
|
||||
WalletDB.prototype.getAddress = function getAddress(address, callback) {
|
||||
if (!address)
|
||||
return callback();
|
||||
|
||||
this.db.fetch('W/' + address, parsePaths, callback);
|
||||
};
|
||||
|
||||
@ -778,78 +691,115 @@ WalletDB.prototype.removeBlock = function removeBlock(block, callback) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Register an event emitter with the walletdb.
|
||||
* Helper function to get a wallet.
|
||||
* @private
|
||||
* @param {WalletID} id
|
||||
* @param {EventEmitter} watcher
|
||||
* @param {Function} callback
|
||||
* @param {Function} handler
|
||||
*/
|
||||
|
||||
WalletDB.prototype.register = function register(id, watcher) {
|
||||
if (!this.watchers[id])
|
||||
this.watchers[id] = [];
|
||||
WalletDB.prototype.fetchWallet = function fetchWallet(id, callback, handler) {
|
||||
var self = this;
|
||||
|
||||
if (this.watchers[id].indexOf(watcher) === -1)
|
||||
this.watchers[id].push(watcher);
|
||||
this.get(id, function(err, wallet) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!wallet)
|
||||
return callback(new Error('No wallet.'));
|
||||
|
||||
handler(wallet, function(err, result) {
|
||||
// Kill the reference.
|
||||
self.unregister(wallet);
|
||||
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
callback(null, result);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Unregister an event emitter with the walletdb.
|
||||
* @param {WalletID} id
|
||||
* @param {EventEmitter} watcher
|
||||
*/
|
||||
|
||||
WalletDB.prototype.unregister = function unregister(id, watcher) {
|
||||
var watchers = this.watchers[id];
|
||||
var i;
|
||||
|
||||
if (!watchers)
|
||||
return;
|
||||
|
||||
i = watchers.indexOf(watcher);
|
||||
if (i !== -1)
|
||||
watchers.splice(i, 1);
|
||||
|
||||
if (watchers.length === 0)
|
||||
delete this.watchers[id];
|
||||
WalletDB.prototype.syncOutputDepth = function syncOutputDepth(id, tx, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.syncOutputDepth(tx, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Fire an event for all registered event emitters.
|
||||
* @param {WalletID} id
|
||||
* @param {...Object} args
|
||||
*/
|
||||
|
||||
WalletDB.prototype.fire = function fire(id) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var watchers = this.watchers[id];
|
||||
var i;
|
||||
|
||||
if (!watchers)
|
||||
return;
|
||||
|
||||
for (i = 0; i < watchers.length; i++)
|
||||
watchers[i].emit.apply(watchers[i], args);
|
||||
WalletDB.prototype.createAddress = function createAddress(id, change, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.createAddress(change, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Test for a listener on a registered event emitter.
|
||||
* @param {WalletID} id
|
||||
* @param {String} event
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
WalletDB.prototype.getReceiveAddress = function getReceiveAddress(id, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
callback(null, wallet.receiveAddress);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.hasListener = function hasListener(id, event) {
|
||||
var watchers = this.watchers[id];
|
||||
var i;
|
||||
WalletDB.prototype.getChangeAddress = function getChangeAddress(id, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
callback(null, wallet.changeAddress);
|
||||
});
|
||||
};
|
||||
|
||||
if (!watchers)
|
||||
return false;
|
||||
WalletDB.prototype.fill = function fill(id, tx, options, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.fill(tx, options, callback);
|
||||
});
|
||||
};
|
||||
|
||||
for (i = 0; i < watchers.length; i++) {
|
||||
if (watchers[i].listeners(event).length !== 0)
|
||||
return true;
|
||||
WalletDB.prototype.scriptInputs = function scriptInputs(id, tx, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.scriptInputs(tx, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.sign = function sign(id, tx, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
return false;
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.sign(tx, options, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.createTX = function createTX(id, options, outputs, callback) {
|
||||
if (typeof outputs === 'function') {
|
||||
callback = outputs;
|
||||
outputs = null;
|
||||
}
|
||||
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.createTX(options, outputs, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.addKey = function addKey(id, key, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.addKey(key, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.removeKey = function removeKey(id, key, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.removeKey(key, callback);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.getInfo = function getInfo(id, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
callback(null, wallet);
|
||||
});
|
||||
};
|
||||
|
||||
WalletDB.prototype.getRedeem = function getRedeem(id, hash, callback) {
|
||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||
wallet.getRedeem(hash, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@ -17,8 +17,7 @@ describe('Chain', function() {
|
||||
walletdb = new bcoin.walletdb({ name: 'chain-test-wdb', db: 'memory' });
|
||||
wallet = new bcoin.wallet({ db: walletdb });
|
||||
miner = new bcoin.miner({
|
||||
chain: chain,
|
||||
address: wallet.getAddress()
|
||||
chain: chain
|
||||
});
|
||||
|
||||
chain.on('error', function() {});
|
||||
@ -73,8 +72,12 @@ describe('Chain', function() {
|
||||
|
||||
it('should open chain and miner', function(cb) {
|
||||
miner.open(function(err) {
|
||||
assert.ifError(cb);
|
||||
wallet.init(cb);
|
||||
assert.ifError(err);
|
||||
wallet.open(function(err) {
|
||||
assert.ifError(err);
|
||||
miner.address = wallet.getAddress();
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -19,18 +19,24 @@ describe('Mempool', function() {
|
||||
db: 'memory'
|
||||
});
|
||||
|
||||
var w;
|
||||
|
||||
mempool.on('error', function() {});
|
||||
|
||||
it('should open mempool', function(cb) {
|
||||
mempool.open(cb);
|
||||
});
|
||||
|
||||
it('should handle incoming orphans and TXs', function(cb) {
|
||||
var w = new bcoin.wallet();
|
||||
it('should open wallet', function(cb) {
|
||||
w = new bcoin.wallet();
|
||||
w.open(cb);
|
||||
});
|
||||
|
||||
it('should handle incoming orphans and TXs', function(cb) {
|
||||
var kp = bcoin.hd.generate();
|
||||
// Coinbase
|
||||
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000
|
||||
var prev = new bcoin.script([w.publicKey, opcodes.OP_CHECKSIG]);
|
||||
var prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
|
||||
var dummyInput = {
|
||||
prevout: {
|
||||
hash: constants.ONE_HASH.toString('hex'),
|
||||
@ -49,84 +55,96 @@ describe('Mempool', function() {
|
||||
sequence: 0xffffffff
|
||||
};
|
||||
t1.addInput(dummyInput);
|
||||
t1.inputs[0].script = new bcoin.script([t1.createSignature(0, prev, w.privateKey, 'all', 0)]),
|
||||
t1.inputs[0].script = new bcoin.script([t1.createSignature(0, prev, kp.privateKey, 'all', 0)]),
|
||||
|
||||
// balance: 51000
|
||||
w.sign(t1);
|
||||
var t2 = bcoin.mtx().addInput(t1, 0) // 50000
|
||||
.addOutput(w, 20000)
|
||||
.addOutput(w, 20000);
|
||||
// balance: 49000
|
||||
w.sign(t2);
|
||||
var t3 = bcoin.mtx().addInput(t1, 1) // 10000
|
||||
.addInput(t2, 0) // 20000
|
||||
.addOutput(w, 23000);
|
||||
// balance: 47000
|
||||
w.sign(t3);
|
||||
var t4 = bcoin.mtx().addInput(t2, 1) // 24000
|
||||
.addInput(t3, 0) // 23000
|
||||
.addOutput(w, 11000)
|
||||
.addOutput(w, 11000);
|
||||
// balance: 22000
|
||||
w.sign(t4);
|
||||
var f1 = bcoin.mtx().addInput(t4, 1) // 11000
|
||||
.addOutput(new bcoin.wallet(), 9000);
|
||||
// balance: 11000
|
||||
w.sign(f1);
|
||||
var fake = bcoin.mtx().addInput(t1, 1) // 1000 (already redeemed)
|
||||
.addOutput(w, 6000); // 6000 instead of 500
|
||||
// Script inputs but do not sign
|
||||
w.scriptInputs(fake);
|
||||
// Fake signature
|
||||
fake.inputs[0].script.code[0] = new Buffer([0,0,0,0,0,0,0,0,0]);
|
||||
// balance: 11000
|
||||
[t2, t3, t4, f1, fake].forEach(function(tx) {
|
||||
tx.inputs.forEach(function(input) {
|
||||
delete input.coin;
|
||||
});
|
||||
});
|
||||
|
||||
// Just for debugging
|
||||
t1.hint = 't1';
|
||||
t2.hint = 't2';
|
||||
t3.hint = 't3';
|
||||
t4.hint = 't4';
|
||||
f1.hint = 'f1';
|
||||
fake.hint = 'fake';
|
||||
|
||||
mempool.addTX(fake, function(err) {
|
||||
w.sign(t1, function(err, total) {
|
||||
assert.ifError(err);
|
||||
mempool.addTX(t4, function(err) {
|
||||
var t2 = bcoin.mtx().addInput(t1, 0) // 50000
|
||||
.addOutput(w, 20000)
|
||||
.addOutput(w, 20000);
|
||||
// balance: 49000
|
||||
w.sign(t2, function(err, total) {
|
||||
assert.ifError(err);
|
||||
mempool.getBalance(function(err, balance) {
|
||||
var t3 = bcoin.mtx().addInput(t1, 1) // 10000
|
||||
.addInput(t2, 0) // 20000
|
||||
.addOutput(w, 23000);
|
||||
// balance: 47000
|
||||
w.sign(t3, function(err, total) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 0);
|
||||
mempool.addTX(t1, function(err) {
|
||||
var t4 = bcoin.mtx().addInput(t2, 1) // 24000
|
||||
.addInput(t3, 0) // 23000
|
||||
.addOutput(w, 11000)
|
||||
.addOutput(w, 11000);
|
||||
// balance: 22000
|
||||
w.sign(t4, function(err, total) {
|
||||
assert.ifError(err);
|
||||
mempool.getBalance(function(err, balance) {
|
||||
var f1 = bcoin.mtx().addInput(t4, 1) // 11000
|
||||
.addOutput(bcoin.address.fromData(new Buffer([])).toBase58(), 9000);
|
||||
// balance: 11000
|
||||
w.sign(f1, function(err, total) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 60000);
|
||||
mempool.addTX(t2, function(err) {
|
||||
var fake = bcoin.mtx().addInput(t1, 1) // 1000 (already redeemed)
|
||||
.addOutput(w, 6000); // 6000 instead of 500
|
||||
// Script inputs but do not sign
|
||||
w.scriptInputs(fake, function(err) {
|
||||
assert.ifError(err);
|
||||
mempool.getBalance(function(err, balance) {
|
||||
// Fake signature
|
||||
fake.inputs[0].script.code[0] = new Buffer([0,0,0,0,0,0,0,0,0]);
|
||||
// balance: 11000
|
||||
[t2, t3, t4, f1, fake].forEach(function(tx) {
|
||||
tx.inputs.forEach(function(input) {
|
||||
delete input.coin;
|
||||
});
|
||||
});
|
||||
|
||||
// Just for debugging
|
||||
t1.hint = 't1';
|
||||
t2.hint = 't2';
|
||||
t3.hint = 't3';
|
||||
t4.hint = 't4';
|
||||
f1.hint = 'f1';
|
||||
fake.hint = 'fake';
|
||||
|
||||
mempool.addTX(fake, function(err) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 50000);
|
||||
mempool.addTX(t3, function(err) {
|
||||
mempool.addTX(t4, function(err) {
|
||||
assert.ifError(err);
|
||||
mempool.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 22000);
|
||||
mempool.addTX(f1, function(err) {
|
||||
assert.equal(balance.total, 0);
|
||||
mempool.addTX(t1, function(err) {
|
||||
assert.ifError(err);
|
||||
mempool.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 20000);
|
||||
mempool.getHistory(function(err, txs) {
|
||||
assert(txs.some(function(tx) {
|
||||
return tx.hash('hex') === f1.hash('hex');
|
||||
}));
|
||||
assert.equal(balance.total, 60000);
|
||||
mempool.addTX(t2, function(err) {
|
||||
assert.ifError(err);
|
||||
mempool.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 50000);
|
||||
mempool.addTX(t3, function(err) {
|
||||
assert.ifError(err);
|
||||
mempool.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 22000);
|
||||
mempool.addTX(f1, function(err) {
|
||||
assert.ifError(err);
|
||||
mempool.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 20000);
|
||||
mempool.getHistory(function(err, txs) {
|
||||
assert(txs.some(function(tx) {
|
||||
return tx.hash('hex') === f1.hash('hex');
|
||||
}));
|
||||
|
||||
cb();
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -142,11 +160,10 @@ describe('Mempool', function() {
|
||||
});
|
||||
|
||||
it('should handle locktime', function(cb) {
|
||||
var w = new bcoin.wallet();
|
||||
|
||||
var kp = bcoin.hd.generate();
|
||||
// Coinbase
|
||||
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000
|
||||
var prev = new bcoin.script([w.publicKey, opcodes.OP_CHECKSIG]);
|
||||
var prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
|
||||
var prevHash = bcoin.ec.random(32).toString('hex');
|
||||
var dummyInput = {
|
||||
prevout: {
|
||||
@ -168,7 +185,7 @@ describe('Mempool', function() {
|
||||
t1.addInput(dummyInput);
|
||||
t1.setLocktime(200);
|
||||
chain.tip.height = 200;
|
||||
t1.inputs[0].script = new bcoin.script([t1.createSignature(0, prev, w.privateKey, 'all', 0)]),
|
||||
t1.inputs[0].script = new bcoin.script([t1.createSignature(0, prev, kp.privateKey, 'all', 0)]),
|
||||
mempool.addTX(t1, function(err) {
|
||||
chain.tip.height = 0;
|
||||
assert.ifError(err);
|
||||
@ -177,11 +194,10 @@ describe('Mempool', function() {
|
||||
});
|
||||
|
||||
it('should handle invalid locktime', function(cb) {
|
||||
var w = new bcoin.wallet();
|
||||
|
||||
var kp = bcoin.hd.generate();
|
||||
// Coinbase
|
||||
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000
|
||||
var prev = new bcoin.script([w.publicKey, opcodes.OP_CHECKSIG]);
|
||||
var prev = new bcoin.script([kp.publicKey, opcodes.OP_CHECKSIG]);
|
||||
var prevHash = bcoin.ec.random(32).toString('hex');
|
||||
var dummyInput = {
|
||||
prevout: {
|
||||
@ -203,7 +219,7 @@ describe('Mempool', function() {
|
||||
t1.addInput(dummyInput);
|
||||
t1.setLocktime(200);
|
||||
chain.tip.height = 200 - 1;
|
||||
t1.inputs[0].script = new bcoin.script([t1.createSignature(0, prev, w.privateKey, 'all', 0)]),
|
||||
t1.inputs[0].script = new bcoin.script([t1.createSignature(0, prev, kp.privateKey, 'all', 0)]),
|
||||
mempool.addTX(t1, function(err) {
|
||||
chain.tip.height = 0;
|
||||
assert(err);
|
||||
|
||||
@ -82,40 +82,37 @@ describe('Wallet', function() {
|
||||
if (witness)
|
||||
flags |= bcoin.protocol.constants.flags.VERIFY_WITNESS;
|
||||
|
||||
wdb.create({ witness: witness }, function(err, w, w2) {
|
||||
wdb.create({ witness: witness }, function(err, w) {
|
||||
assert.ifError(err);
|
||||
|
||||
w.getReceiveAddress(function(err, a) {
|
||||
if (witness)
|
||||
assert(bcoin.address.parseBase58(a.getAddress()).type === 'witnesspubkeyhash');
|
||||
else
|
||||
assert(bcoin.address.parseBase58(a.getAddress()).type === 'pubkeyhash');
|
||||
if (witness)
|
||||
assert(bcoin.address.parseBase58(w.getAddress()).type === 'witnesspubkeyhash');
|
||||
else
|
||||
assert(bcoin.address.parseBase58(w.getAddress()).type === 'pubkeyhash');
|
||||
|
||||
// Input transcation
|
||||
var src = bcoin.mtx({
|
||||
outputs: [{
|
||||
value: 5460 * 2,
|
||||
address: bullshitNesting
|
||||
? a.getProgramAddress()
|
||||
: a.getAddress()
|
||||
}, {
|
||||
value: 5460 * 2,
|
||||
address: bcoin.address.fromData(new Buffer([])).toBase58()
|
||||
}]
|
||||
});
|
||||
// Input transcation
|
||||
var src = bcoin.mtx({
|
||||
outputs: [{
|
||||
value: 5460 * 2,
|
||||
address: bullshitNesting
|
||||
? w.getProgramAddress()
|
||||
: w.getAddress()
|
||||
}, {
|
||||
value: 5460 * 2,
|
||||
address: bcoin.address.fromData(new Buffer([])).toBase58()
|
||||
}]
|
||||
});
|
||||
|
||||
src.addInput(dummyInput);
|
||||
src.addInput(dummyInput);
|
||||
|
||||
var tx = bcoin.mtx()
|
||||
.addInput(src, 0)
|
||||
.addOutput(a.getAddress(), 5460);
|
||||
var tx = bcoin.mtx()
|
||||
.addInput(src, 0)
|
||||
.addOutput(w.getAddress(), 5460);
|
||||
|
||||
w.sign(tx, function(err) {
|
||||
assert.ifError(err);
|
||||
utils.print(tx);
|
||||
assert(tx.verify(null, true, flags));
|
||||
cb();
|
||||
});
|
||||
w.sign(tx, function(err) {
|
||||
assert.ifError(err);
|
||||
assert(tx.verify(null, true, flags));
|
||||
cb();
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -174,107 +171,109 @@ describe('Wallet', function() {
|
||||
var dw, di;
|
||||
it('should have TX pool and be serializable', function(cb) {
|
||||
wdb.create({}, function(err, w) {
|
||||
assert.ifError(err);
|
||||
w.getReceiveAddress(function(err, aw) {
|
||||
assert.ifError(err);
|
||||
wdb.create({}, function(err, f) {
|
||||
assert.ifError(err);
|
||||
f.getReceiveAddress(function(err, af) {
|
||||
assert.ifError(err);
|
||||
dw = w;
|
||||
|
||||
// Coinbase
|
||||
var t1 = bcoin.mtx().addOutput(aw, 50000).addOutput(aw, 1000);
|
||||
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 1000);
|
||||
t1.addInput(dummyInput);
|
||||
// balance: 51000
|
||||
// w.sign(t1);
|
||||
w.sign(t1, function(err) {
|
||||
assert.ifError(err);
|
||||
var t2 = bcoin.mtx().addInput(t1, 0) // 50000
|
||||
.addOutput(aw, 24000)
|
||||
.addOutput(aw, 24000);
|
||||
di = t2.inputs[0];
|
||||
// balance: 49000
|
||||
// w.sign(t2);
|
||||
w.sign(t2, function(err) {
|
||||
assert.ifError(err);
|
||||
var t3 = bcoin.mtx().addInput(t1, 1) // 1000
|
||||
.addInput(t2, 0) // 24000
|
||||
.addOutput(aw, 23000);
|
||||
// balance: 47000
|
||||
// w.sign(t3);
|
||||
w.sign(t3, function(err) {
|
||||
assert.ifError(err);
|
||||
var t4 = bcoin.mtx().addInput(t2, 1) // 24000
|
||||
.addInput(t3, 0) // 23000
|
||||
.addOutput(aw, 11000)
|
||||
.addOutput(aw, 11000);
|
||||
// balance: 22000
|
||||
// w.sign(t4);
|
||||
w.sign(t4, function(err) {
|
||||
assert.ifError(err);
|
||||
var f1 = bcoin.mtx().addInput(t4, 1) // 11000
|
||||
.addOutput(af, 10000);
|
||||
// balance: 11000
|
||||
// w.sign(f1);
|
||||
w.sign(f1, function(err) {
|
||||
assert.ifError(err);
|
||||
var fake = bcoin.mtx().addInput(t1, 1) // 1000 (already redeemed)
|
||||
.addOutput(aw, 500);
|
||||
// Script inputs but do not sign
|
||||
// w.scriptInputs(fake);
|
||||
w.scriptInputs(fake, function(err) {
|
||||
assert.ifError(err);
|
||||
// Fake signature
|
||||
fake.inputs[0].script.code[0] = new Buffer([0,0,0,0,0,0,0,0,0]);
|
||||
// balance: 11000
|
||||
|
||||
// Just for debugging
|
||||
t1.hint = 't1';
|
||||
t2.hint = 't2';
|
||||
t3.hint = 't3';
|
||||
t4.hint = 't4';
|
||||
f1.hint = 'f1';
|
||||
fake.hint = 'fake';
|
||||
|
||||
// Fake TX should temporarly change output
|
||||
wdb.addTX(fake, function(err) {
|
||||
assert.ifError(err);
|
||||
wdb.addTX(t4, function(err) {
|
||||
var t2 = bcoin.mtx().addInput(t1, 0) // 50000
|
||||
.addOutput(w, 24000)
|
||||
.addOutput(w, 24000);
|
||||
di = t2.inputs[0];
|
||||
// balance: 49000
|
||||
// w.sign(t2);
|
||||
w.sign(t2, function(err) {
|
||||
assert.ifError(err);
|
||||
w.getBalance(function(err, balance) {
|
||||
var t3 = bcoin.mtx().addInput(t1, 1) // 1000
|
||||
.addInput(t2, 0) // 24000
|
||||
.addOutput(w, 23000);
|
||||
// balance: 47000
|
||||
// w.sign(t3);
|
||||
w.sign(t3, function(err) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 22500);
|
||||
wdb.addTX(t1, function(err) {
|
||||
w.getBalance(function(err, balance) {
|
||||
var t4 = bcoin.mtx().addInput(t2, 1) // 24000
|
||||
.addInput(t3, 0) // 23000
|
||||
.addOutput(w, 11000)
|
||||
.addOutput(w, 11000);
|
||||
// balance: 22000
|
||||
// w.sign(t4);
|
||||
w.sign(t4, function(err) {
|
||||
assert.ifError(err);
|
||||
var f1 = bcoin.mtx().addInput(t4, 1) // 11000
|
||||
.addOutput(f, 10000);
|
||||
// balance: 11000
|
||||
// w.sign(f1);
|
||||
w.sign(f1, function(err) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 73000);
|
||||
wdb.addTX(t2, function(err) {
|
||||
var fake = bcoin.mtx().addInput(t1, 1) // 1000 (already redeemed)
|
||||
.addOutput(w, 500);
|
||||
// Script inputs but do not sign
|
||||
// w.scriptInputs(fake);
|
||||
w.scriptInputs(fake, function(err) {
|
||||
assert.ifError(err);
|
||||
w.getBalance(function(err, balance) {
|
||||
// Fake signature
|
||||
fake.inputs[0].script.code[0] = new Buffer([0,0,0,0,0,0,0,0,0]);
|
||||
// balance: 11000
|
||||
|
||||
// Just for debugging
|
||||
t1.hint = 't1';
|
||||
t2.hint = 't2';
|
||||
t3.hint = 't3';
|
||||
t4.hint = 't4';
|
||||
f1.hint = 'f1';
|
||||
fake.hint = 'fake';
|
||||
|
||||
// Fake TX should temporarly change output
|
||||
wdb.addTX(fake, function(err) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 47000);
|
||||
wdb.addTX(t3, function(err) {
|
||||
wdb.addTX(t4, function(err) {
|
||||
assert.ifError(err);
|
||||
w.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 22000);
|
||||
wdb.addTX(f1, function(err) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 22500);
|
||||
wdb.addTX(t1, function(err) {
|
||||
w.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 11000);
|
||||
w.getHistory(function(err, txs) {
|
||||
assert(txs.some(function(tx) {
|
||||
return tx.hash('hex') === f1.hash('hex');
|
||||
}));
|
||||
assert.equal(balance.total, 73000);
|
||||
wdb.addTX(t2, function(err) {
|
||||
assert.ifError(err);
|
||||
w.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 47000);
|
||||
wdb.addTX(t3, function(err) {
|
||||
assert.ifError(err);
|
||||
w.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 22000);
|
||||
wdb.addTX(f1, function(err) {
|
||||
assert.ifError(err);
|
||||
w.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.equal(balance.total, 11000);
|
||||
w.getHistory(function(err, txs) {
|
||||
assert(txs.some(function(tx) {
|
||||
return tx.hash('hex') === f1.hash('hex');
|
||||
}));
|
||||
|
||||
//var w2 = bcoin.wallet.fromJSON(w.toJSON());
|
||||
// assert.equal(w2.getBalance(), 11000);
|
||||
// assert(w2.getHistory().some(function(tx) {
|
||||
// return tx.hash('hex') === f1.hash('hex');
|
||||
// }));
|
||||
cb();
|
||||
//var w2 = bcoin.wallet.fromJSON(w.toJSON());
|
||||
// assert.equal(w2.getBalance(), 11000);
|
||||
// assert(w2.getHistory().some(function(tx) {
|
||||
// return tx.hash('hex') === f1.hash('hex');
|
||||
// }));
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -285,17 +284,9 @@ describe('Wallet', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -314,20 +305,16 @@ describe('Wallet', function() {
|
||||
|
||||
it('should fill tx with inputs', function(cb) {
|
||||
wdb.create({}, function(err, w1) {
|
||||
assert.ifError(err);
|
||||
w1.getReceiveAddress(function(err, aw1) {
|
||||
assert.ifError(err);
|
||||
wdb.create({}, function(err, w2) {
|
||||
assert.ifError(err);
|
||||
w2.getReceiveAddress(function(err, aw2) {
|
||||
assert.ifError(err);
|
||||
|
||||
// Coinbase
|
||||
var t1 = bcoin.mtx()
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460);
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
|
||||
@ -336,7 +323,7 @@ describe('Wallet', function() {
|
||||
assert.ifError(err);
|
||||
|
||||
// Create new transaction
|
||||
var t2 = bcoin.mtx().addOutput(aw2, 5460);
|
||||
var t2 = bcoin.mtx().addOutput(w2, 5460);
|
||||
w1.fill(t2, { rate: 10000, round: true }, function(err) {
|
||||
assert.ifError(err);
|
||||
w1.sign(t2, function(err) {
|
||||
@ -351,7 +338,7 @@ describe('Wallet', function() {
|
||||
assert.equal(t2.getFee(), 10920);
|
||||
|
||||
// Create new transaction
|
||||
var t3 = bcoin.mtx().addOutput(aw2, 15000);
|
||||
var t3 = bcoin.mtx().addOutput(w2, 15000);
|
||||
w1.fill(t3, { rate: 10000, round: true }, function(err) {
|
||||
assert(err);
|
||||
assert.equal(err.requiredFunds, 25000);
|
||||
@ -360,28 +347,22 @@ describe('Wallet', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should fill tx with inputs with accurate fee', function(cb) {
|
||||
wdb.create({ master: KEY1 }, function(err, w1) {
|
||||
assert.ifError(err);
|
||||
w1.getReceiveAddress(function(err, aw1) {
|
||||
assert.ifError(err);
|
||||
wdb.create({ master: KEY2 }, function(err, w2) {
|
||||
assert.ifError(err);
|
||||
w2.getReceiveAddress(function(err, aw2) {
|
||||
assert.ifError(err);
|
||||
|
||||
// Coinbase
|
||||
var t1 = bcoin.mtx()
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460);
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
|
||||
@ -390,73 +371,71 @@ describe('Wallet', function() {
|
||||
assert.ifError(err);
|
||||
|
||||
// Create new transaction
|
||||
var t2 = bcoin.mtx().addOutput(aw2, 5460);
|
||||
var t2 = bcoin.mtx().addOutput(w2, 5460);
|
||||
w1.fill(t2, { rate: 10000 }, function(err) {
|
||||
assert.ifError(err);
|
||||
w1.sign(t2, function(err) {
|
||||
assert.ifError(err);
|
||||
assert(t2.verify());
|
||||
|
||||
assert.equal(t2.getInputValue(), 16380);
|
||||
|
||||
// Should now have a change output:
|
||||
assert.equal(t2.getOutputValue(), 11130);
|
||||
|
||||
assert.equal(t2.getFee(), 5250);
|
||||
|
||||
assert.equal(t2.getCost(), 2084);
|
||||
assert.equal(t2.getBaseSize(), 521);
|
||||
assert.equal(t2.getSize(), 521);
|
||||
assert.equal(t2.getVirtualSize(), 521);
|
||||
|
||||
// Create new transaction
|
||||
wdb.addTX(t2, function(err) {
|
||||
assert.ifError(err);
|
||||
var t3 = bcoin.mtx().addOutput(aw2, 15000);
|
||||
w1.fill(t3, { rate: 10000 }, function(err) {
|
||||
assert(err);
|
||||
cb();
|
||||
assert(t2.verify());
|
||||
|
||||
assert.equal(t2.getInputValue(), 16380);
|
||||
|
||||
// Should now have a change output:
|
||||
assert.equal(t2.getOutputValue(), 11130);
|
||||
|
||||
assert.equal(t2.getFee(), 5250);
|
||||
|
||||
assert.equal(t2.getCost(), 2084);
|
||||
assert.equal(t2.getBaseSize(), 521);
|
||||
assert.equal(t2.getSize(), 521);
|
||||
assert.equal(t2.getVirtualSize(), 521);
|
||||
|
||||
var balance;
|
||||
w2.once('balance', function(b) {
|
||||
balance = b;
|
||||
});
|
||||
|
||||
// Create new transaction
|
||||
wdb.addTX(t2, function(err) {
|
||||
assert.ifError(err);
|
||||
var t3 = bcoin.mtx().addOutput(w2, 15000);
|
||||
w1.fill(t3, { rate: 10000 }, function(err) {
|
||||
assert(err);
|
||||
assert(balance.total === 5460);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should sign multiple inputs using different keys', function(cb) {
|
||||
wdb.create({}, function(err, w1) {
|
||||
assert.ifError(err);
|
||||
w1.getReceiveAddress(function(err, aw1) {
|
||||
assert.ifError(err);
|
||||
wdb.create({}, function(err, w2) {
|
||||
assert.ifError(err);
|
||||
w2.getReceiveAddress(function(err, aw2) {
|
||||
assert.ifError(err);
|
||||
wdb.create({}, function(err, to) {
|
||||
assert.ifError(err);
|
||||
to.getReceiveAddress(function(err, ato) {
|
||||
assert.ifError(err);
|
||||
|
||||
// Coinbase
|
||||
var t1 = bcoin.mtx()
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460)
|
||||
.addOutput(aw1, 5460);
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460)
|
||||
.addOutput(w1, 5460);
|
||||
|
||||
t1.addInput(dummyInput);
|
||||
|
||||
// Fake TX should temporarly change output
|
||||
// Coinbase
|
||||
var t2 = bcoin.mtx()
|
||||
.addOutput(aw2, 5460)
|
||||
.addOutput(aw2, 5460)
|
||||
.addOutput(aw2, 5460)
|
||||
.addOutput(aw2, 5460);
|
||||
.addOutput(w2, 5460)
|
||||
.addOutput(w2, 5460)
|
||||
.addOutput(w2, 5460)
|
||||
.addOutput(w2, 5460);
|
||||
|
||||
t2.addInput(dummyInput);
|
||||
// Fake TX should temporarly change output
|
||||
@ -468,7 +447,7 @@ describe('Wallet', function() {
|
||||
|
||||
// Create our tx with an output
|
||||
var tx = bcoin.mtx();
|
||||
tx.addOutput(ato, 5460);
|
||||
tx.addOutput(to, 5460);
|
||||
|
||||
var cost = tx.getOutputValue();
|
||||
var total = cost * constants.tx.MIN_FEE;
|
||||
@ -479,7 +458,7 @@ describe('Wallet', function() {
|
||||
assert.ifError(err);
|
||||
|
||||
// Add dummy output (for `left`) to calculate maximum TX size
|
||||
tx.addOutput(aw1, 0);
|
||||
tx.addOutput(w1, 0);
|
||||
|
||||
// Add our unspent inputs to sign
|
||||
tx.addInput(coins1[0]);
|
||||
@ -534,9 +513,6 @@ describe('Wallet', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function multisig(witness, bullshitNesting, cb) {
|
||||
@ -556,43 +532,6 @@ describe('Wallet', function() {
|
||||
|
||||
var w1, w2, w3, receive;
|
||||
|
||||
function getInfo(callback) {
|
||||
var info = { change: {} };
|
||||
utils.serial([
|
||||
function(next) {
|
||||
w1.getInfo(function(err, info_) {
|
||||
assert.ifError(err);
|
||||
info.w1 = info_;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
w2.getInfo(function(err, info_) {
|
||||
assert.ifError(err);
|
||||
info.w2 = info_;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
w3.getInfo(function(err, info_) {
|
||||
assert.ifError(err);
|
||||
info.w3 = info_;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
receive.getInfo(function(err, info_) {
|
||||
assert.ifError(err);
|
||||
info.receive = info_;
|
||||
next();
|
||||
});
|
||||
}
|
||||
], function(err) {
|
||||
assert.ifError(err);
|
||||
return callback(null, info);
|
||||
});
|
||||
}
|
||||
|
||||
utils.serial([
|
||||
function(next) {
|
||||
wdb.create(utils.merge({}, options), function(err, w1_) {
|
||||
@ -625,38 +564,34 @@ describe('Wallet', function() {
|
||||
], function(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
getInfo(function(err, a) {
|
||||
assert.ifError(err);
|
||||
utils.serial([
|
||||
w1.addKey.bind(w1, a.w2.accountKey),
|
||||
w1.addKey.bind(w1, a.w3.accountKey),
|
||||
w2.addKey.bind(w2, a.w1.accountKey),
|
||||
w2.addKey.bind(w2, a.w3.accountKey),
|
||||
w3.addKey.bind(w3, a.w1.accountKey),
|
||||
w3.addKey.bind(w3, a.w2.accountKey)
|
||||
w1.addKey.bind(w1, w2.accountKey),
|
||||
w1.addKey.bind(w1, w3.accountKey),
|
||||
w2.addKey.bind(w2, w1.accountKey),
|
||||
w2.addKey.bind(w2, w3.accountKey),
|
||||
w3.addKey.bind(w3, w1.accountKey),
|
||||
w3.addKey.bind(w3, w2.accountKey)
|
||||
], function(err) {
|
||||
assert.ifError(err);
|
||||
getInfo(function(err, a) {
|
||||
assert.ifError(err);
|
||||
|
||||
// w3 = bcoin.wallet.fromJSON(w3.toJSON());
|
||||
|
||||
// Our p2sh address
|
||||
var addr = a.w1.getAddress();
|
||||
var addr = w1.getAddress();
|
||||
|
||||
if (witness)
|
||||
assert(bcoin.address.parseBase58(addr).type === 'witnessscripthash');
|
||||
else
|
||||
assert(bcoin.address.parseBase58(addr).type === 'scripthash');
|
||||
|
||||
assert.equal(a.w1.getAddress(), addr);
|
||||
assert.equal(a.w2.getAddress(), addr);
|
||||
assert.equal(a.w3.getAddress(), addr);
|
||||
assert.equal(w1.getAddress(), addr);
|
||||
assert.equal(w2.getAddress(), addr);
|
||||
assert.equal(w3.getAddress(), addr);
|
||||
|
||||
var paddr = a.w1.getProgramAddress();
|
||||
assert.equal(a.w1.getProgramAddress(), paddr);
|
||||
assert.equal(a.w2.getProgramAddress(), paddr);
|
||||
assert.equal(a.w3.getProgramAddress(), paddr);
|
||||
var paddr = w1.getProgramAddress();
|
||||
assert.equal(w1.getProgramAddress(), paddr);
|
||||
assert.equal(w2.getProgramAddress(), paddr);
|
||||
assert.equal(w3.getProgramAddress(), paddr);
|
||||
|
||||
// Add a shared unspent transaction to our wallets
|
||||
var utx = bcoin.mtx();
|
||||
@ -672,7 +607,7 @@ describe('Wallet', function() {
|
||||
utx.ts = 1;
|
||||
utx.height = 1;
|
||||
|
||||
assert.equal(a.w1.receiveDepth, 1);
|
||||
assert.equal(w1.receiveDepth, 1);
|
||||
|
||||
wdb.addTX(utx, function(err) {
|
||||
assert.ifError(err);
|
||||
@ -681,91 +616,83 @@ describe('Wallet', function() {
|
||||
wdb.addTX(utx, function(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
getInfo(function(err, a) {
|
||||
assert.ifError(err);
|
||||
assert.equal(a.w1.receiveDepth, 2);
|
||||
assert.equal(a.w1.changeDepth, 1);
|
||||
assert.equal(w1.receiveDepth, 2);
|
||||
assert.equal(w1.changeDepth, 1);
|
||||
|
||||
assert(a.w1.getAddress() !== addr);
|
||||
addr = a.w1.getAddress();
|
||||
assert.equal(a.w1.getAddress(), addr);
|
||||
assert.equal(a.w2.getAddress(), addr);
|
||||
assert.equal(a.w3.getAddress(), addr);
|
||||
assert(w1.getAddress() !== addr);
|
||||
addr = w1.getAddress();
|
||||
assert.equal(w1.getAddress(), addr);
|
||||
assert.equal(w2.getAddress(), addr);
|
||||
assert.equal(w3.getAddress(), addr);
|
||||
|
||||
// Create a tx requiring 2 signatures
|
||||
var send = bcoin.mtx();
|
||||
send.addOutput({ address: a.receive.getAddress(), value: 5460 });
|
||||
send.addOutput({ address: receive.getAddress(), value: 5460 });
|
||||
assert(!send.verify(null, true, flags));
|
||||
w1.fill(send, { rate: 10000, round: true }, function(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
w1.sign(send, function(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert(!send.verify(null, true, flags));
|
||||
w2.sign(send, function(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert(send.verify(null, true, flags));
|
||||
|
||||
assert.equal(a.w1.changeDepth, 1);
|
||||
var change = a.w1.changeAddress.getAddress();
|
||||
assert.equal(a.w1.changeAddress.getAddress(), change);
|
||||
assert.equal(a.w2.changeAddress.getAddress(), change);
|
||||
assert.equal(a.w3.changeAddress.getAddress(), change);
|
||||
|
||||
// Simulate a confirmation
|
||||
send.ps = 0;
|
||||
send.ts = 1;
|
||||
send.height = 1;
|
||||
|
||||
wdb.addTX(send, function(err) {
|
||||
assert.ifError(err);
|
||||
wdb.addTX(send, function(err) {
|
||||
|
||||
assert(!send.verify(null, true, flags));
|
||||
w2.sign(send, function(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert(send.verify(null, true, flags));
|
||||
|
||||
assert.equal(w1.changeDepth, 1);
|
||||
var change = w1.changeAddress.getAddress();
|
||||
assert.equal(w1.changeAddress.getAddress(), change);
|
||||
assert.equal(w2.changeAddress.getAddress(), change);
|
||||
assert.equal(w3.changeAddress.getAddress(), change);
|
||||
|
||||
// Simulate a confirmation
|
||||
send.ps = 0;
|
||||
send.ts = 1;
|
||||
send.height = 1;
|
||||
|
||||
wdb.addTX(send, function(err) {
|
||||
assert.ifError(err);
|
||||
getInfo(function(err, a) {
|
||||
wdb.addTX(send, function(err) {
|
||||
assert.ifError(err);
|
||||
wdb.addTX(send, function(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert.equal(a.w1.receiveDepth, 2);
|
||||
assert.equal(a.w1.changeDepth, 2);
|
||||
assert.equal(w1.receiveDepth, 2);
|
||||
assert.equal(w1.changeDepth, 2);
|
||||
|
||||
assert(a.w1.getAddress() === addr);
|
||||
assert(a.w1.changeAddress.getAddress() !== change);
|
||||
change = a.w1.changeAddress.getAddress();
|
||||
assert.equal(a.w1.changeAddress.getAddress(), change);
|
||||
assert.equal(a.w2.changeAddress.getAddress(), change);
|
||||
assert.equal(a.w3.changeAddress.getAddress(), change);
|
||||
assert(w1.getAddress() === addr);
|
||||
assert(w1.changeAddress.getAddress() !== change);
|
||||
change = w1.changeAddress.getAddress();
|
||||
assert.equal(w1.changeAddress.getAddress(), change);
|
||||
assert.equal(w2.changeAddress.getAddress(), change);
|
||||
assert.equal(w3.changeAddress.getAddress(), change);
|
||||
|
||||
if (witness)
|
||||
send.inputs[0].witness.items[2] = new Buffer([]);
|
||||
else
|
||||
send.inputs[0].script.code[2] = 0;
|
||||
if (witness)
|
||||
send.inputs[0].witness.items[2] = new Buffer([]);
|
||||
else
|
||||
send.inputs[0].script.code[2] = 0;
|
||||
|
||||
assert(!send.verify(null, true, flags));
|
||||
assert.equal(send.getFee(), 10000);
|
||||
assert(!send.verify(null, true, flags));
|
||||
assert.equal(send.getFee(), 10000);
|
||||
|
||||
// w3 = bcoin.wallet.fromJSON(w3.toJSON());
|
||||
// assert.equal(a.w3.receiveDepth, 2);
|
||||
// assert.equal(a.w3.changeDepth, 2);
|
||||
//assert.equal(a.w3.getAddress(), addr);
|
||||
//assert.equal(a.w3.changeAddress.getAddress(), change);
|
||||
// w3 = bcoin.wallet.fromJSON(w3.toJSON());
|
||||
// assert.equal(w3.receiveDepth, 2);
|
||||
// assert.equal(w3.changeDepth, 2);
|
||||
//assert.equal(w3.getAddress(), addr);
|
||||
//assert.equal(w3.changeAddress.getAddress(), change);
|
||||
|
||||
cb();
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user