scanning. local. etc.

This commit is contained in:
Christopher Jeffrey 2016-05-31 05:44:44 -07:00
parent b16a8ed1c4
commit 512f3de412
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 206 additions and 43 deletions

View File

@ -113,6 +113,9 @@ function Mnemonic(options) {
if (!options)
options = {};
if (typeof options === 'string')
options = { phrase: options };
this.bits = options.bits || 128;
this.entropy = options.entropy;
this.phrase = options.phrase;
@ -300,13 +303,25 @@ HD.fromMnemonic = function fromMnemonic(options, network) {
* Instantiate an HD key from a jsonified key object.
* @param {Object} json - The jsonified transaction object.
* @param {String?} passphrase
* @returns {HDPrivateKey}
* @returns {HDPrivateKey|HDPublicKey}
*/
HD.fromJSON = function fromJSON(json, passphrase) {
return HDPrivateKey.fromJSON(json, passphrase);
};
/**
* Instantiate an HD key from serialized data.
* @param {Buffer} data
* @returns {HDPrivateKey|HDPublicKey}
*/
HD.fromRaw = function fromRaw(data) {
if (HDPrivateKey.hasPrefix(data))
return HDPrivateKey.fromRaw(data);
return HDPublicKey.fromRaw(data);
};
/**
* Generate an hdkey from any number of options.
* @param {Object|Mnemonic|Buffer} options - mnemonic, mnemonic
@ -335,6 +350,9 @@ HD.fromAny = function fromAny(options, network) {
if (HDPublicKey.isExtended(xkey))
return HDPublicKey.fromBase58(xkey);
if (HD.hasPrefix(options))
return HD.fromRaw(options);
return HDPrivateKey.fromMnemonic(options, network);
};
@ -349,6 +367,17 @@ HD.isExtended = function isExtended(data) {
|| HDPublicKey.isExtended(data);
};
/**
* Test whether an object is in the form of a serialized hd key.
* @param {Buffer} data
* @returns {NetworkType}
*/
HD.hasPrefix = function hasPrefix(data) {
return HDPrivateKey.hasPrefix(data)
|| HDPublicKey.hasPrefix(data);
};
/**
* Parse a derivation path and return an array of indexes.
* @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
@ -655,6 +684,30 @@ HDPrivateKey.isExtended = function isExtended(data) {
return false;
};
/**
* Test whether a buffer has a valid network prefix.
* @param {Buffer} data
* @returns {NetworkType}
*/
HDPrivateKey.hasPrefix = function hasPrefix(data) {
var i, version, prefix, type;
if (!Buffer.isBuffer(data))
return false;
version = data.readUInt32BE(0, true);
for (i = 0; i < network.types.length; i++) {
type = network.types[i];
prefix = network[type].prefixes.xprivkey;
if (version === prefix)
return type;
}
return false;
};
/**
* Test whether a string is a valid path.
* @param {String} path
@ -865,6 +918,12 @@ HDPrivateKey.parseBase58 = function parseBase58(xkey) {
return data;
};
/**
* Parse a raw serialized key.
* @param {Buffer} raw
* @returns {Object}
*/
HDPrivateKey.parseRaw = function parseRaw(raw) {
var p = new BufferReader(raw, true);
var data = {};
@ -903,6 +962,12 @@ HDPrivateKey.prototype.toBase58 = function toBase58(network) {
return utils.toBase58(this.toRaw(network));
};
/**
* Serialize the key
* @param {Network|String} network
* @returns {Buffer}
*/
HDPrivateKey.prototype.toRaw = function toRaw(network, writer) {
var p = new BufferWriter(writer);
@ -936,6 +1001,12 @@ HDPrivateKey.fromBase58 = function fromBase58(xkey) {
return new HDPrivateKey(HDPrivateKey.parseBase58(xkey));
};
/**
* Instantiate key from serialized data.
* @param {Buffer} raw
* @returns {HDPrivateKey}
*/
HDPrivateKey.fromRaw = function fromRaw(raw) {
return new HDPrivateKey(HDPrivateKey.parseRaw(raw));
};
@ -1312,6 +1383,30 @@ HDPublicKey.isExtended = function isExtended(data) {
return false;
};
/**
* Test whether a buffer has a valid network prefix.
* @param {Buffer} data
* @returns {NetworkType}
*/
HDPublicKey.hasPrefix = function hasPrefix(data) {
var i, version, prefix, type;
if (!Buffer.isBuffer(data))
return false;
version = data.readUInt32BE(0, true);
for (i = 0; i < network.types.length; i++) {
type = network.types[i];
prefix = network[type].prefixes.xpubkey;
if (version === prefix)
return type;
}
return false;
};
/**
* Parse a base58 extended public key.
* @param {Base58String} xkey
@ -1324,10 +1419,15 @@ HDPublicKey.parseBase58 = function parseBase58(xkey) {
return data;
};
/**
* Parse a raw serialized key.
* @param {Buffer} raw
* @returns {Object}
*/
HDPublicKey.parseRaw = function parseRaw(raw) {
var p = new BufferReader(raw, true);
var data = {};
var i, type, prefix;
data.version = p.readU32BE();
data.depth = p.readU8();
@ -1361,6 +1461,12 @@ HDPublicKey.prototype.toBase58 = function toBase58(network) {
return utils.toBase58(this.toRaw(network));
};
/**
* Serialize the key
* @param {Network|String} network
* @returns {Buffer}
*/
HDPublicKey.prototype.toRaw = function toRaw(network, writer) {
var p = new BufferWriter(writer);
@ -1393,6 +1499,12 @@ HDPublicKey.fromBase58 = function fromBase58(xkey) {
return new HDPublicKey(HDPublicKey.parseBase58(xkey));
};
/**
* Instantiate key from serialized data.
* @param {Buffer} raw
* @returns {HDPublicKey}
*/
HDPublicKey.fromRaw = function fromRaw(data) {
return new HDPublicKey(HDPublicKey.parseRaw(data));
};

View File

@ -128,7 +128,7 @@ ldb.parseOptions = function parseOptions(options) {
else if (bcoin.isBrowser)
db = require('level-js');
else
db = require(options.db);
db = require(backend.name);
return utils.merge({}, options, {
backend: backend.name,

View File

@ -71,16 +71,21 @@ function Wallet(options) {
this.loaded = false;
this.loading = false;
this.account = null;
this.local = false;
if (!this.id)
this.id = this.getID();
// An in-memory database for testing.
if (!this.db) {
if (this.options.passphrase)
this.master.encrypt(this.options.passphrase);
if (!this.db || typeof this.db === 'string') {
this.local = true;
this.db = new bcoin.walletdb({
network: this.network,
name: this.id,
db: 'memory'
name: 'wallet-' + this.id,
location: this.options.location,
db: this.db || 'memory'
});
}
}
@ -174,9 +179,6 @@ Wallet.prototype.init = function init(callback) {
self.account = account;
if (options.passphrase)
self.master.encrypt(options.passphrase);
if (Buffer.isBuffer(options.passphrase))
options.passphrase.fill(0);
@ -189,11 +191,25 @@ Wallet.prototype.init = function init(callback) {
if (err)
return callback(err);
if (self.local) {
return self.db.getRaw(self.id, function(err, data) {
if (err)
return callback(err);
if (data) {
utils.merge(self, data);
return self.getAccount(0, done);
}
self.initialized = true;
self.createAccount(options, done);
});
}
if (self.initialized)
return self.getAccount(0, done);
self.initialized = true;
self.createAccount(options, done);
});
};
@ -439,7 +455,7 @@ Wallet.prototype.fill = function fill(tx, options, callback) {
options = {};
if (!this.initialized)
return callback(new Error('Cannot use uninitialized wallet.'));
return callback(new Error('Wallet is not initialized.'));
this.getCoins(options.account, function(err, coins) {
if (err)
@ -862,24 +878,30 @@ Wallet.prototype.scan = function scan(getByAddress, callback) {
var self = this;
var total = 0;
(function next() {
self.createAccount(self.options, function(err, account) {
if (!this.initialized)
return callback(new Error('Wallet is not initialized.'));
(function next(err, account) {
if (err)
return callback(err);
account.scan(getByAddress, function(err, result) {
if (err)
return callback(err);
account.scan(getByAddress, function(err, result) {
if (err)
return callback(err);
if (result === 0)
if (result === 0) {
return self.save(function(err) {
if (err)
return callback(err);
return callback(null, total);
});
}
total += result;
total += result;
next();
});
self.createAccount(self.options, next);
});
})();
})(null, this.account);
};
/**
@ -2034,7 +2056,7 @@ Account.prototype.scan = function scan(getByAddress, callback) {
var total = 0;
if (!this.initialized)
return callback(new Error('Account is uninitialized.'));
return callback(new Error('Account is not initialized.'));
function addTX(txs, calback) {
if (!Array.isArray(txs) || txs.length === 0)
@ -2051,38 +2073,37 @@ Account.prototype.scan = function scan(getByAddress, callback) {
}
(function chainCheck(change) {
var address = change ? self.changeAddress : self.receiveAddress;
var gap = 0;
(function next() {
self.createAddress(change, function(err, address) {
(function next(err, address) {
if (err)
return callback(err);
getByAddress(address.getAddress(), function(err, txs) {
if (err)
return callback(err);
getByAddress(address.getAddress(), function(err, txs) {
addTX(txs, function(err, result) {
if (err)
return callback(err);
addTX(txs, function(err, result) {
if (err)
return callback(err);
if (result) {
total++;
gap = 0;
return self.createAddress(change, next);
}
if (result) {
total++;
gap = 0;
return next();
}
if (++gap < 20)
return self.createAddress(change, next);
if (++gap < 20)
return next();
if (!change)
return chainCheck(true);
if (!change)
return chainCheck(true);
return callback(null, total);
});
return callback(null, total);
});
});
})();
})(null, address);
})(false);
};

View File

@ -340,6 +340,36 @@ WalletDB.prototype.get = function get(id, callback) {
});
};
/**
* Get raw wallet from the database, do not instantiate.
* @param {WalletID} id
* @param {Function} callback - Returns [Error, {@link Wallet}].
*/
WalletDB.prototype.getRaw = function getRaw(id, callback) {
var self = this;
var wallet;
if (!id)
return callback();
this.db.get('w/' + id, function(err, data) {
if (err && err.type !== 'NotFoundError')
return callback();
if (!data)
return callback();
try {
data = bcoin.wallet.parseRaw(data);
} catch (e) {
return callback(e);
}
return callback(null, data);
});
};
/**
* Save a wallet to the database.
* @param {Wallet} wallet