wallet provider.

This commit is contained in:
Christopher Jeffrey 2016-03-03 19:54:44 -08:00
parent 4df5b305ea
commit e962686e93
3 changed files with 198 additions and 73 deletions

View File

@ -86,7 +86,6 @@ TXPool.prototype.getMap = function getMap(tx, callback) {
map.input = [];
map.output = [];
map.all = [];
map.table = {};
tx.getInputAddresses().forEach(function(address) {
assert(map[address]);
@ -101,10 +100,6 @@ TXPool.prototype.getMap = function getMap(tx, callback) {
map.input = utils.uniqs(map.input);
map.output = utils.uniqs(map.output);
map.all = utils.uniqs(map.input.concat(map.output));
map.table = map.all.reduce(function(out, id) {
out[id] = true;
return out;
}, {});
return callback(null, map);
}

View File

@ -44,8 +44,6 @@ function Wallet(options) {
options.master = bcoin.hd.fromSeed();
this.options = options;
this.db = options.db || null;
this.tx = options.tx || null;
this.provider = options.provider || null;
this.addresses = [];
this.master = options.master || null;
@ -131,61 +129,36 @@ Wallet.prototype._init = function _init() {
assert(!this.receiveAddress.change);
assert(this.changeAddress.change);
if (!this.tx)
if (!this.provider)
return;
this.tx.on('tx', this._onTX = function(tx) {
if (!self.ownInput(tx) && !self.ownOutput(tx))
return;
this.provider.setID(this.id);
this.provider.on('tx', function(tx) {
self.emit('tx', tx);
});
this.tx.on('updated', this._onUpdated = function(tx) {
if (!self.ownInput(tx) && !self.ownOutput(tx))
return;
this.provider.on('updated', function(tx) {
self.emit('updated', tx);
if (!self.provider)
return;
self.getBalance(function(err, balance) {
if (err)
return self.emit('error', err);
self.emit('balance', balance);
});
});
this.tx.on('confirmed', this._onConfirmed = function(tx) {
if (!self.ownInput(tx) && !self.ownOutput(tx))
return;
this.provider.on('balance', function(balance) {
self.emit('balance', balance);
});
this.provider.on('confirmed', function(tx) {
self.syncOutputDepth(tx);
self.emit('confirmed', tx);
});
this.provider.on('unconfirmed', function(tx) {
self.syncOutputDepth(tx);
self.emit('unconfirmed', tx);
});
};
Wallet.prototype.destroy = function destroy() {
if (this.tx) {
if (this._onTX) {
this.tx.removeListener('tx', this._onTX);
delete this._onTX;
}
if (this._onUpdated) {
this.tx.removeListener('updated', this._onUpdated);
delete this._onUpdated;
}
if (this._onConfirmed) {
this.tx.removeListener('confirmed', this._onConfirmed);
delete this._onConfirmed;
}
}
this.db = null;
this.tx = null;
this.provider.destroy();
this.provider = null;
};
@ -407,8 +380,8 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) {
this.addressMap[address.getProgramAddress()] = data.path;
// Update the DB with the new address.
if (this.db)
this.db.update(this, address);
if (this.provider && this.provider.update)
this.provider.update(this, address);
this.emit('add address', address);
@ -539,7 +512,21 @@ Wallet.prototype.fillPrevout = function fillPrevout(tx, callback) {
if (!this.provider)
return callback(new Error('No wallet provider available.'));
return this.provider.fillCoin(tx, callback);
return this.provider.fillTX(tx, callback);
};
Wallet.prototype.getCoin = function getCoin(id, callback) {
if (!this.provider)
return callback(new Error('No wallet provider available.'));
return this.provider.getCoin(id, callback);
};
Wallet.prototype.getTX = function getTX(hash, callback) {
if (!this.provider)
return callback(new Error('No wallet provider available.'));
return this.provider.getTX(hash, callback);
};
Wallet.prototype.createTX = function createTX(options, outputs, callback) {
@ -801,45 +788,45 @@ Wallet.prototype.sign = function sign(tx, type, index) {
};
Wallet.prototype.addTX = function addTX(tx, callback) {
if (!this.tx)
if (!this.provider || !this.provider.addTX)
return callback(new Error('No transaction pool available.'));
return this.tx.add(tx, callback);
return this.provider.addTX(tx, callback);
};
Wallet.prototype.getAll = function getAll(callback) {
if (!this.provider)
return callback(new Error('No wallet provider available.'));
return this.provider.getAll(this, callback);
return this.provider.getAll(callback);
};
Wallet.prototype.getCoins = function getCoins(callback) {
if (!this.provider)
return callback(new Error('No wallet provider available.'));
return this.provider.getCoins(this, callback);
return this.provider.getCoins(callback);
};
Wallet.prototype.getPending = function getPending(callback) {
if (!this.provider)
return callback(new Error('No wallet provider available.'));
return this.provider.getPending(this, callback);
return this.provider.getPending(callback);
};
Wallet.prototype.getBalance = function getBalance(callback) {
if (!this.provider)
return callback(new Error('No wallet provider available.'));
return this.provider.getBalance(this, callback);
return this.provider.getBalance(callback);
};
Wallet.prototype.getLast = function getLast(callback) {
if (!this.provider)
return callback(new Error('No wallet provider available.'));
return this.provider.getLast(this, callback);
return this.provider.getLast(callback);
};
Wallet.prototype.getPrivateKey = function getPrivateKey(enc) {

View File

@ -125,9 +125,42 @@ WalletDB.prototype._init = function _init() {
self.emit('error', err);
});
this.tx.on('tx', function(tx, map) {
map.all.forEach(function(id) {
self.emit(id + ' tx', tx);
});
});
this.tx.on('confirmed', function(tx, map) {
map.all.forEach(function(id) {
self.emit(id + ' confirmed', tx);
});
});
this.tx.on('unconfirmed', function(tx, map) {
map.all.forEach(function(id) {
self.emit(id + ' unconfirmed', tx);
});
});
this.tx.on('updated', function(tx, map) {
self.emit('wallet tx', tx, map);
utils.forEachSerial(map.output, function(id, next) {
if (self.listeners(id + ' balance').length === 0)
return next();
self.getBalance(id, function(err, balance) {
if (err)
return self.emit('error', err);
self.emit(id + ' balance', balance);
});
}, function(err) {
if (err)
self.emit('error', err);
});
// Only sync for confirmed txs.
if (tx.ts === 0)
return;
@ -145,6 +178,7 @@ WalletDB.prototype._init = function _init() {
self.saveJSON(id, json, function(err) {
if (err)
return next(err);
next();
});
});
@ -197,7 +231,7 @@ WalletDB.prototype.saveJSON = function saveJSON(id, json, callback) {
callback = utils.ensure(callback);
function cb(err, json) {
return this._saveDB(id, json, function(err, json) {
var batch;
if (err)
@ -216,9 +250,7 @@ WalletDB.prototype.saveJSON = function saveJSON(id, json, callback) {
}
return callback(null, json);
}
return this._saveDB(id, json, cb);
});
};
WalletDB.prototype.removeJSON = function removeJSON(id, callback) {
@ -229,7 +261,7 @@ WalletDB.prototype.removeJSON = function removeJSON(id, callback) {
if (typeof id === 'object')
id = id.id;
function cb(err, json) {
return this._removeDB(id, function(err, json) {
var batch;
if (err)
@ -248,9 +280,7 @@ WalletDB.prototype.removeJSON = function removeJSON(id, callback) {
}
return callback(null, json);
}
return this._removeDB(id, cb);
});
};
WalletDB.prototype._getDB = function _getDB(id, callback) {
@ -334,9 +364,7 @@ WalletDB.prototype.get = function get(id, passphrase, callback) {
try {
options = bcoin.wallet._fromJSON(options, passphrase);
options.db = self;
options.tx = self.tx;
options.provider = self;
options.provider = new Provider(self);
wallet = new bcoin.wallet(options);
} catch (e) {
return callback(e);
@ -398,18 +426,14 @@ WalletDB.prototype.create = function create(options, callback) {
if (json) {
try {
options = bcoin.wallet._fromJSON(json, options.passphrase);
options.db = self;
options.tx = self.tx;
options.provider = self;
options.provider = new Provider(self);
wallet = new bcoin.wallet(options);
} catch (e) {
return callback(e);
}
done();
} else {
options.db = self;
options.tx = self.tx;
options.provider = self;
options.provider = new Provider(self);
wallet = new bcoin.wallet(options);
self.saveJSON(wallet.id, wallet.toJSON(), done);
}
@ -535,6 +559,125 @@ WalletDB.prototype.removeBlock = function removeBlock(block, callback) {
}, callback);
};
/**
* Provider
*/
function Provider(db) {
if (!(this instanceof Provider))
return new Provider(db);
EventEmitter.call(this);
this.db = db;
this.id = null;
}
utils.inherits(Provider, EventEmitter);
Provider.prototype.setID = function setID(id) {
var self = this;
assert(!this.id);
this.id = id;
this.db.on(id + ' tx', this._onTX = function(tx) {
self.emit('tx', tx);
});
this.db.on(id + ' updated', this._onUpdated = function(tx) {
self.emit('updated', tx);
});
this.db.on(id + ' confirmed', this._onConfirmed = function(tx) {
self.emit('confirmed', tx);
});
this.db.on(id + ' unconfirmed', this._onUnconfirmed = function(tx) {
self.emit('unconfirmed', tx);
});
this.db.on(id + ' balance', this._onBalance = function(balance) {
self.emit('balance', balance);
});
};
Provider.prototype.destroy = function destroy() {
if (this.db) {
if (this._onTX) {
this.removeListener(this.id + ' tx', this._onTX);
delete this._onTX;
}
if (this._onUpdated) {
this.removeListener(this.id + ' updated', this._onUpdated);
delete this._onUpdated;
}
if (this._onConfirmed) {
this.removeListener(this.id + ' confirmed', this._onConfirmed);
delete this._onConfirmed;
}
if (this._onUnconfirmed) {
this.removeListener(this.id + ' unconfirmed', this._onUnconfirmed);
delete this._onUnconfirmed;
}
if (this._onBalance) {
this.removeListener(this.id + ' balance', this._onBalance);
delete this._onBalance;
}
}
this.db = null;
};
Provider.prototype.getAll = function getAll(callback) {
return this.db.getAll(this.id, callback);
};
Provider.prototype.getCoins = function getCoins(callback) {
return this.db.getCoins(this.id, callback);
};
Provider.prototype.getPending = function getPending(callback) {
return this.db.getPending(this.id, callback);
};
Provider.prototype.getBalance = function getBalance(callback) {
return this.db.getBalance(this.id, callback);
};
Provider.prototype.getLast = function getLast(callback) {
return this.db.getLast(this.id, callback);
};
Provider.prototype.getTX = function getTX(hash, callback) {
return this.db.getTX(hash, callback);
};
Provider.prototype.getCoin = function getCoin(hash, index, callback) {
return this.db.getCoin(hash, index, callback);
};
Provider.prototype.fillTX = function fillTX(tx, callback) {
return this.db.fillTX(tx, callback);
};
Provider.prototype.fillCoin = function fillCoin(tx, callback) {
return this.db.fillCoin(tx, callback);
};
Provider.prototype.addTX = function addTX(tx, callback) {
return this.db.tx.add(tx, callback);
};
Provider.prototype.update = function update(wallet, address) {
return this.db.update(wallet, address);
};
/**
* Expose
*/