wallet: use batches.
This commit is contained in:
parent
969fd8f704
commit
55f5ff9493
@ -11,6 +11,7 @@ const assert = require('assert');
|
|||||||
|
|
||||||
const LOW = Buffer.from([0x00]);
|
const LOW = Buffer.from([0x00]);
|
||||||
const HIGH = Buffer.from([0xff]);
|
const HIGH = Buffer.from([0xff]);
|
||||||
|
const DUMMY = Buffer.alloc(0);
|
||||||
|
|
||||||
let VERSION_ERROR;
|
let VERSION_ERROR;
|
||||||
|
|
||||||
@ -50,7 +51,6 @@ function LowlevelUp(backend, location, options) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the database.
|
* Initialize the database.
|
||||||
* @method
|
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -293,6 +293,19 @@ LowlevelUp.prototype.batch = function batch() {
|
|||||||
return new Batch(this);
|
return new Batch(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a bucket.
|
||||||
|
* @param {Buffer} [prefix=DUMMY]
|
||||||
|
* @returns {Bucket}
|
||||||
|
*/
|
||||||
|
|
||||||
|
LowlevelUp.prototype.bucket = function bucket(prefix) {
|
||||||
|
if (!this.loaded)
|
||||||
|
throw new Error('Database is closed.');
|
||||||
|
|
||||||
|
return new Bucket(this, this.batch(), prefix);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an iterator.
|
* Create an iterator.
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
@ -376,7 +389,6 @@ LowlevelUp.prototype.compactRange = function compactRange(start, end) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether a key exists.
|
* Test whether a key exists.
|
||||||
* @method
|
|
||||||
* @param {String} key
|
* @param {String} key
|
||||||
* @returns {Promise} - Returns Boolean.
|
* @returns {Promise} - Returns Boolean.
|
||||||
*/
|
*/
|
||||||
@ -388,89 +400,54 @@ LowlevelUp.prototype.has = async function has(key) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect all keys from iterator options.
|
* Collect all keys from iterator options.
|
||||||
* @method
|
|
||||||
* @param {Object} options - Iterator options.
|
* @param {Object} options - Iterator options.
|
||||||
* @returns {Promise} - Returns Array.
|
* @returns {Promise} - Returns Array.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LowlevelUp.prototype.range = async function range(options) {
|
LowlevelUp.prototype.range = function range(options) {
|
||||||
const iter = this.iterator({
|
const iter = this.iterator({
|
||||||
gte: options.gte,
|
gte: options.gte,
|
||||||
lte: options.lte,
|
lte: options.lte,
|
||||||
keys: true,
|
keys: true,
|
||||||
values: true
|
values: true
|
||||||
});
|
});
|
||||||
|
return iter.range(options.parse);
|
||||||
const items = [];
|
|
||||||
|
|
||||||
await iter.each((key, value) => {
|
|
||||||
if (options.parse) {
|
|
||||||
const item = options.parse(key, value);
|
|
||||||
if (item)
|
|
||||||
items.push(item);
|
|
||||||
} else {
|
|
||||||
items.push(new IteratorItem(key, value));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return items;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect all keys from iterator options.
|
* Collect all keys from iterator options.
|
||||||
* @method
|
|
||||||
* @param {Object} options - Iterator options.
|
* @param {Object} options - Iterator options.
|
||||||
* @returns {Promise} - Returns Array.
|
* @returns {Promise} - Returns Array.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LowlevelUp.prototype.keys = async function keys(options) {
|
LowlevelUp.prototype.keys = function keys(options) {
|
||||||
const iter = this.iterator({
|
const iter = this.iterator({
|
||||||
gte: options.gte,
|
gte: options.gte,
|
||||||
lte: options.lte,
|
lte: options.lte,
|
||||||
keys: true,
|
keys: true,
|
||||||
values: false
|
values: false
|
||||||
});
|
});
|
||||||
|
return iter.keys(options.parse);
|
||||||
const items = [];
|
|
||||||
|
|
||||||
await iter.each((key) => {
|
|
||||||
if (options.parse)
|
|
||||||
key = options.parse(key);
|
|
||||||
items.push(key);
|
|
||||||
});
|
|
||||||
|
|
||||||
return items;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect all keys from iterator options.
|
* Collect all keys from iterator options.
|
||||||
* @method
|
|
||||||
* @param {Object} options - Iterator options.
|
* @param {Object} options - Iterator options.
|
||||||
* @returns {Promise} - Returns Array.
|
* @returns {Promise} - Returns Array.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LowlevelUp.prototype.values = async function values(options) {
|
LowlevelUp.prototype.values = function values(options) {
|
||||||
const iter = this.iterator({
|
const iter = this.iterator({
|
||||||
gte: options.gte,
|
gte: options.gte,
|
||||||
lte: options.lte,
|
lte: options.lte,
|
||||||
keys: false,
|
keys: false,
|
||||||
values: true
|
values: true
|
||||||
});
|
});
|
||||||
|
return iter.values(options.parse);
|
||||||
const items = [];
|
|
||||||
|
|
||||||
await iter.each((value) => {
|
|
||||||
if (options.parse)
|
|
||||||
value = options.parse(value);
|
|
||||||
items.push(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
return items;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dump database (for debugging).
|
* Dump database (for debugging).
|
||||||
* @method
|
|
||||||
* @returns {Promise} - Returns Object.
|
* @returns {Promise} - Returns Object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -493,7 +470,6 @@ LowlevelUp.prototype.dump = async function dump() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Write and assert a version number for the database.
|
* Write and assert a version number for the database.
|
||||||
* @method
|
|
||||||
* @param {Number} version
|
* @param {Number} version
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
@ -518,7 +494,6 @@ LowlevelUp.prototype.checkVersion = async function checkVersion(key, version) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone the database.
|
* Clone the database.
|
||||||
* @method
|
|
||||||
* @param {String} path
|
* @param {String} path
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
@ -631,6 +606,168 @@ Batch.prototype.clear = function clear() {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bucket
|
||||||
|
* @constructor
|
||||||
|
* @ignore
|
||||||
|
* @param {LowlevelUp} db
|
||||||
|
* @param {Batch} batch
|
||||||
|
* @param {Buffer} [prefix=DUMMY]
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Bucket(db, batch, prefix, parent) {
|
||||||
|
this.db = db;
|
||||||
|
this.batch = batch;
|
||||||
|
this.prefix = prefix || DUMMY;
|
||||||
|
this.parent = parent || DUMMY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get child bucket.
|
||||||
|
* @param {Buffer} [prefix=DUMMY]
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.batch = function batch() {
|
||||||
|
return new Bucket(this.db, this.batch, this.prefix, this.parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get child bucket.
|
||||||
|
* @param {Buffer} [prefix=DUMMY]
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.bucket = function bucket(prefix = DUMMY) {
|
||||||
|
const parent = this.prefix;
|
||||||
|
const child = concat(parent, prefix);
|
||||||
|
return new Bucket(this.db, this.batch, child, parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get child bucket.
|
||||||
|
* @param {Buffer} [prefix=DUMMY]
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.up = function up() {
|
||||||
|
return new Bucket(this.db, this.batch, this.parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value from the bucket.
|
||||||
|
* @param {String|Buffer} key
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.has = function has(key) {
|
||||||
|
return this.db.has(concat(this.prefix, key));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value from the bucket.
|
||||||
|
* @param {String|Buffer} key
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.get = function get(key) {
|
||||||
|
return this.db.get(concat(this.prefix, key));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an iterator.
|
||||||
|
* @param {Object} options
|
||||||
|
* @returns {Iterator}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.iterator = function iterator(options) {
|
||||||
|
return new Iterator(this.db, options, this.prefix);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect all keys from iterator options.
|
||||||
|
* @param {Object} options - Iterator options.
|
||||||
|
* @returns {Promise} - Returns Array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.range = function range(options = {}) {
|
||||||
|
const iter = this.iterator({
|
||||||
|
gte: options.gte,
|
||||||
|
lte: options.lte,
|
||||||
|
keys: true,
|
||||||
|
values: true
|
||||||
|
});
|
||||||
|
return iter.range(options.parse);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect all keys from iterator options.
|
||||||
|
* @param {Object} options - Iterator options.
|
||||||
|
* @returns {Promise} - Returns Array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.keys = function keys(options = {}) {
|
||||||
|
const iter = this.iterator({
|
||||||
|
gte: options.gte,
|
||||||
|
lte: options.lte,
|
||||||
|
keys: true,
|
||||||
|
values: false
|
||||||
|
});
|
||||||
|
return iter.keys(options.parse);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect all keys from iterator options.
|
||||||
|
* @param {Object} options - Iterator options.
|
||||||
|
* @returns {Promise} - Returns Array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.values = function values(options = {}) {
|
||||||
|
const iter = this.iterator({
|
||||||
|
gte: options.gte,
|
||||||
|
lte: options.lte,
|
||||||
|
keys: false,
|
||||||
|
values: true
|
||||||
|
});
|
||||||
|
return iter.values(options.parse);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a value to the bucket.
|
||||||
|
* @param {String|Buffer} key
|
||||||
|
* @param {Buffer} value
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.put = function put(key, value) {
|
||||||
|
this.batch.put(concat(this.prefix, key), value);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a value from the bucket.
|
||||||
|
* @param {String|Buffer} key
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.del = function del(key) {
|
||||||
|
this.batch.del(concat(this.prefix, key));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write batch to database.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.write = function write() {
|
||||||
|
return this.batch.write();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the batch.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bucket.prototype.clear = function clear() {
|
||||||
|
this.batch.clear();
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator
|
* Iterator
|
||||||
* @constructor
|
* @constructor
|
||||||
@ -639,8 +776,9 @@ Batch.prototype.clear = function clear() {
|
|||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Iterator(db, options) {
|
function Iterator(db, options, prefix) {
|
||||||
this.options = new IteratorOptions(options);
|
this.prefix = prefix || DUMMY;
|
||||||
|
this.options = new IteratorOptions(options, prefix);
|
||||||
this.options.keyAsBuffer = db.options.bufferKeys;
|
this.options.keyAsBuffer = db.options.bufferKeys;
|
||||||
|
|
||||||
this.iter = db.binding.iterator(this.options);
|
this.iter = db.binding.iterator(this.options);
|
||||||
@ -681,7 +819,7 @@ Iterator.prototype.each = async function each(cb) {
|
|||||||
await this.read();
|
await this.read();
|
||||||
|
|
||||||
while (this.cache.length > 0) {
|
while (this.cache.length > 0) {
|
||||||
const key = this.cache.pop();
|
const key = slice(this.prefix, this.cache.pop());
|
||||||
const value = this.cache.pop();
|
const value = this.cache.pop();
|
||||||
|
|
||||||
let result = null;
|
let result = null;
|
||||||
@ -725,7 +863,7 @@ Iterator.prototype.next = async function next() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.cache.length > 0) {
|
if (this.cache.length > 0) {
|
||||||
this.key = this.cache.pop();
|
this.key = slice(this.prefix, this.cache.pop());
|
||||||
this.value = this.cache.pop();
|
this.value = this.cache.pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -803,6 +941,64 @@ Iterator.prototype.end = function end() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect all keys from iterator options.
|
||||||
|
* @param {Object} options - Iterator options.
|
||||||
|
* @returns {Promise} - Returns Array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Iterator.prototype.range = async function range(parse) {
|
||||||
|
const items = [];
|
||||||
|
|
||||||
|
await this.each((key, value) => {
|
||||||
|
if (parse) {
|
||||||
|
const item = parse(key, value);
|
||||||
|
if (item)
|
||||||
|
items.push(item);
|
||||||
|
} else {
|
||||||
|
items.push(new IteratorItem(key, value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect all keys from iterator options.
|
||||||
|
* @param {Object} options - Iterator options.
|
||||||
|
* @returns {Promise} - Returns Array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Iterator.prototype.keys = async function keys(parse) {
|
||||||
|
const items = [];
|
||||||
|
|
||||||
|
await this.each((key) => {
|
||||||
|
if (parse)
|
||||||
|
key = parse(key);
|
||||||
|
items.push(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect all keys from iterator options.
|
||||||
|
* @param {Object} options - Iterator options.
|
||||||
|
* @returns {Promise} - Returns Array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Iterator.prototype.values = async function values(parse) {
|
||||||
|
const items = [];
|
||||||
|
|
||||||
|
await this.each((value) => {
|
||||||
|
if (parse)
|
||||||
|
value = parse(value);
|
||||||
|
items.push(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator Item
|
* Iterator Item
|
||||||
* @ignore
|
* @ignore
|
||||||
@ -948,7 +1144,7 @@ LLUOptions.prototype.fromOptions = function fromOptions(options) {
|
|||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function IteratorOptions(options) {
|
function IteratorOptions(options, prefix) {
|
||||||
this.gte = null;
|
this.gte = null;
|
||||||
this.lte = null;
|
this.lte = null;
|
||||||
this.gt = null;
|
this.gt = null;
|
||||||
@ -964,8 +1160,7 @@ function IteratorOptions(options) {
|
|||||||
// Note: do not add this property.
|
// Note: do not add this property.
|
||||||
// this.limit = null;
|
// this.limit = null;
|
||||||
|
|
||||||
if (options)
|
this.fromOptions(options || {}, prefix || DUMMY);
|
||||||
this.fromOptions(options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -975,27 +1170,44 @@ function IteratorOptions(options) {
|
|||||||
* @returns {IteratorOptions}
|
* @returns {IteratorOptions}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IteratorOptions.prototype.fromOptions = function fromOptions(options) {
|
IteratorOptions.prototype.fromOptions = function fromOptions(options, prefix) {
|
||||||
assert(options, 'Options are required.');
|
assert(options, 'Options are required.');
|
||||||
|
|
||||||
if (options.gte != null) {
|
if (options.gte != null) {
|
||||||
assert(Buffer.isBuffer(options.gte) || typeof options.gte === 'string');
|
assert(Buffer.isBuffer(options.gte) || typeof options.gte === 'string');
|
||||||
this.gte = options.gte;
|
this.gte = concat(prefix, options.gte);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.lte != null) {
|
if (options.lte != null) {
|
||||||
assert(Buffer.isBuffer(options.lte) || typeof options.lte === 'string');
|
assert(Buffer.isBuffer(options.lte) || typeof options.lte === 'string');
|
||||||
this.lte = options.lte;
|
this.lte = concat(prefix, options.lte);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.gt != null) {
|
if (options.gt != null) {
|
||||||
assert(Buffer.isBuffer(options.gt) || typeof options.gt === 'string');
|
assert(Buffer.isBuffer(options.gt) || typeof options.gt === 'string');
|
||||||
this.gt = options.gt;
|
this.gt = concat(prefix, options.gt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.lt != null) {
|
if (options.lt != null) {
|
||||||
assert(Buffer.isBuffer(options.lt) || typeof options.lt === 'string');
|
assert(Buffer.isBuffer(options.lt) || typeof options.lt === 'string');
|
||||||
this.lt = options.lt;
|
this.lt = concat(prefix, options.lt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefix.length > 0) {
|
||||||
|
if (!this.gt && !this.gte)
|
||||||
|
this.gt = prefix;
|
||||||
|
|
||||||
|
if (!this.lt && !this.lte) {
|
||||||
|
const pre = Buffer.from(prefix);
|
||||||
|
for (let i = pre.length - 1; i >= 0; i--) {
|
||||||
|
if (pre[i] !== 0xff) {
|
||||||
|
pre[i] += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pre[i] = 0;
|
||||||
|
}
|
||||||
|
this.lt = pre;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.keys != null) {
|
if (options.keys != null) {
|
||||||
@ -1058,6 +1270,54 @@ function wrap(resolve, reject) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function slice(prefix, key) {
|
||||||
|
if (!key || key.length === 0)
|
||||||
|
return key;
|
||||||
|
|
||||||
|
if (prefix.length === 0)
|
||||||
|
return key;
|
||||||
|
|
||||||
|
if (typeof key === 'string') {
|
||||||
|
if (Buffer.isBuffer(prefix))
|
||||||
|
prefix = prefix.toString('ascii');
|
||||||
|
assert(typeof prefix === 'string');
|
||||||
|
assert(key.length > prefix.length);
|
||||||
|
return key.slice(prefix.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(Buffer.isBuffer(key));
|
||||||
|
assert(key.length > prefix.length);
|
||||||
|
|
||||||
|
return key.slice(prefix.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function concat(prefix, key) {
|
||||||
|
if (prefix.length === 0)
|
||||||
|
return key;
|
||||||
|
|
||||||
|
if (typeof key === 'string') {
|
||||||
|
if (Buffer.isBuffer(prefix))
|
||||||
|
prefix = prefix.toString('ascii');
|
||||||
|
assert(typeof prefix === 'string');
|
||||||
|
return prefix + key;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(Buffer.isBuffer(key));
|
||||||
|
|
||||||
|
const data = Buffer.allocUnsafe(prefix.length + key.length);
|
||||||
|
|
||||||
|
if (typeof prefix === 'string') {
|
||||||
|
data.write(prefix, 0, 'ascii');
|
||||||
|
} else {
|
||||||
|
assert(Buffer.isBuffer(prefix));
|
||||||
|
prefix.copy(data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
key.copy(data, prefix.length);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
VERSION_ERROR = 'Warning:'
|
VERSION_ERROR = 'Warning:'
|
||||||
+ ' Your database does not match the current database version.'
|
+ ' Your database does not match the current database version.'
|
||||||
+ ' This is likely because the database layout or serialization'
|
+ ' This is likely because the database layout or serialization'
|
||||||
|
|||||||
@ -667,13 +667,13 @@ HTTPClient.prototype.retoken = async function retoken(id, passphrase) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Change or set master key's passphrase.
|
* Change or set master key's passphrase.
|
||||||
|
* @param {String|Buffer} passphrase
|
||||||
* @param {(String|Buffer)?} old
|
* @param {(String|Buffer)?} old
|
||||||
* @param {String|Buffer} new_
|
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HTTPClient.prototype.setPassphrase = function setPassphrase(id, old, new_) {
|
HTTPClient.prototype.setPassphrase = function setPassphrase(id, passphrase, old) {
|
||||||
const body = { old: old, new: new_ };
|
const body = { passphrase , old };
|
||||||
return this._post(`/wallet/${id}/passphrase`, body);
|
return this._post(`/wallet/${id}/passphrase`, body);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -336,8 +336,8 @@ HTTPWallet.prototype.createNested = function createNested(account) {
|
|||||||
* @see Wallet#setPassphrase
|
* @see Wallet#setPassphrase
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HTTPWallet.prototype.setPassphrase = function setPassphrase(old, new_) {
|
HTTPWallet.prototype.setPassphrase = function setPassphrase(passphrase, old) {
|
||||||
return this.client.setPassphrase(this.id, old, new_);
|
return this.client.setPassphrase(this.id, passphrase, old);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -48,7 +48,6 @@ function Account(wdb, options) {
|
|||||||
|
|
||||||
this.wdb = wdb;
|
this.wdb = wdb;
|
||||||
this.network = wdb.network;
|
this.network = wdb.network;
|
||||||
this.wallet = null;
|
|
||||||
|
|
||||||
this.receive = null;
|
this.receive = null;
|
||||||
this.change = null;
|
this.change = null;
|
||||||
@ -226,11 +225,11 @@ Account.MAX_LOOKAHEAD = 40;
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.init = async function init() {
|
Account.prototype.init = async function init(b) {
|
||||||
// Waiting for more keys.
|
// Waiting for more keys.
|
||||||
if (this.keys.length !== this.n - 1) {
|
if (this.keys.length !== this.n - 1) {
|
||||||
assert(!this.initialized);
|
assert(!this.initialized);
|
||||||
this.save();
|
this.save(b);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +239,7 @@ Account.prototype.init = async function init() {
|
|||||||
|
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
|
|
||||||
await this.initDepth();
|
await this.initDepth(b);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -341,7 +340,7 @@ Account.prototype.spliceKey = function spliceKey(key) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.addSharedKey = async function addSharedKey(key) {
|
Account.prototype.addSharedKey = async function addSharedKey(b, key) {
|
||||||
const result = this.pushKey(key);
|
const result = this.pushKey(key);
|
||||||
|
|
||||||
if (await this.hasDuplicate()) {
|
if (await this.hasDuplicate()) {
|
||||||
@ -350,7 +349,7 @@ Account.prototype.addSharedKey = async function addSharedKey(key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to initialize again.
|
// Try to initialize again.
|
||||||
await this.init();
|
await this.init(b);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@ -361,14 +360,14 @@ Account.prototype.addSharedKey = async function addSharedKey(key) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.hasDuplicate = function hasDuplicate() {
|
Account.prototype.hasDuplicate = async function hasDuplicate() {
|
||||||
if (this.keys.length !== this.n - 1)
|
if (this.keys.length !== this.n - 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const ring = this.deriveReceive(0);
|
const ring = this.deriveReceive(0);
|
||||||
const hash = ring.getScriptHash('hex');
|
const hash = ring.getScriptHash('hex');
|
||||||
|
|
||||||
return this.wallet.hasAddress(hash);
|
return this.wdb.hasPath(this.wid, hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -378,13 +377,13 @@ Account.prototype.hasDuplicate = function hasDuplicate() {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.removeSharedKey = function removeSharedKey(key) {
|
Account.prototype.removeSharedKey = function removeSharedKey(b, key) {
|
||||||
const result = this.spliceKey(key);
|
const result = this.spliceKey(key);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this.save();
|
this.save(b);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@ -422,28 +421,28 @@ Account.prototype.createNested = function createNested() {
|
|||||||
* @returns {Promise} - Returns {@link WalletKey}.
|
* @returns {Promise} - Returns {@link WalletKey}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.createKey = async function createKey(branch) {
|
Account.prototype.createKey = async function createKey(b, branch) {
|
||||||
let key, lookahead;
|
let key, lookahead;
|
||||||
|
|
||||||
switch (branch) {
|
switch (branch) {
|
||||||
case 0:
|
case 0:
|
||||||
key = this.deriveReceive(this.receiveDepth);
|
key = this.deriveReceive(this.receiveDepth);
|
||||||
lookahead = this.deriveReceive(this.receiveDepth + this.lookahead);
|
lookahead = this.deriveReceive(this.receiveDepth + this.lookahead);
|
||||||
await this.saveKey(lookahead);
|
await this.saveKey(b, lookahead);
|
||||||
this.receiveDepth++;
|
this.receiveDepth++;
|
||||||
this.receive = key;
|
this.receive = key;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
key = this.deriveChange(this.changeDepth);
|
key = this.deriveChange(this.changeDepth);
|
||||||
lookahead = this.deriveReceive(this.changeDepth + this.lookahead);
|
lookahead = this.deriveReceive(this.changeDepth + this.lookahead);
|
||||||
await this.saveKey(lookahead);
|
await this.saveKey(b, lookahead);
|
||||||
this.changeDepth++;
|
this.changeDepth++;
|
||||||
this.change = key;
|
this.change = key;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
key = this.deriveNested(this.nestedDepth);
|
key = this.deriveNested(this.nestedDepth);
|
||||||
lookahead = this.deriveNested(this.nestedDepth + this.lookahead);
|
lookahead = this.deriveNested(this.nestedDepth + this.lookahead);
|
||||||
await this.saveKey(lookahead);
|
await this.saveKey(b, lookahead);
|
||||||
this.nestedDepth++;
|
this.nestedDepth++;
|
||||||
this.nested = key;
|
this.nested = key;
|
||||||
break;
|
break;
|
||||||
@ -570,8 +569,8 @@ Account.prototype.deriveKey = function deriveKey(branch, index, master) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.save = function save() {
|
Account.prototype.save = function save(b) {
|
||||||
return this.wdb.saveAccount(this);
|
return this.wdb.saveAccount(b, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -580,8 +579,8 @@ Account.prototype.save = function save() {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.saveKey = function saveKey(ring) {
|
Account.prototype.saveKey = function saveKey(b, ring) {
|
||||||
return this.wdb.saveKey(this.wallet, ring);
|
return this.wdb.saveKey(b, this.wid, ring);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -590,8 +589,8 @@ Account.prototype.saveKey = function saveKey(ring) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.savePath = function savePath(path) {
|
Account.prototype.savePath = function savePath(b, path) {
|
||||||
return this.wdb.savePath(this.wallet, path);
|
return this.wdb.savePath(b, this.wid, path);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -599,29 +598,29 @@ Account.prototype.savePath = function savePath(path) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.initDepth = async function initDepth() {
|
Account.prototype.initDepth = async function initDepth(b) {
|
||||||
// Receive Address
|
// Receive Address
|
||||||
this.receive = this.deriveReceive(0);
|
this.receive = this.deriveReceive(0);
|
||||||
this.receiveDepth = 1;
|
this.receiveDepth = 1;
|
||||||
|
|
||||||
await this.saveKey(this.receive);
|
await this.saveKey(b, this.receive);
|
||||||
|
|
||||||
// Lookahead
|
// Lookahead
|
||||||
for (let i = 0; i < this.lookahead; i++) {
|
for (let i = 0; i < this.lookahead; i++) {
|
||||||
const key = this.deriveReceive(i + 1);
|
const key = this.deriveReceive(i + 1);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change Address
|
// Change Address
|
||||||
this.change = this.deriveChange(0);
|
this.change = this.deriveChange(0);
|
||||||
this.changeDepth = 1;
|
this.changeDepth = 1;
|
||||||
|
|
||||||
await this.saveKey(this.change);
|
await this.saveKey(b, this.change);
|
||||||
|
|
||||||
// Lookahead
|
// Lookahead
|
||||||
for (let i = 0; i < this.lookahead; i++) {
|
for (let i = 0; i < this.lookahead; i++) {
|
||||||
const key = this.deriveChange(i + 1);
|
const key = this.deriveChange(i + 1);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nested Address
|
// Nested Address
|
||||||
@ -629,16 +628,16 @@ Account.prototype.initDepth = async function initDepth() {
|
|||||||
this.nested = this.deriveNested(0);
|
this.nested = this.deriveNested(0);
|
||||||
this.nestedDepth = 1;
|
this.nestedDepth = 1;
|
||||||
|
|
||||||
await this.saveKey(this.nested);
|
await this.saveKey(b, this.nested);
|
||||||
|
|
||||||
// Lookahead
|
// Lookahead
|
||||||
for (let i = 0; i < this.lookahead; i++) {
|
for (let i = 0; i < this.lookahead; i++) {
|
||||||
const key = this.deriveNested(i + 1);
|
const key = this.deriveNested(i + 1);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save();
|
this.save(b);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -649,7 +648,7 @@ Account.prototype.initDepth = async function initDepth() {
|
|||||||
* @returns {Promise} - Returns {@link WalletKey}.
|
* @returns {Promise} - Returns {@link WalletKey}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.syncDepth = async function syncDepth(receive, change, nested) {
|
Account.prototype.syncDepth = async function syncDepth(b, receive, change, nested) {
|
||||||
let derived = false;
|
let derived = false;
|
||||||
let result = null;
|
let result = null;
|
||||||
|
|
||||||
@ -660,7 +659,7 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested)
|
|||||||
|
|
||||||
for (let i = depth; i < receive + this.lookahead; i++) {
|
for (let i = depth; i < receive + this.lookahead; i++) {
|
||||||
const key = this.deriveReceive(i);
|
const key = this.deriveReceive(i);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.receive = this.deriveReceive(receive - 1);
|
this.receive = this.deriveReceive(receive - 1);
|
||||||
@ -677,7 +676,7 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested)
|
|||||||
|
|
||||||
for (let i = depth; i < change + this.lookahead; i++) {
|
for (let i = depth; i < change + this.lookahead; i++) {
|
||||||
const key = this.deriveChange(i);
|
const key = this.deriveChange(i);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.change = this.deriveChange(change - 1);
|
this.change = this.deriveChange(change - 1);
|
||||||
@ -693,7 +692,7 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested)
|
|||||||
|
|
||||||
for (let i = depth; i < nested + this.lookahead; i++) {
|
for (let i = depth; i < nested + this.lookahead; i++) {
|
||||||
const key = this.deriveNested(i);
|
const key = this.deriveNested(i);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nested = this.deriveNested(nested - 1);
|
this.nested = this.deriveNested(nested - 1);
|
||||||
@ -704,7 +703,7 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (derived)
|
if (derived)
|
||||||
this.save();
|
this.save(b);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@ -715,13 +714,9 @@ Account.prototype.syncDepth = async function syncDepth(receive, change, nested)
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.setLookahead = async function setLookahead(lookahead) {
|
Account.prototype.setLookahead = async function setLookahead(b, lookahead) {
|
||||||
if (lookahead === this.lookahead) {
|
if (lookahead === this.lookahead)
|
||||||
this.wdb.logger.warning(
|
|
||||||
'Lookahead is not changing for: %s/%s.',
|
|
||||||
this.id, this.name);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (lookahead < this.lookahead) {
|
if (lookahead < this.lookahead) {
|
||||||
const diff = this.lookahead - lookahead;
|
const diff = this.lookahead - lookahead;
|
||||||
@ -739,7 +734,7 @@ Account.prototype.setLookahead = async function setLookahead(lookahead) {
|
|||||||
|
|
||||||
this.lookahead = lookahead;
|
this.lookahead = lookahead;
|
||||||
|
|
||||||
this.save();
|
this.save(b);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -750,7 +745,7 @@ Account.prototype.setLookahead = async function setLookahead(lookahead) {
|
|||||||
|
|
||||||
for (let i = depth; i < target; i++) {
|
for (let i = depth; i < target; i++) {
|
||||||
const key = this.deriveReceive(i);
|
const key = this.deriveReceive(i);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,7 +755,7 @@ Account.prototype.setLookahead = async function setLookahead(lookahead) {
|
|||||||
|
|
||||||
for (let i = depth; i < target; i++) {
|
for (let i = depth; i < target; i++) {
|
||||||
const key = this.deriveChange(i);
|
const key = this.deriveChange(i);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,12 +765,12 @@ Account.prototype.setLookahead = async function setLookahead(lookahead) {
|
|||||||
|
|
||||||
for (let i = depth; i < target; i++) {
|
for (let i = depth; i < target; i++) {
|
||||||
const key = this.deriveNested(i);
|
const key = this.deriveNested(i);
|
||||||
await this.saveKey(key);
|
await this.saveKey(b, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lookahead = lookahead;
|
this.lookahead = lookahead;
|
||||||
this.save();
|
this.save(b);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -305,12 +305,12 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
|||||||
// Change passphrase
|
// Change passphrase
|
||||||
this.post('/:id/passphrase', async (req, res) => {
|
this.post('/:id/passphrase', async (req, res) => {
|
||||||
const valid = req.valid();
|
const valid = req.valid();
|
||||||
|
const passphrase = valid.str('passphrase');
|
||||||
const old = valid.str('old');
|
const old = valid.str('old');
|
||||||
const new_ = valid.str('new');
|
|
||||||
|
|
||||||
enforce(old || new_, 'Passphrase is required.');
|
enforce(old || new_, 'Passphrase is required.');
|
||||||
|
|
||||||
await req.wallet.setPassphrase(old, new_);
|
await req.wallet.setPassphrase(passphrase, old);
|
||||||
|
|
||||||
res.send(200, { success: true });
|
res.send(200, { success: true });
|
||||||
});
|
});
|
||||||
@ -416,7 +416,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
|||||||
|
|
||||||
const details = await req.wallet.getDetails(tx.hash('hex'));
|
const details = await req.wallet.getDetails(tx.hash('hex'));
|
||||||
|
|
||||||
res.send(200, details.toJSON());
|
res.send(200, details.toJSON(this.network));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create TX
|
// Create TX
|
||||||
@ -790,7 +790,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
|
|||||||
|
|
||||||
const details = await req.wallet.toDetails(tx);
|
const details = await req.wallet.toDetails(tx);
|
||||||
|
|
||||||
res.send(200, details.toJSON());
|
res.send(200, details.toJSON(this.network));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Resend
|
// Resend
|
||||||
@ -813,38 +813,38 @@ HTTPServer.prototype.initSockets = function initSockets() {
|
|||||||
this.handleSocket(socket);
|
this.handleSocket(socket);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('tx', (id, tx, details) => {
|
this.walletdb.on('tx', (w, tx, details) => {
|
||||||
const json = details.toJSON();
|
const json = details.toJSON(this.network);
|
||||||
this.to(`w:${id}`, 'wallet tx', json);
|
this.to(`w:${w.id}`, 'wallet tx', json);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('confirmed', (id, tx, details) => {
|
this.walletdb.on('confirmed', (w, tx, details) => {
|
||||||
const json = details.toJSON();
|
const json = details.toJSON(this.network);
|
||||||
this.to(`w:${id}`, 'wallet confirmed', json);
|
this.to(`w:${w.id}`, 'wallet confirmed', json);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('unconfirmed', (id, tx, details) => {
|
this.walletdb.on('unconfirmed', (w, tx, details) => {
|
||||||
const json = details.toJSON();
|
const json = details.toJSON(this.network);
|
||||||
this.to(`w:${id}`, 'wallet unconfirmed', json);
|
this.to(`w:${w.id}`, 'wallet unconfirmed', json);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('conflict', (id, tx, details) => {
|
this.walletdb.on('conflict', (w, tx, details) => {
|
||||||
const json = details.toJSON();
|
const json = details.toJSON(this.network);
|
||||||
this.to(`w:${id}`, 'wallet conflict', json);
|
this.to(`w:${w.id}`, 'wallet conflict', json);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('balance', (id, balance) => {
|
this.walletdb.on('balance', (w, balance) => {
|
||||||
const json = balance.toJSON();
|
const json = balance.toJSON();
|
||||||
this.to(`w:${id}`, 'wallet balance', json);
|
this.to(`w:${w.id}`, 'wallet balance', json);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('address', (id, receive) => {
|
this.walletdb.on('address', (w, receive) => {
|
||||||
const json = [];
|
const json = [];
|
||||||
|
|
||||||
for (const addr of receive)
|
for (const addr of receive)
|
||||||
json.push(addr.toJSON());
|
json.push(addr.toJSON());
|
||||||
|
|
||||||
this.to(`w:${id}`, 'wallet address', json);
|
this.to(`w:${w.id}`, 'wallet address', json);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -95,13 +95,8 @@ layouts.walletdb = {
|
|||||||
|
|
||||||
layouts.txdb = {
|
layouts.txdb = {
|
||||||
binary: false,
|
binary: false,
|
||||||
prefix: function prefix(wid, key) {
|
prefix: function prefix(wid) {
|
||||||
assert(typeof key === 'string');
|
return 't' + pad32(wid);
|
||||||
return 't' + pad32(wid) + key;
|
|
||||||
},
|
|
||||||
pre: function pre(key) {
|
|
||||||
assert(typeof key === 'string');
|
|
||||||
return parseInt(key.slice(1, 11), 10);
|
|
||||||
},
|
},
|
||||||
R: 'R',
|
R: 'R',
|
||||||
hi: function hi(ch, hash, index) {
|
hi: function hi(ch, hash, index) {
|
||||||
@ -110,8 +105,7 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
hii: function hii(key) {
|
hii: function hii(key) {
|
||||||
assert(typeof key === 'string');
|
assert(typeof key === 'string');
|
||||||
key = key.slice(12);
|
return [key.slice(1, 65), parseInt(key.slice(65), 10)];
|
||||||
return [key.slice(0, 64), parseInt(key.slice(64), 10)];
|
|
||||||
},
|
},
|
||||||
ih: function ih(ch, index, hash) {
|
ih: function ih(ch, index, hash) {
|
||||||
assert(typeof hash === 'string');
|
assert(typeof hash === 'string');
|
||||||
@ -119,8 +113,7 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
ihh: function ihh(key) {
|
ihh: function ihh(key) {
|
||||||
assert(typeof key === 'string');
|
assert(typeof key === 'string');
|
||||||
key = key.slice(12);
|
return [parseInt(key.slice(1, 11), 10), key.slice(11)];
|
||||||
return [parseInt(key.slice(0, 10), 10), key.slice(10)];
|
|
||||||
},
|
},
|
||||||
iih: function iih(ch, index, num, hash) {
|
iih: function iih(ch, index, num, hash) {
|
||||||
assert(typeof hash === 'string');
|
assert(typeof hash === 'string');
|
||||||
@ -128,11 +121,10 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
iihh: function iihh(key) {
|
iihh: function iihh(key) {
|
||||||
assert(typeof key === 'string');
|
assert(typeof key === 'string');
|
||||||
key = key.slice(12);
|
|
||||||
return [
|
return [
|
||||||
parseInt(key.slice(0, 10), 10),
|
parseInt(key.slice(1, 11), 10),
|
||||||
parseInt(key.slice(10, 20), 10),
|
parseInt(key.slice(11, 21), 10),
|
||||||
key.slice(20)
|
key.slice(21)
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
ihi: function ihi(ch, index, hash, num) {
|
ihi: function ihi(ch, index, hash, num) {
|
||||||
@ -141,11 +133,10 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
ihii: function ihii(key) {
|
ihii: function ihii(key) {
|
||||||
assert(typeof key === 'string');
|
assert(typeof key === 'string');
|
||||||
key = key.slice(12);
|
|
||||||
return [
|
return [
|
||||||
parseInt(key.slice(0, 10), 10),
|
parseInt(key.slice(1, 11), 10),
|
||||||
key.slice(10, 74),
|
key.slice(11, 75),
|
||||||
parseInt(key.slice(74), 10)
|
parseInt(key.slice(75), 10)
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
ha: function ha(ch, hash) {
|
ha: function ha(ch, hash) {
|
||||||
@ -154,8 +145,7 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
haa: function haa(key) {
|
haa: function haa(key) {
|
||||||
assert(typeof key === 'string');
|
assert(typeof key === 'string');
|
||||||
key = key.slice(12);
|
return key.slice(1);
|
||||||
return key;
|
|
||||||
},
|
},
|
||||||
t: function t(hash) {
|
t: function t(hash) {
|
||||||
return this.ha('t', hash);
|
return this.ha('t', hash);
|
||||||
@ -235,15 +225,11 @@ layouts.txdb = {
|
|||||||
Cc: function Cc(key) {
|
Cc: function Cc(key) {
|
||||||
return this.ihii(key);
|
return this.ihii(key);
|
||||||
},
|
},
|
||||||
r: function r(hash) {
|
|
||||||
return this.ha('r', hash);
|
|
||||||
},
|
|
||||||
b: function b(height) {
|
b: function b(height) {
|
||||||
return 'b' + pad32(height);
|
return 'b' + pad32(height);
|
||||||
},
|
},
|
||||||
bb: function bb(key) {
|
bb: function bb(key) {
|
||||||
assert(typeof key === 'string');
|
assert(typeof key === 'string');
|
||||||
key = key.slice(12);
|
return parseInt(key.slice(1), 10);
|
||||||
return parseInt(key.slice(0), 10);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -199,20 +199,13 @@ layouts.walletdb = {
|
|||||||
|
|
||||||
layouts.txdb = {
|
layouts.txdb = {
|
||||||
binary: true,
|
binary: true,
|
||||||
prefix: function prefix(wid, key) {
|
prefix: function prefix(wid) {
|
||||||
assert(typeof wid === 'number');
|
assert(typeof wid === 'number');
|
||||||
assert(Buffer.isBuffer(key));
|
const out = Buffer.allocUnsafe(5);
|
||||||
const out = Buffer.allocUnsafe(5 + key.length);
|
|
||||||
out[0] = 0x74;
|
out[0] = 0x74;
|
||||||
out.writeUInt32BE(wid, 1);
|
out.writeUInt32BE(wid, 1);
|
||||||
key.copy(out, 5);
|
|
||||||
return out;
|
return out;
|
||||||
},
|
},
|
||||||
pre: function pre(key) {
|
|
||||||
assert(Buffer.isBuffer(key));
|
|
||||||
assert(key.length >= 5);
|
|
||||||
return key.readUInt32BE(1, true);
|
|
||||||
},
|
|
||||||
R: Buffer.from([0x52]),
|
R: Buffer.from([0x52]),
|
||||||
hi: function hi(ch, hash, index) {
|
hi: function hi(ch, hash, index) {
|
||||||
assert(typeof hash === 'string');
|
assert(typeof hash === 'string');
|
||||||
@ -225,9 +218,8 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
hii: function hii(key) {
|
hii: function hii(key) {
|
||||||
assert(Buffer.isBuffer(key));
|
assert(Buffer.isBuffer(key));
|
||||||
assert(key.length - 5 === 37);
|
assert(key.length === 37);
|
||||||
key = key.slice(6);
|
return [key.toString('hex', 1, 33), key.readUInt32BE(33, true)];
|
||||||
return [key.toString('hex', 0, 32), key.readUInt32BE(32, true)];
|
|
||||||
},
|
},
|
||||||
ih: function ih(ch, index, hash) {
|
ih: function ih(ch, index, hash) {
|
||||||
assert(typeof index === 'number');
|
assert(typeof index === 'number');
|
||||||
@ -240,9 +232,8 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
ihh: function ihh(key) {
|
ihh: function ihh(key) {
|
||||||
assert(Buffer.isBuffer(key));
|
assert(Buffer.isBuffer(key));
|
||||||
assert(key.length - 5 === 37);
|
assert(key.length === 37);
|
||||||
key = key.slice(6);
|
return [key.readUInt32BE(1, true), key.toString('hex', 5, 37)];
|
||||||
return [key.readUInt32BE(0, true), key.toString('hex', 4, 36)];
|
|
||||||
},
|
},
|
||||||
iih: function iih(ch, index, num, hash) {
|
iih: function iih(ch, index, num, hash) {
|
||||||
assert(typeof index === 'number');
|
assert(typeof index === 'number');
|
||||||
@ -257,12 +248,11 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
iihh: function iihh(key) {
|
iihh: function iihh(key) {
|
||||||
assert(Buffer.isBuffer(key));
|
assert(Buffer.isBuffer(key));
|
||||||
assert(key.length - 5 === 41);
|
assert(key.length === 41);
|
||||||
key = key.slice(6);
|
|
||||||
return [
|
return [
|
||||||
key.readUInt32BE(0, true),
|
key.readUInt32BE(1, true),
|
||||||
key.readUInt32BE(4, true),
|
key.readUInt32BE(5, true),
|
||||||
key.toString('hex', 8, 40)
|
key.toString('hex', 9, 41)
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
ihi: function ihi(ch, index, hash, num) {
|
ihi: function ihi(ch, index, hash, num) {
|
||||||
@ -278,12 +268,11 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
ihii: function ihii(key) {
|
ihii: function ihii(key) {
|
||||||
assert(Buffer.isBuffer(key));
|
assert(Buffer.isBuffer(key));
|
||||||
assert(key.length - 5 === 41);
|
assert(key.length === 41);
|
||||||
key = key.slice(6);
|
|
||||||
return [
|
return [
|
||||||
key.readUInt32BE(0, true),
|
key.readUInt32BE(1, true),
|
||||||
key.toString('hex', 4, 36),
|
key.toString('hex', 5, 37),
|
||||||
key.readUInt32BE(36, true)
|
key.readUInt32BE(37, true)
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
ha: function ha(ch, hash) {
|
ha: function ha(ch, hash) {
|
||||||
@ -295,9 +284,8 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
haa: function haa(key) {
|
haa: function haa(key) {
|
||||||
assert(Buffer.isBuffer(key));
|
assert(Buffer.isBuffer(key));
|
||||||
assert(key.length - 5 === 33);
|
assert(key.length === 33);
|
||||||
key = key.slice(6);
|
return key.toString('hex', 1, 33);
|
||||||
return key.toString('hex', 0);
|
|
||||||
},
|
},
|
||||||
t: function t(hash) {
|
t: function t(hash) {
|
||||||
return this.ha(0x74, hash);
|
return this.ha(0x74, hash);
|
||||||
@ -371,9 +359,6 @@ layouts.txdb = {
|
|||||||
Cc: function Cc(key) {
|
Cc: function Cc(key) {
|
||||||
return this.ihii(key);
|
return this.ihii(key);
|
||||||
},
|
},
|
||||||
r: function r(hash) {
|
|
||||||
return this.ha(0x72, hash);
|
|
||||||
},
|
|
||||||
b: function b(height) {
|
b: function b(height) {
|
||||||
assert(typeof height === 'number');
|
assert(typeof height === 'number');
|
||||||
const key = Buffer.allocUnsafe(5);
|
const key = Buffer.allocUnsafe(5);
|
||||||
@ -383,8 +368,7 @@ layouts.txdb = {
|
|||||||
},
|
},
|
||||||
bb: function bb(key) {
|
bb: function bb(key) {
|
||||||
assert(Buffer.isBuffer(key));
|
assert(Buffer.isBuffer(key));
|
||||||
assert(key.length - 5 === 5);
|
assert(key.length === 5);
|
||||||
key = key.slice(6);
|
return key.readUInt32BE(1, true);
|
||||||
return key.readUInt32BE(0, true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -316,7 +316,7 @@ RPC.prototype.encryptWallet = async function encryptWallet(args, help) {
|
|||||||
throw new RPCError(errs.MISC_ERROR, 'encryptwallet "passphrase"');
|
throw new RPCError(errs.MISC_ERROR, 'encryptwallet "passphrase"');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await wallet.setPassphrase(passphrase);
|
await wallet.encrypt(passphrase);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new RPCError(errs.WALLET_ENCRYPTION_FAILED, 'Encryption failed.');
|
throw new RPCError(errs.WALLET_ENCRYPTION_FAILED, 'Encryption failed.');
|
||||||
}
|
}
|
||||||
@ -1432,15 +1432,15 @@ RPC.prototype.walletPassphraseChange = async function walletPassphraseChange(arg
|
|||||||
|
|
||||||
const valid = new Validator([args]);
|
const valid = new Validator([args]);
|
||||||
const old = valid.str(0, '');
|
const old = valid.str(0, '');
|
||||||
const new_ = valid.str(1, '');
|
const passphrase = valid.str(1, '');
|
||||||
|
|
||||||
if (!wallet.master.encrypted)
|
if (!wallet.master.encrypted)
|
||||||
throw new RPCError(errs.WALLET_WRONG_ENC_STATE, 'Wallet is not encrypted.');
|
throw new RPCError(errs.WALLET_WRONG_ENC_STATE, 'Wallet is not encrypted.');
|
||||||
|
|
||||||
if (old.length < 1 || new_.length < 1)
|
if (old.length < 1 || passphrase.length < 1)
|
||||||
throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter');
|
throw new RPCError(errs.INVALID_PARAMETER, 'Invalid parameter');
|
||||||
|
|
||||||
await wallet.setPassphrase(old, new_);
|
await wallet.setPassphrase(passphrase, old);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,6 @@ const HD = require('../hd/hd');
|
|||||||
const Output = require('../primitives/output');
|
const Output = require('../primitives/output');
|
||||||
const Account = require('./account');
|
const Account = require('./account');
|
||||||
const MasterKey = require('./masterkey');
|
const MasterKey = require('./masterkey');
|
||||||
const LRU = require('../utils/lru');
|
|
||||||
const policy = require('../protocol/policy');
|
const policy = require('../protocol/policy');
|
||||||
const consensus = require('../protocol/consensus');
|
const consensus = require('../protocol/consensus');
|
||||||
const Mnemonic = HD.Mnemonic;
|
const Mnemonic = HD.Mnemonic;
|
||||||
@ -70,15 +69,11 @@ function Wallet(wdb, options) {
|
|||||||
assert(wdb, 'WDB required.');
|
assert(wdb, 'WDB required.');
|
||||||
|
|
||||||
this.wdb = wdb;
|
this.wdb = wdb;
|
||||||
|
this.db = wdb.db;
|
||||||
this.network = wdb.network;
|
this.network = wdb.network;
|
||||||
this.logger = wdb.logger;
|
this.logger = wdb.logger;
|
||||||
this.readLock = new MappedLock();
|
|
||||||
this.writeLock = new Lock();
|
this.writeLock = new Lock();
|
||||||
this.fundLock = new Lock();
|
this.fundLock = new Lock();
|
||||||
this.indexCache = new LRU(1000);
|
|
||||||
this.accountCache = new LRU(1000);
|
|
||||||
this.pathCache = new LRU(1000);
|
|
||||||
this.current = null;
|
|
||||||
|
|
||||||
this.wid = 0;
|
this.wid = 0;
|
||||||
this.id = null;
|
this.id = null;
|
||||||
@ -89,7 +84,7 @@ function Wallet(wdb, options) {
|
|||||||
this.tokenDepth = 0;
|
this.tokenDepth = 0;
|
||||||
this.master = new MasterKey();
|
this.master = new MasterKey();
|
||||||
|
|
||||||
this.txdb = new TXDB(this);
|
this.txdb = new TXDB(this.wdb);
|
||||||
this.account = null;
|
this.account = null;
|
||||||
|
|
||||||
if (options)
|
if (options)
|
||||||
@ -207,7 +202,7 @@ Wallet.prototype.init = async function init(options) {
|
|||||||
|
|
||||||
this.logger.info('Wallet initialized (%s).', this.id);
|
this.logger.info('Wallet initialized (%s).', this.id);
|
||||||
|
|
||||||
await this.txdb.open();
|
await this.txdb.open(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -227,7 +222,7 @@ Wallet.prototype.open = async function open() {
|
|||||||
|
|
||||||
this.logger.info('Wallet opened (%s).', this.id);
|
this.logger.info('Wallet opened (%s).', this.id);
|
||||||
|
|
||||||
await this.txdb.open();
|
await this.txdb.open(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -239,9 +234,7 @@ Wallet.prototype.destroy = async function destroy() {
|
|||||||
const unlock1 = await this.writeLock.lock();
|
const unlock1 = await this.writeLock.lock();
|
||||||
const unlock2 = await this.fundLock.lock();
|
const unlock2 = await this.fundLock.lock();
|
||||||
try {
|
try {
|
||||||
this.wdb.unregister(this);
|
|
||||||
await this.master.destroy();
|
await this.master.destroy();
|
||||||
this.readLock.destroy();
|
|
||||||
this.writeLock.destroy();
|
this.writeLock.destroy();
|
||||||
this.fundLock.destroy();
|
this.fundLock.destroy();
|
||||||
} finally {
|
} finally {
|
||||||
@ -276,30 +269,14 @@ Wallet.prototype.addSharedKey = async function addSharedKey(acct, key) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._addSharedKey = async function _addSharedKey(acct, key) {
|
Wallet.prototype._addSharedKey = async function _addSharedKey(acct, key) {
|
||||||
if (!key) {
|
|
||||||
key = acct;
|
|
||||||
acct = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acct == null)
|
|
||||||
acct = 0;
|
|
||||||
|
|
||||||
const account = await this.getAccount(acct);
|
const account = await this.getAccount(acct);
|
||||||
|
|
||||||
if (!account)
|
if (!account)
|
||||||
throw new Error('Account not found.');
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
this.start();
|
const b = this.db.batch();
|
||||||
|
const result = await account.addSharedKey(b, key);
|
||||||
let result;
|
await b.write();
|
||||||
try {
|
|
||||||
result = await account.addSharedKey(key);
|
|
||||||
} catch (e) {
|
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@ -329,47 +306,30 @@ Wallet.prototype.removeSharedKey = async function removeSharedKey(acct, key) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._removeSharedKey = async function _removeSharedKey(acct, key) {
|
Wallet.prototype._removeSharedKey = async function _removeSharedKey(acct, key) {
|
||||||
if (!key) {
|
|
||||||
key = acct;
|
|
||||||
acct = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acct == null)
|
|
||||||
acct = 0;
|
|
||||||
|
|
||||||
const account = await this.getAccount(acct);
|
const account = await this.getAccount(acct);
|
||||||
|
|
||||||
if (!account)
|
if (!account)
|
||||||
throw new Error('Account not found.');
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
this.start();
|
const b = this.db.batch();
|
||||||
|
const result = await account.removeSharedKey(b, key);
|
||||||
let result;
|
await b.write();
|
||||||
try {
|
|
||||||
result = await account.removeSharedKey(key);
|
|
||||||
} catch (e) {
|
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change or set master key's passphrase.
|
* Change or set master key's passphrase.
|
||||||
* @param {(String|Buffer)?} old
|
* @param {String|Buffer} passphrase
|
||||||
* @param {String|Buffer} new_
|
* @param {String|Buffer} old
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.setPassphrase = async function setPassphrase(old, new_) {
|
Wallet.prototype.setPassphrase = async function setPassphrase(passphrase, old) {
|
||||||
if (old)
|
if (old != null)
|
||||||
await this.decrypt(old);
|
await this.decrypt(old);
|
||||||
|
|
||||||
if (new_)
|
await this.encrypt(passphrase);
|
||||||
await this.encrypt(new_);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,22 +356,17 @@ Wallet.prototype.encrypt = async function encrypt(passphrase) {
|
|||||||
|
|
||||||
Wallet.prototype._encrypt = async function _encrypt(passphrase) {
|
Wallet.prototype._encrypt = async function _encrypt(passphrase) {
|
||||||
const key = await this.master.encrypt(passphrase, true);
|
const key = await this.master.encrypt(passphrase, true);
|
||||||
|
const b = this.db.batch();
|
||||||
this.start();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.wdb.encryptKeys(this, key);
|
await this.wdb.encryptKeys(b, this.wid, key);
|
||||||
} catch (e) {
|
} finally {
|
||||||
cleanse(key);
|
cleanse(key);
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanse(key);
|
this.save(b);
|
||||||
|
|
||||||
this.save();
|
await b.write();
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -438,22 +393,17 @@ Wallet.prototype.decrypt = async function decrypt(passphrase) {
|
|||||||
|
|
||||||
Wallet.prototype._decrypt = async function _decrypt(passphrase) {
|
Wallet.prototype._decrypt = async function _decrypt(passphrase) {
|
||||||
const key = await this.master.decrypt(passphrase, true);
|
const key = await this.master.decrypt(passphrase, true);
|
||||||
|
const b = this.db.batch();
|
||||||
this.start();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.wdb.decryptKeys(this, key);
|
await this.wdb.decryptKeys(b, this.wid, key);
|
||||||
} catch (e) {
|
} finally {
|
||||||
cleanse(key);
|
cleanse(key);
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanse(key);
|
this.save(b);
|
||||||
|
|
||||||
this.save();
|
await b.write();
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -479,15 +429,16 @@ Wallet.prototype.retoken = async function retoken(passphrase) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._retoken = async function _retoken(passphrase) {
|
Wallet.prototype._retoken = async function _retoken(passphrase) {
|
||||||
await this.unlock(passphrase);
|
if (passphrase)
|
||||||
|
await this.unlock(passphrase);
|
||||||
|
|
||||||
this.tokenDepth++;
|
this.tokenDepth += 1;
|
||||||
this.token = this.getToken(this.tokenDepth);
|
this.token = this.getToken(this.tokenDepth);
|
||||||
|
|
||||||
this.start();
|
const b = this.db.batch();
|
||||||
this.save();
|
this.save(b);
|
||||||
|
|
||||||
await this.commit();
|
await b.write();
|
||||||
|
|
||||||
return this.token;
|
return this.token;
|
||||||
};
|
};
|
||||||
@ -546,24 +497,11 @@ Wallet.prototype._renameAccount = async function _renameAccount(acct, name) {
|
|||||||
if (await this.hasAccount(name))
|
if (await this.hasAccount(name))
|
||||||
throw new Error('Account name not available.');
|
throw new Error('Account name not available.');
|
||||||
|
|
||||||
const old = account.name;
|
const b = this.db.batch();
|
||||||
|
|
||||||
this.start();
|
this.wdb.renameAccount(b, account, name);
|
||||||
|
|
||||||
this.wdb.renameAccount(account, name);
|
await b.write();
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
|
|
||||||
this.indexCache.remove(old);
|
|
||||||
|
|
||||||
const paths = this.pathCache.values();
|
|
||||||
|
|
||||||
for (const path of paths) {
|
|
||||||
if (path.account !== account.accountIndex)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
path.name = name;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -631,7 +569,8 @@ Wallet.prototype.getID = function getID() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.getToken = function getToken(nonce) {
|
Wallet.prototype.getToken = function getToken(nonce) {
|
||||||
assert(this.master.key, 'Cannot derive token.');
|
if (!this.master.key)
|
||||||
|
throw new Error('Cannot derive token.');
|
||||||
|
|
||||||
const key = this.master.key.derive(44, true);
|
const key = this.master.key.derive(44, true);
|
||||||
|
|
||||||
@ -706,17 +645,11 @@ Wallet.prototype._createAccount = async function _createAccount(options, passphr
|
|||||||
keys: options.keys
|
keys: options.keys
|
||||||
};
|
};
|
||||||
|
|
||||||
this.start();
|
const b = this.db.batch();
|
||||||
|
|
||||||
let account;
|
const account = Account.fromOptions(this.wdb, opt);
|
||||||
try {
|
|
||||||
account = Account.fromOptions(this.wdb, opt);
|
await account.init(b);
|
||||||
account.wallet = this;
|
|
||||||
await account.init();
|
|
||||||
} catch (e) {
|
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.info('Created account %s/%s/%d.',
|
this.logger.info('Created account %s/%s/%d.',
|
||||||
account.id,
|
account.id,
|
||||||
@ -724,9 +657,9 @@ Wallet.prototype._createAccount = async function _createAccount(options, passphr
|
|||||||
account.accountIndex);
|
account.accountIndex);
|
||||||
|
|
||||||
this.accountDepth++;
|
this.accountDepth++;
|
||||||
this.save();
|
this.save(b);
|
||||||
|
|
||||||
await this.commit();
|
await b.write();
|
||||||
|
|
||||||
return account;
|
return account;
|
||||||
};
|
};
|
||||||
@ -775,7 +708,11 @@ Wallet.prototype.getAddressHashes = function getAddressHashes(acct) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.getAccountHashes = async function getAccountHashes(acct) {
|
Wallet.prototype.getAccountHashes = async function getAccountHashes(acct) {
|
||||||
const index = await this.ensureIndex(acct, true);
|
const index = await this.getAccountIndex(acct);
|
||||||
|
|
||||||
|
if (index === -1)
|
||||||
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
return await this.wdb.getAccountHashes(this.wid, index);
|
return await this.wdb.getAccountHashes(this.wid, index);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -796,69 +733,51 @@ Wallet.prototype.getAccount = async function getAccount(acct) {
|
|||||||
if (index === -1)
|
if (index === -1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
const unlock = await this.readLock.lock(index);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await this._getAccount(index);
|
|
||||||
} finally {
|
|
||||||
unlock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an account from the database without a lock.
|
|
||||||
* @param {Number} index
|
|
||||||
* @returns {Promise} - Returns {@link Account}.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Wallet.prototype._getAccount = async function _getAccount(index) {
|
|
||||||
const cache = this.accountCache.get(index);
|
|
||||||
|
|
||||||
if (cache)
|
|
||||||
return cache;
|
|
||||||
|
|
||||||
const account = await this.wdb.getAccount(this.wid, index);
|
const account = await this.wdb.getAccount(this.wid, index);
|
||||||
|
|
||||||
if (!account)
|
if (!account)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
account.wallet = this;
|
|
||||||
account.wid = this.wid;
|
account.wid = this.wid;
|
||||||
account.id = this.id;
|
account.id = this.id;
|
||||||
account.watchOnly = this.watchOnly;
|
account.watchOnly = this.watchOnly;
|
||||||
|
|
||||||
await account.open();
|
await account.open();
|
||||||
|
|
||||||
this.accountCache.set(index, account);
|
|
||||||
|
|
||||||
return account;
|
return account;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup the corresponding account name's index.
|
* Lookup the corresponding account name's index.
|
||||||
* @param {WalletID} wid
|
* @param {String|Number} acct - Account name/index.
|
||||||
* @param {String|Number} name - Account name/index.
|
|
||||||
* @returns {Promise} - Returns Number.
|
* @returns {Promise} - Returns Number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.getAccountIndex = async function getAccountIndex(name) {
|
Wallet.prototype.getAccountIndex = function getAccountIndex(acct) {
|
||||||
if (name == null)
|
if (acct == null)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (typeof name === 'number')
|
if (typeof acct === 'number')
|
||||||
return name;
|
return acct;
|
||||||
|
|
||||||
const cache = this.indexCache.get(name);
|
return this.wdb.getAccountIndex(this.wid, acct);
|
||||||
|
};
|
||||||
|
|
||||||
if (cache != null)
|
/**
|
||||||
return cache;
|
* Lookup the corresponding account name's index.
|
||||||
|
* @param {String|Number} acct - Account name/index.
|
||||||
|
* @returns {Promise} - Returns Number.
|
||||||
|
* @throws on non-existent account
|
||||||
|
*/
|
||||||
|
|
||||||
const index = await this.wdb.getAccountIndex(this.wid, name);
|
Wallet.prototype.ensureIndex = async function ensureIndex(acct) {
|
||||||
|
if (acct == null || acct === -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const index = await this.getAccountIndex(acct);
|
||||||
|
|
||||||
if (index === -1)
|
if (index === -1)
|
||||||
return -1;
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
this.indexCache.set(name, index);
|
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
};
|
};
|
||||||
@ -874,11 +793,6 @@ Wallet.prototype.getAccountName = async function getAccountName(index) {
|
|||||||
if (typeof index === 'string')
|
if (typeof index === 'string')
|
||||||
return index;
|
return index;
|
||||||
|
|
||||||
const account = this.accountCache.get(index);
|
|
||||||
|
|
||||||
if (account)
|
|
||||||
return account.name;
|
|
||||||
|
|
||||||
return await this.wdb.getAccountName(this.wid, index);
|
return await this.wdb.getAccountName(this.wid, index);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -894,9 +808,6 @@ Wallet.prototype.hasAccount = async function hasAccount(acct) {
|
|||||||
if (index === -1)
|
if (index === -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (this.accountCache.has(index))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return await this.db.hasAccount(this.wid, index);
|
return await this.db.hasAccount(this.wid, index);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -906,7 +817,7 @@ Wallet.prototype.hasAccount = async function hasAccount(acct) {
|
|||||||
* @returns {Promise} - Returns {@link WalletKey}.
|
* @returns {Promise} - Returns {@link WalletKey}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.createReceive = function createReceive(acct) {
|
Wallet.prototype.createReceive = function createReceive(acct = 0) {
|
||||||
return this.createKey(acct, 0);
|
return this.createKey(acct, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -916,7 +827,7 @@ Wallet.prototype.createReceive = function createReceive(acct) {
|
|||||||
* @returns {Promise} - Returns {@link WalletKey}.
|
* @returns {Promise} - Returns {@link WalletKey}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.createChange = function createChange(acct) {
|
Wallet.prototype.createChange = function createChange(acct = 0) {
|
||||||
return this.createKey(acct, 1);
|
return this.createKey(acct, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -926,7 +837,7 @@ Wallet.prototype.createChange = function createChange(acct) {
|
|||||||
* @returns {Promise} - Returns {@link WalletKey}.
|
* @returns {Promise} - Returns {@link WalletKey}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.createNested = function createNested(acct) {
|
Wallet.prototype.createNested = function createNested(acct = 0) {
|
||||||
return this.createKey(acct, 2);
|
return this.createKey(acct, 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -955,32 +866,16 @@ Wallet.prototype.createKey = async function createKey(acct, branch) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._createKey = async function _createKey(acct, branch) {
|
Wallet.prototype._createKey = async function _createKey(acct, branch) {
|
||||||
if (branch == null) {
|
|
||||||
branch = acct;
|
|
||||||
acct = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acct == null)
|
|
||||||
acct = 0;
|
|
||||||
|
|
||||||
const account = await this.getAccount(acct);
|
const account = await this.getAccount(acct);
|
||||||
|
|
||||||
if (!account)
|
if (!account)
|
||||||
throw new Error('Account not found.');
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
this.start();
|
const b = this.db.batch();
|
||||||
|
const key = await account.createKey(b, branch);
|
||||||
|
await b.write();
|
||||||
|
|
||||||
let result;
|
return key;
|
||||||
try {
|
|
||||||
result = await account.createKey(branch);
|
|
||||||
} catch (e) {
|
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -989,44 +884,8 @@ Wallet.prototype._createKey = async function _createKey(acct, branch) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.save = function save() {
|
Wallet.prototype.save = function save(b) {
|
||||||
return this.wdb.save(this);
|
return this.wdb.save(b, this);
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start batch.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
Wallet.prototype.start = function start() {
|
|
||||||
return this.wdb.start(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drop batch.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
Wallet.prototype.drop = function drop() {
|
|
||||||
return this.wdb.drop(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear batch.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
Wallet.prototype.clear = function clear() {
|
|
||||||
return this.wdb.clear(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save batch.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Wallet.prototype.commit = function commit() {
|
|
||||||
return this.wdb.commit(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1048,18 +907,8 @@ Wallet.prototype.hasAddress = async function hasAddress(address) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.getPath = async function getPath(address) {
|
Wallet.prototype.getPath = async function getPath(address) {
|
||||||
const path = await this.readPath(address);
|
const hash = Address.getHash(address, 'hex');
|
||||||
|
return this.wdb.getPath(this.wid, this.id, hash);
|
||||||
if (!path)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
path.name = await this.getAccountName(path.account);
|
|
||||||
|
|
||||||
assert(path.name);
|
|
||||||
|
|
||||||
this.pathCache.set(path.hash, path);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1071,19 +920,7 @@ Wallet.prototype.getPath = async function getPath(address) {
|
|||||||
|
|
||||||
Wallet.prototype.readPath = async function readPath(address) {
|
Wallet.prototype.readPath = async function readPath(address) {
|
||||||
const hash = Address.getHash(address, 'hex');
|
const hash = Address.getHash(address, 'hex');
|
||||||
const cache = this.pathCache.get(hash);
|
return this.wdb.readPath(this.wid, this.id, hash);
|
||||||
|
|
||||||
if (cache)
|
|
||||||
return cache;
|
|
||||||
|
|
||||||
const path = await this.wdb.getPath(this.wid, hash);
|
|
||||||
|
|
||||||
if (!path)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
path.id = this.id;
|
|
||||||
|
|
||||||
return path;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1094,10 +931,6 @@ Wallet.prototype.readPath = async function readPath(address) {
|
|||||||
|
|
||||||
Wallet.prototype.hasPath = async function hasPath(address) {
|
Wallet.prototype.hasPath = async function hasPath(address) {
|
||||||
const hash = Address.getHash(address, 'hex');
|
const hash = Address.getHash(address, 'hex');
|
||||||
|
|
||||||
if (this.pathCache.has(hash))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return await this.wdb.hasPath(this.wid, hash);
|
return await this.wdb.hasPath(this.wid, hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1120,8 +953,6 @@ Wallet.prototype.getPaths = async function getPaths(acct) {
|
|||||||
|
|
||||||
assert(path.name);
|
assert(path.name);
|
||||||
|
|
||||||
this.pathCache.set(path.hash, path);
|
|
||||||
|
|
||||||
result.push(path);
|
result.push(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1135,7 +966,11 @@ Wallet.prototype.getPaths = async function getPaths(acct) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.getAccountPaths = async function getAccountPaths(acct) {
|
Wallet.prototype.getAccountPaths = async function getAccountPaths(acct) {
|
||||||
const index = await this.ensureIndex(acct, true);
|
const index = await this.getAccountIndex(acct);
|
||||||
|
|
||||||
|
if (index === -1)
|
||||||
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
const hashes = await this.getAccountHashes(index);
|
const hashes = await this.getAccountHashes(index);
|
||||||
const name = await this.getAccountName(acct);
|
const name = await this.getAccountName(acct);
|
||||||
|
|
||||||
@ -1151,8 +986,6 @@ Wallet.prototype.getAccountPaths = async function getAccountPaths(acct) {
|
|||||||
|
|
||||||
path.name = name;
|
path.name = name;
|
||||||
|
|
||||||
this.pathCache.set(path.hash, path);
|
|
||||||
|
|
||||||
result.push(path);
|
result.push(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1187,15 +1020,6 @@ Wallet.prototype.importKey = async function importKey(acct, ring, passphrase) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._importKey = async function _importKey(acct, ring, passphrase) {
|
Wallet.prototype._importKey = async function _importKey(acct, ring, passphrase) {
|
||||||
if (acct && typeof acct === 'object') {
|
|
||||||
passphrase = ring;
|
|
||||||
ring = acct;
|
|
||||||
acct = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acct == null)
|
|
||||||
acct = 0;
|
|
||||||
|
|
||||||
assert(ring.network === this.network,
|
assert(ring.network === this.network,
|
||||||
'Network mismatch for key.');
|
'Network mismatch for key.');
|
||||||
|
|
||||||
@ -1231,16 +1055,9 @@ Wallet.prototype._importKey = async function _importKey(acct, ring, passphrase)
|
|||||||
path.encrypted = true;
|
path.encrypted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.start();
|
const b = this.db.batch();
|
||||||
|
await account.savePath(b, path);
|
||||||
try {
|
await b.write();
|
||||||
await account.savePath(path);
|
|
||||||
} catch (e) {
|
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1271,14 +1088,6 @@ Wallet.prototype.importAddress = async function importAddress(acct, address) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._importAddress = async function _importAddress(acct, address) {
|
Wallet.prototype._importAddress = async function _importAddress(acct, address) {
|
||||||
if (!address) {
|
|
||||||
address = acct;
|
|
||||||
acct = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acct == null)
|
|
||||||
acct = 0;
|
|
||||||
|
|
||||||
assert(address.network === this.network,
|
assert(address.network === this.network,
|
||||||
'Network mismatch for address.');
|
'Network mismatch for address.');
|
||||||
|
|
||||||
@ -1298,16 +1107,9 @@ Wallet.prototype._importAddress = async function _importAddress(acct, address) {
|
|||||||
|
|
||||||
const path = Path.fromAddress(account, address);
|
const path = Path.fromAddress(account, address);
|
||||||
|
|
||||||
this.start();
|
const b = this.db.batch();
|
||||||
|
await account.savePath(b, path);
|
||||||
try {
|
await b.write();
|
||||||
await account.savePath(path);
|
|
||||||
} catch (e) {
|
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1881,29 +1683,14 @@ Wallet.prototype.setLookahead = async function setLookahead(acct, lookahead) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._setLookahead = async function _setLookahead(acct, lookahead) {
|
Wallet.prototype._setLookahead = async function _setLookahead(acct, lookahead) {
|
||||||
if (lookahead == null) {
|
|
||||||
lookahead = acct;
|
|
||||||
acct = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acct == null)
|
|
||||||
acct = 0;
|
|
||||||
|
|
||||||
const account = await this.getAccount(acct);
|
const account = await this.getAccount(acct);
|
||||||
|
|
||||||
if (!account)
|
if (!account)
|
||||||
throw new Error('Account not found.');
|
throw new Error('Account not found.');
|
||||||
|
|
||||||
this.start();
|
const b = this.db.batch();
|
||||||
|
await account.setLookahead(b, lookahead);
|
||||||
try {
|
await b.write();
|
||||||
await account.setLookahead(lookahead);
|
|
||||||
} catch (e) {
|
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.commit();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1933,6 +1720,7 @@ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(tx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const derived = [];
|
const derived = [];
|
||||||
|
const b = this.db.batch();
|
||||||
|
|
||||||
for (const [acct, paths] of map) {
|
for (const [acct, paths] of map) {
|
||||||
let receive = -1;
|
let receive = -1;
|
||||||
@ -1963,33 +1751,17 @@ Wallet.prototype.syncOutputDepth = async function syncOutputDepth(tx) {
|
|||||||
const account = await this.getAccount(acct);
|
const account = await this.getAccount(acct);
|
||||||
assert(account);
|
assert(account);
|
||||||
|
|
||||||
const ring = await account.syncDepth(receive, change, nested);
|
const ring = await account.syncDepth(b, receive, change, nested);
|
||||||
|
|
||||||
if (ring)
|
if (ring)
|
||||||
derived.push(ring);
|
derived.push(ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await b.write();
|
||||||
|
|
||||||
return derived;
|
return derived;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a redeem script or witness script by hash.
|
|
||||||
* @param {Hash} hash - Can be a ripemd160 or a sha256.
|
|
||||||
* @returns {Script}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Wallet.prototype.getRedeem = async function getRedeem(hash) {
|
|
||||||
if (typeof hash === 'string')
|
|
||||||
hash = Buffer.from(hash, 'hex');
|
|
||||||
|
|
||||||
const ring = await this.getKey(hash.toString('hex'));
|
|
||||||
|
|
||||||
if (!ring)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return ring.getRedeem(hash);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build input scripts templates for a transaction (does not
|
* Build input scripts templates for a transaction (does not
|
||||||
* sign, only creates signature slots). Only builds scripts
|
* sign, only creates signature slots). Only builds scripts
|
||||||
@ -2021,7 +1793,7 @@ Wallet.prototype.sign = async function sign(mtx, passphrase) {
|
|||||||
|
|
||||||
const rings = await this.deriveInputs(mtx);
|
const rings = await this.deriveInputs(mtx);
|
||||||
|
|
||||||
return await mtx.signAsync(rings, Script.hashType.ALL, this.wdb.workers);
|
return mtx.signAsync(rings, Script.hashType.ALL, this.wdb.workers);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2128,23 +1900,14 @@ Wallet.prototype.add = async function add(tx, block) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype._add = async function _add(tx, block) {
|
Wallet.prototype._add = async function _add(tx, block) {
|
||||||
this.txdb.start();
|
const details = await this.txdb.add(tx, block);
|
||||||
|
|
||||||
let details, derived;
|
if (details) {
|
||||||
try {
|
const derived = await this.syncOutputDepth(tx);
|
||||||
details = await this.txdb._add(tx, block);
|
if (derived.length > 0) {
|
||||||
if (details)
|
this.wdb.emit('address', this.id, derived);
|
||||||
derived = await this.syncOutputDepth(tx);
|
this.emit('address', derived);
|
||||||
} catch (e) {
|
}
|
||||||
this.txdb.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.txdb.commit();
|
|
||||||
|
|
||||||
if (derived && derived.length > 0) {
|
|
||||||
this.wdb.emit('address', this.id, derived);
|
|
||||||
this.emit('address', derived);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return details;
|
return details;
|
||||||
@ -2375,10 +2138,6 @@ Wallet.prototype.getBalance = async function getBalance(acct) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.getRange = async function getRange(acct, options) {
|
Wallet.prototype.getRange = async function getRange(acct, options) {
|
||||||
if (acct && typeof acct === 'object') {
|
|
||||||
options = acct;
|
|
||||||
acct = null;
|
|
||||||
}
|
|
||||||
const account = await this.ensureIndex(acct);
|
const account = await this.ensureIndex(acct);
|
||||||
return await this.txdb.getRange(account, options);
|
return await this.txdb.getRange(account, options);
|
||||||
};
|
};
|
||||||
@ -2395,29 +2154,6 @@ Wallet.prototype.getLast = async function getLast(acct, limit) {
|
|||||||
return await this.txdb.getLast(account, limit);
|
return await this.txdb.getLast(account, limit);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve account index.
|
|
||||||
* @private
|
|
||||||
* @param {(Number|String)?} acct
|
|
||||||
* @param {Function} errback - Returns [Error].
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Wallet.prototype.ensureIndex = async function ensureIndex(acct, enforce) {
|
|
||||||
if (acct == null) {
|
|
||||||
if (enforce)
|
|
||||||
throw new Error('No account provided.');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const index = await this.getAccountIndex(acct);
|
|
||||||
|
|
||||||
if (index === -1)
|
|
||||||
throw new Error('Account not found.');
|
|
||||||
|
|
||||||
return index;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current receive address.
|
* Get current receive address.
|
||||||
* @param {String?} enc - `"base58"` or `null`.
|
* @param {String?} enc - `"base58"` or `null`.
|
||||||
|
|||||||
@ -184,8 +184,10 @@ WalletDB.prototype._close = async function _close() {
|
|||||||
if (this.http && this.options.listen)
|
if (this.http && this.options.listen)
|
||||||
await this.http.close();
|
await this.http.close();
|
||||||
|
|
||||||
for (const wallet of this.wallets.values())
|
for (const wallet of this.wallets.values()) {
|
||||||
await wallet.destroy();
|
await wallet.destroy();
|
||||||
|
this.unregister(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
await this.db.close();
|
await this.db.close();
|
||||||
|
|
||||||
@ -303,14 +305,14 @@ WalletDB.prototype.disconnect = async function disconnect() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.init = async function init() {
|
WalletDB.prototype.init = async function init() {
|
||||||
const state = await this.getState();
|
const cache = await this.getState();
|
||||||
|
|
||||||
if (state) {
|
if (cache) {
|
||||||
this.state = state;
|
this.state = cache;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const batch = this.db.batch();
|
const b = this.db.batch();
|
||||||
|
|
||||||
let tip = null;
|
let tip = null;
|
||||||
|
|
||||||
@ -320,27 +322,27 @@ WalletDB.prototype.init = async function init() {
|
|||||||
for (let height = 0; height < hashes.length; height++) {
|
for (let height = 0; height < hashes.length; height++) {
|
||||||
const hash = hashes[height];
|
const hash = hashes[height];
|
||||||
const meta = new BlockMeta(hash, height);
|
const meta = new BlockMeta(hash, height);
|
||||||
batch.put(layout.h(height), meta.toHash());
|
b.put(layout.h(height), meta.toHash());
|
||||||
tip = meta;
|
tip = meta;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tip = new BlockMeta(this.network.genesis.hash, 0);
|
tip = new BlockMeta(this.network.genesis.hash, 0);
|
||||||
batch.put(layout.h(0), tip.toHash());
|
b.put(layout.h(0), tip.toHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(tip);
|
assert(tip);
|
||||||
|
|
||||||
const pending = this.state.clone();
|
const state = this.state.clone();
|
||||||
pending.startHeight = tip.height;
|
state.startHeight = tip.height;
|
||||||
pending.startHash = tip.hash;
|
state.startHash = tip.hash;
|
||||||
pending.height = tip.height;
|
state.height = tip.height;
|
||||||
pending.marked = false;
|
state.marked = false;
|
||||||
|
|
||||||
batch.put(layout.R, pending.toRaw());
|
b.put(layout.R, state.toRaw());
|
||||||
|
|
||||||
await batch.write();
|
await b.write();
|
||||||
|
|
||||||
this.state = pending;
|
this.state = state;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -587,7 +589,7 @@ WalletDB.prototype.wipe = async function wipe() {
|
|||||||
lte: Buffer.from([0xff])
|
lte: Buffer.from([0xff])
|
||||||
});
|
});
|
||||||
|
|
||||||
const batch = this.db.batch();
|
const b = this.db.batch();
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
|
|
||||||
@ -600,7 +602,7 @@ WalletDB.prototype.wipe = async function wipe() {
|
|||||||
case 0x6f: // o
|
case 0x6f: // o
|
||||||
case 0x68: // h
|
case 0x68: // h
|
||||||
case 0x52: // R
|
case 0x52: // R
|
||||||
batch.del(key);
|
b.del(key);
|
||||||
total += 1;
|
total += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -608,7 +610,7 @@ WalletDB.prototype.wipe = async function wipe() {
|
|||||||
|
|
||||||
this.logger.warning('Wiped %d txdb records.', total);
|
this.logger.warning('Wiped %d txdb records.', total);
|
||||||
|
|
||||||
await batch.write();
|
await b.write();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -646,83 +648,6 @@ WalletDB.prototype.getDepth = async function getDepth() {
|
|||||||
return depth + 1;
|
return depth + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Start batch.
|
|
||||||
* @private
|
|
||||||
* @param {WalletID} wid
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletDB.prototype.start = function start(wallet) {
|
|
||||||
assert(!wallet.current, 'WDB: Batch already started.');
|
|
||||||
wallet.current = this.db.batch();
|
|
||||||
wallet.accountCache.start();
|
|
||||||
wallet.pathCache.start();
|
|
||||||
return wallet.current;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drop batch.
|
|
||||||
* @private
|
|
||||||
* @param {WalletID} wid
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletDB.prototype.drop = function drop(wallet) {
|
|
||||||
const batch = this.batch(wallet);
|
|
||||||
wallet.current = null;
|
|
||||||
wallet.accountCache.drop();
|
|
||||||
wallet.pathCache.drop();
|
|
||||||
batch.clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear batch.
|
|
||||||
* @private
|
|
||||||
* @param {WalletID} wid
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletDB.prototype.clear = function clear(wallet) {
|
|
||||||
const batch = this.batch(wallet);
|
|
||||||
wallet.accountCache.clear();
|
|
||||||
wallet.pathCache.clear();
|
|
||||||
batch.clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get batch.
|
|
||||||
* @private
|
|
||||||
* @param {WalletID} wid
|
|
||||||
* @returns {Leveldown.Batch}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletDB.prototype.batch = function batch(wallet) {
|
|
||||||
assert(wallet.current, 'WDB: Batch does not exist.');
|
|
||||||
return wallet.current;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save batch.
|
|
||||||
* @private
|
|
||||||
* @param {WalletID} wid
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
WalletDB.prototype.commit = async function commit(wallet) {
|
|
||||||
const batch = this.batch(wallet);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await batch.write();
|
|
||||||
} catch (e) {
|
|
||||||
wallet.current = null;
|
|
||||||
wallet.accountCache.drop();
|
|
||||||
wallet.pathCache.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
wallet.current = null;
|
|
||||||
wallet.accountCache.commit();
|
|
||||||
wallet.pathCache.commit();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the bloom filter against a tx or address hash.
|
* Test the bloom filter against a tx or address hash.
|
||||||
* @private
|
* @private
|
||||||
@ -793,7 +718,7 @@ WalletDB.prototype.unregister = function unregister(wallet) {
|
|||||||
* @returns {Promise} - Returns {WalletID}.
|
* @returns {Promise} - Returns {WalletID}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.getWalletID = async function getWalletID(id) {
|
WalletDB.prototype.getWID = async function getWID(id) {
|
||||||
if (!id)
|
if (!id)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -817,7 +742,7 @@ WalletDB.prototype.getWalletID = async function getWalletID(id) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.get = async function get(id) {
|
WalletDB.prototype.get = async function get(id) {
|
||||||
const wid = await this.getWalletID(id);
|
const wid = await this.getWID(id);
|
||||||
|
|
||||||
if (!wid)
|
if (!wid)
|
||||||
return null;
|
return null;
|
||||||
@ -863,13 +788,12 @@ WalletDB.prototype._get = async function _get(wid) {
|
|||||||
* @param {Wallet} wallet
|
* @param {Wallet} wallet
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.save = function save(wallet) {
|
WalletDB.prototype.save = function save(b, wallet) {
|
||||||
const wid = wallet.wid;
|
const wid = wallet.wid;
|
||||||
const id = wallet.id;
|
const id = wallet.id;
|
||||||
const batch = this.batch(wallet);
|
|
||||||
|
|
||||||
batch.put(layout.w(wid), wallet.toRaw());
|
b.put(layout.w(wid), wallet.toRaw());
|
||||||
batch.put(layout.l(id), U32(wid));
|
b.put(layout.l(id), U32(wid));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -897,27 +821,23 @@ WalletDB.prototype.rename = async function rename(wallet, id) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype._rename = async function _rename(wallet, id) {
|
WalletDB.prototype._rename = async function _rename(wallet, id) {
|
||||||
const old = wallet.id;
|
|
||||||
|
|
||||||
if (!common.isName(id))
|
if (!common.isName(id))
|
||||||
throw new Error('WDB: Bad wallet ID.');
|
throw new Error('WDB: Bad wallet ID.');
|
||||||
|
|
||||||
if (await this.has(id))
|
if (await this.has(id))
|
||||||
throw new Error('WDB: ID not available.');
|
throw new Error('WDB: ID not available.');
|
||||||
|
|
||||||
const batch = this.start(wallet);
|
const old = wallet.id;
|
||||||
batch.del(layout.l(old));
|
const b = this.db.batch();
|
||||||
|
|
||||||
|
b.del(layout.l(old));
|
||||||
|
|
||||||
wallet.id = id;
|
wallet.id = id;
|
||||||
|
wallet.txdb.id = id;
|
||||||
|
|
||||||
this.save(wallet);
|
this.save(b, wallet);
|
||||||
|
|
||||||
await this.commit(wallet);
|
await b.write();
|
||||||
|
|
||||||
const paths = wallet.pathCache.values();
|
|
||||||
|
|
||||||
for (const path of paths)
|
|
||||||
path.id = id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -926,16 +846,13 @@ WalletDB.prototype._rename = async function _rename(wallet, id) {
|
|||||||
* @param {String} name
|
* @param {String} name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.renameAccount = function renameAccount(account, name) {
|
WalletDB.prototype.renameAccount = function renameAccount(b, account, name) {
|
||||||
const wallet = account.wallet;
|
|
||||||
const batch = this.batch(wallet);
|
|
||||||
|
|
||||||
// Remove old wid/name->account index.
|
// Remove old wid/name->account index.
|
||||||
batch.del(layout.i(account.wid, account.name));
|
b.del(layout.i(account.wid, account.name));
|
||||||
|
|
||||||
account.name = name;
|
account.name = name;
|
||||||
|
|
||||||
this.saveAccount(account);
|
this.saveAccount(b, account);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1018,7 +935,7 @@ WalletDB.prototype._create = async function _create(options) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.has = async function has(id) {
|
WalletDB.prototype.has = async function has(id) {
|
||||||
const wid = await this.getWalletID(id);
|
const wid = await this.getWID(id);
|
||||||
return wid != null;
|
return wid != null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1106,23 +1023,19 @@ WalletDB.prototype.getAccountName = async function getAccountName(wid, index) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.saveAccount = function saveAccount(account) {
|
WalletDB.prototype.saveAccount = function saveAccount(b, account) {
|
||||||
const wid = account.wid;
|
const wid = account.wid;
|
||||||
const wallet = account.wallet;
|
|
||||||
const index = account.accountIndex;
|
const index = account.accountIndex;
|
||||||
const name = account.name;
|
const name = account.name;
|
||||||
const batch = this.batch(wallet);
|
|
||||||
|
|
||||||
// Account data
|
// Account data
|
||||||
batch.put(layout.a(wid, index), account.toRaw());
|
b.put(layout.a(wid, index), account.toRaw());
|
||||||
|
|
||||||
// Name->Index lookups
|
// Name->Index lookups
|
||||||
batch.put(layout.i(wid, name), U32(index));
|
b.put(layout.i(wid, name), U32(index));
|
||||||
|
|
||||||
// Index->Name lookups
|
// Index->Name lookups
|
||||||
batch.put(layout.n(wid, index), Buffer.from(name, 'ascii'));
|
b.put(layout.n(wid, index), Buffer.from(name, 'ascii'));
|
||||||
|
|
||||||
wallet.accountCache.push(index, account);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1143,8 +1056,8 @@ WalletDB.prototype.hasAccount = function hasAccount(wid, index) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.saveKey = function saveKey(wallet, ring) {
|
WalletDB.prototype.saveKey = function saveKey(b, wid, ring) {
|
||||||
return this.savePath(wallet, ring.toPath());
|
return this.savePath(b, wid, ring.toPath());
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1160,21 +1073,15 @@ WalletDB.prototype.saveKey = function saveKey(wallet, ring) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.savePath = async function savePath(wallet, path) {
|
WalletDB.prototype.savePath = async function savePath(b, wid, path) {
|
||||||
const wid = wallet.wid;
|
|
||||||
const hash = path.hash;
|
|
||||||
const batch = this.batch(wallet);
|
|
||||||
|
|
||||||
wallet.pathCache.push(hash, path);
|
|
||||||
|
|
||||||
// Address Hash -> Wallet Map
|
// Address Hash -> Wallet Map
|
||||||
await this.addPathMap(wallet, hash);
|
await this.addPathMap(b, path.hash, wid);
|
||||||
|
|
||||||
// Wallet ID + Address Hash -> Path Data
|
// Wallet ID + Address Hash -> Path Data
|
||||||
batch.put(layout.P(wid, hash), path.toRaw());
|
b.put(layout.P(wid, path.hash), path.toRaw());
|
||||||
|
|
||||||
// Wallet ID + Account Index + Address Hash -> Dummy
|
// Wallet ID + Account Index + Address Hash -> Dummy
|
||||||
batch.put(layout.r(wid, path.account, hash), null);
|
b.put(layout.r(wid, path.account, path.hash), null);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1184,13 +1091,33 @@ WalletDB.prototype.savePath = async function savePath(wallet, path) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.getPath = async function getPath(wid, hash) {
|
WalletDB.prototype.getPath = async function getPath(wid, id, hash) {
|
||||||
|
const path = await this.readPath(wid, id, hash);
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
path.name = await this.getAccountName(wid, path.account);
|
||||||
|
assert(path.name);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve path by hash.
|
||||||
|
* @param {WalletID} wid
|
||||||
|
* @param {Hash} hash
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
|
||||||
|
WalletDB.prototype.readPath = async function readPath(wid, id, hash) {
|
||||||
const data = await this.db.get(layout.P(wid, hash));
|
const data = await this.db.get(layout.P(wid, hash));
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
const path = Path.fromRaw(data);
|
const path = Path.fromRaw(data);
|
||||||
|
path.id = id;
|
||||||
path.wid = wid;
|
path.wid = wid;
|
||||||
path.hash = hash;
|
path.hash = hash;
|
||||||
|
|
||||||
@ -1313,28 +1240,30 @@ WalletDB.prototype.getWallets = function getWallets() {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.encryptKeys = async function encryptKeys(wallet, key) {
|
WalletDB.prototype.encryptKeys = async function encryptKeys(b, wid, key) {
|
||||||
const wid = wallet.wid;
|
const iter = this.db.iterator({
|
||||||
const paths = await wallet.getPaths();
|
gte: layout.P(wid, encoding.NULL_HASH),
|
||||||
const batch = this.batch(wallet);
|
lte: layout.P(wid, encoding.HIGH_HASH),
|
||||||
|
values: true
|
||||||
|
});
|
||||||
|
|
||||||
|
await iter.each((k, value) => {
|
||||||
|
const hash = layout.Pp(k);
|
||||||
|
const path = Path.fromRaw(value);
|
||||||
|
|
||||||
for (let path of paths) {
|
|
||||||
if (!path.data)
|
if (!path.data)
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
assert(!path.encrypted);
|
assert(!path.encrypted);
|
||||||
|
|
||||||
const hash = Buffer.from(path.hash, 'hex');
|
const bhash = Buffer.from(hash, 'hex');
|
||||||
const iv = hash.slice(0, 16);
|
const iv = bhash.slice(0, 16);
|
||||||
|
|
||||||
path = path.clone();
|
|
||||||
path.data = aes.encipher(path.data, key, iv);
|
path.data = aes.encipher(path.data, key, iv);
|
||||||
path.encrypted = true;
|
path.encrypted = true;
|
||||||
|
|
||||||
wallet.pathCache.push(path.hash, path);
|
b.put(k, path.toRaw());
|
||||||
|
});
|
||||||
batch.put(layout.P(wid, path.hash), path.toRaw());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1344,28 +1273,30 @@ WalletDB.prototype.encryptKeys = async function encryptKeys(wallet, key) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.decryptKeys = async function decryptKeys(wallet, key) {
|
WalletDB.prototype.decryptKeys = async function decryptKeys(b, wid, key) {
|
||||||
const wid = wallet.wid;
|
const iter = this.db.iterator({
|
||||||
const paths = await wallet.getPaths();
|
gte: layout.P(wid, encoding.NULL_HASH),
|
||||||
const batch = this.batch(wallet);
|
lte: layout.P(wid, encoding.HIGH_HASH),
|
||||||
|
values: true
|
||||||
|
});
|
||||||
|
|
||||||
|
await iter.each((k, value) => {
|
||||||
|
const hash = layout.Pp(k);
|
||||||
|
const path = Path.fromRaw(value);
|
||||||
|
|
||||||
for (let path of paths) {
|
|
||||||
if (!path.data)
|
if (!path.data)
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
assert(path.encrypted);
|
assert(path.encrypted);
|
||||||
|
|
||||||
const hash = Buffer.from(path.hash, 'hex');
|
const bhash = Buffer.from(hash, 'hex');
|
||||||
const iv = hash.slice(0, 16);
|
const iv = bhash.slice(0, 16);
|
||||||
|
|
||||||
path = path.clone();
|
|
||||||
path.data = aes.decipher(path.data, key, iv);
|
path.data = aes.decipher(path.data, key, iv);
|
||||||
path.encrypted = false;
|
path.encrypted = false;
|
||||||
|
|
||||||
wallet.pathCache.push(path.hash, path);
|
b.put(k, path.toRaw());
|
||||||
|
});
|
||||||
batch.put(layout.P(wid, path.hash), path.toRaw());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1500,14 +1431,14 @@ WalletDB.prototype.getState = async function getState() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.syncState = async function syncState(tip) {
|
WalletDB.prototype.syncState = async function syncState(tip) {
|
||||||
const batch = this.db.batch();
|
const b = this.db.batch();
|
||||||
const state = this.state.clone();
|
const state = this.state.clone();
|
||||||
|
|
||||||
if (tip.height < state.height) {
|
if (tip.height < state.height) {
|
||||||
// Hashes ahead of our new tip
|
// Hashes ahead of our new tip
|
||||||
// that we need to delete.
|
// that we need to delete.
|
||||||
while (state.height !== tip.height) {
|
while (state.height !== tip.height) {
|
||||||
batch.del(layout.h(state.height));
|
b.del(layout.h(state.height));
|
||||||
state.height -= 1;
|
state.height -= 1;
|
||||||
}
|
}
|
||||||
} else if (tip.height > state.height) {
|
} else if (tip.height > state.height) {
|
||||||
@ -1522,10 +1453,10 @@ WalletDB.prototype.syncState = async function syncState(tip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save tip and state.
|
// Save tip and state.
|
||||||
batch.put(layout.h(tip.height), tip.toHash());
|
b.put(layout.h(tip.height), tip.toHash());
|
||||||
batch.put(layout.R, state.toRaw());
|
b.put(layout.R, state.toRaw());
|
||||||
|
|
||||||
await batch.write();
|
await b.write();
|
||||||
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
};
|
};
|
||||||
@ -1542,9 +1473,9 @@ WalletDB.prototype.markState = async function markState(block) {
|
|||||||
state.startHash = block.hash;
|
state.startHash = block.hash;
|
||||||
state.marked = true;
|
state.marked = true;
|
||||||
|
|
||||||
const batch = this.db.batch();
|
const b = this.db.batch();
|
||||||
batch.put(layout.R, state.toRaw());
|
b.put(layout.R, state.toRaw());
|
||||||
await batch.write();
|
await b.write();
|
||||||
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
};
|
};
|
||||||
@ -1571,15 +1502,13 @@ WalletDB.prototype.getMap = async function getMap(key) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.addMap = async function addMap(wallet, key) {
|
WalletDB.prototype.addMap = async function addMap(b, key, wid) {
|
||||||
const wid = wallet.wid;
|
|
||||||
const batch = this.batch(wallet);
|
|
||||||
const data = await this.db.get(key);
|
const data = await this.db.get(key);
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
const map = new MapRecord();
|
const map = new MapRecord();
|
||||||
map.add(wid);
|
map.add(wid);
|
||||||
batch.put(key, map.toRaw());
|
b.put(key, map.toRaw());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1592,7 +1521,7 @@ WalletDB.prototype.addMap = async function addMap(wallet, key) {
|
|||||||
bw.copy(data, 4, data.length);
|
bw.copy(data, 4, data.length);
|
||||||
bw.writeU32(wid);
|
bw.writeU32(wid);
|
||||||
|
|
||||||
batch.put(key, bw.render());
|
b.put(key, bw.render());
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1602,9 +1531,7 @@ WalletDB.prototype.addMap = async function addMap(wallet, key) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.removeMap = async function removeMap(wallet, key) {
|
WalletDB.prototype.removeMap = async function removeMap(b, key, wid) {
|
||||||
const wid = wallet.wid;
|
|
||||||
const batch = this.batch(wallet);
|
|
||||||
const map = await this.getMap(key);
|
const map = await this.getMap(key);
|
||||||
|
|
||||||
if (!map)
|
if (!map)
|
||||||
@ -1614,11 +1541,11 @@ WalletDB.prototype.removeMap = async function removeMap(wallet, key) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (map.size === 0) {
|
if (map.size === 0) {
|
||||||
batch.del(key);
|
b.del(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.put(key, map.toRaw());
|
b.put(key, map.toRaw());
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1638,9 +1565,9 @@ WalletDB.prototype.getPathMap = function getPathMap(hash) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.addPathMap = function addPathMap(wallet, hash) {
|
WalletDB.prototype.addPathMap = function addPathMap(b, hash, wid) {
|
||||||
this.addHash(hash);
|
this.addHash(hash);
|
||||||
return this.addMap(wallet, layout.p(hash));
|
return this.addMap(b, layout.p(hash), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1650,8 +1577,8 @@ WalletDB.prototype.addPathMap = function addPathMap(wallet, hash) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.removePathMap = function removePathMap(wallet, hash) {
|
WalletDB.prototype.removePathMap = function removePathMap(b, hash, wid) {
|
||||||
return this.removeMap(wallet, layout.p(hash));
|
return this.removeMap(b, layout.p(hash), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1671,8 +1598,8 @@ WalletDB.prototype.getBlockMap = async function getBlockMap(height) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.addBlockMap = function addBlockMap(wallet, height) {
|
WalletDB.prototype.addBlockMap = function addBlockMap(b, height, wid) {
|
||||||
return this.addMap(wallet, layout.b(height));
|
return this.addMap(b, layout.b(height), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1682,8 +1609,8 @@ WalletDB.prototype.addBlockMap = function addBlockMap(wallet, height) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.removeBlockMap = function removeBlockMap(wallet, height) {
|
WalletDB.prototype.removeBlockMap = function removeBlockMap(b, height, wid) {
|
||||||
return this.removeMap(wallet, layout.b(height));
|
return this.removeMap(b, layout.b(height), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1703,8 +1630,8 @@ WalletDB.prototype.getTXMap = function getTXMap(hash) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.addTXMap = function addTXMap(wallet, hash) {
|
WalletDB.prototype.addTXMap = function addTXMap(b, hash, wid) {
|
||||||
return this.addMap(wallet, layout.T(hash));
|
return this.addMap(b, layout.T(hash), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1714,8 +1641,8 @@ WalletDB.prototype.addTXMap = function addTXMap(wallet, hash) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.removeTXMap = function removeTXMap(wallet, hash) {
|
WalletDB.prototype.removeTXMap = function removeTXMap(b, hash, wid) {
|
||||||
return this.removeMap(wallet, layout.T(hash));
|
return this.removeMap(b, layout.T(hash), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1724,7 +1651,7 @@ WalletDB.prototype.removeTXMap = function removeTXMap(wallet, hash) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.getOutpointMap = async function getOutpointMap(hash, index) {
|
WalletDB.prototype.getOutpointMap = function getOutpointMap(hash, index) {
|
||||||
return this.getMap(layout.o(hash, index));
|
return this.getMap(layout.o(hash, index));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1735,9 +1662,9 @@ WalletDB.prototype.getOutpointMap = async function getOutpointMap(hash, index) {
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.addOutpointMap = async function addOutpointMap(wallet, hash, index) {
|
WalletDB.prototype.addOutpointMap = async function addOutpointMap(b, hash, index, wid) {
|
||||||
this.addOutpoint(hash, index);
|
await this.addOutpoint(hash, index);
|
||||||
return this.addMap(wallet, layout.o(hash, index));
|
return this.addMap(b, layout.o(hash, index), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1747,8 +1674,8 @@ WalletDB.prototype.addOutpointMap = async function addOutpointMap(wallet, hash,
|
|||||||
* @param {Number} wid
|
* @param {Number} wid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.removeOutpointMap = async function removeOutpointMap(wallet, hash, index) {
|
WalletDB.prototype.removeOutpointMap = function removeOutpointMap(b, hash, index, wid) {
|
||||||
return this.removeMap(wallet, layout.o(hash, index));
|
return this.removeMap(b, layout.o(hash, index), wid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -118,14 +118,14 @@ async function testP2SH(witness, nesting) {
|
|||||||
const carol = await wdb.create(options);
|
const carol = await wdb.create(options);
|
||||||
const recipient = await wdb.create();
|
const recipient = await wdb.create();
|
||||||
|
|
||||||
await alice.addSharedKey(bob.account.accountKey);
|
await alice.addSharedKey(0, bob.account.accountKey);
|
||||||
await alice.addSharedKey(carol.account.accountKey);
|
await alice.addSharedKey(0, carol.account.accountKey);
|
||||||
|
|
||||||
await bob.addSharedKey(alice.account.accountKey);
|
await bob.addSharedKey(0, alice.account.accountKey);
|
||||||
await bob.addSharedKey(carol.account.accountKey);
|
await bob.addSharedKey(0, carol.account.accountKey);
|
||||||
|
|
||||||
await carol.addSharedKey(alice.account.accountKey);
|
await carol.addSharedKey(0, alice.account.accountKey);
|
||||||
await carol.addSharedKey(bob.account.accountKey);
|
await carol.addSharedKey(0, bob.account.accountKey);
|
||||||
|
|
||||||
// Our p2sh address
|
// Our p2sh address
|
||||||
const addr1 = alice.account[receive].getAddress();
|
const addr1 = alice.account[receive].getAddress();
|
||||||
@ -262,15 +262,8 @@ describe('Wallet', function() {
|
|||||||
|
|
||||||
it('should create and get wallet', async () => {
|
it('should create and get wallet', async () => {
|
||||||
const wallet1 = await wdb.create();
|
const wallet1 = await wdb.create();
|
||||||
|
|
||||||
await wallet1.destroy();
|
|
||||||
|
|
||||||
const wallet2 = await wdb.get(wallet1.id);
|
const wallet2 = await wdb.get(wallet1.id);
|
||||||
|
assert(wallet1 === wallet2);
|
||||||
assert(wallet1 !== wallet2);
|
|
||||||
assert(wallet1.master !== wallet2.master);
|
|
||||||
assert(wallet1.master.key.equals(wallet2.master.key));
|
|
||||||
assert(wallet1.account.accountKey.equals(wallet2.account.accountKey));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should sign/verify p2pkh tx', async () => {
|
it('should sign/verify p2pkh tx', async () => {
|
||||||
@ -295,7 +288,7 @@ describe('Wallet', function() {
|
|||||||
const xpriv = HD.PrivateKey.generate();
|
const xpriv = HD.PrivateKey.generate();
|
||||||
const key = xpriv.deriveAccount(44, 0).toPublic();
|
const key = xpriv.deriveAccount(44, 0).toPublic();
|
||||||
|
|
||||||
await wallet.addSharedKey(key);
|
await wallet.addSharedKey(0, key);
|
||||||
|
|
||||||
const script = Script.fromMultisig(1, 2, [
|
const script = Script.fromMultisig(1, 2, [
|
||||||
wallet.account.receive.getPublicKey(),
|
wallet.account.receive.getPublicKey(),
|
||||||
@ -684,7 +677,7 @@ describe('Wallet', function() {
|
|||||||
assert.strictEqual(t2.getSize(), 521);
|
assert.strictEqual(t2.getSize(), 521);
|
||||||
assert.strictEqual(t2.getVirtualSize(), 521);
|
assert.strictEqual(t2.getVirtualSize(), 521);
|
||||||
|
|
||||||
let balance;
|
let balance = null;
|
||||||
bob.once('balance', (b) => {
|
bob.once('balance', (b) => {
|
||||||
balance = b;
|
balance = b;
|
||||||
});
|
});
|
||||||
@ -927,6 +920,7 @@ describe('Wallet', function() {
|
|||||||
passphrase: 'foo'
|
passphrase: 'foo'
|
||||||
});
|
});
|
||||||
await wallet.destroy();
|
await wallet.destroy();
|
||||||
|
wdb.unregister(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
const wallet = await wdb.get('foobar');
|
const wallet = await wdb.get('foobar');
|
||||||
@ -1156,7 +1150,7 @@ describe('Wallet', function() {
|
|||||||
|
|
||||||
it('should get range of txs', async () => {
|
it('should get range of txs', async () => {
|
||||||
const wallet = currentWallet;
|
const wallet = currentWallet;
|
||||||
const txs = await wallet.getRange({
|
const txs = await wallet.getRange(null, {
|
||||||
start: util.now() - 1000
|
start: util.now() - 1000
|
||||||
});
|
});
|
||||||
assert.strictEqual(txs.length, 2);
|
assert.strictEqual(txs.length, 2);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user