scanning. local. etc.
This commit is contained in:
parent
b16a8ed1c4
commit
512f3de412
116
lib/bcoin/hd.js
116
lib/bcoin/hd.js
@ -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));
|
||||
};
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user