387 lines
10 KiB
JavaScript
387 lines
10 KiB
JavaScript
/*!
|
|
* layout.js - data layout for wallets
|
|
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
|
|
* https://github.com/bcoin-org/bcoin
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const layouts = exports;
|
|
|
|
/*
|
|
* Wallet Database Layout:
|
|
* p[addr-hash] -> wallet ids
|
|
* P[wid][addr-hash] -> path data
|
|
* r[wid][index][hash] -> path account index
|
|
* w[wid] -> wallet
|
|
* l[id] -> wid
|
|
* a[wid][index] -> account
|
|
* i[wid][name] -> account index
|
|
* n[wid][index] -> account name
|
|
* t[wid]* -> txdb
|
|
* R -> chain sync state
|
|
* h[height] -> recent block hash
|
|
* b[height] -> block->wid map
|
|
* o[hash][index] -> outpoint->wid map
|
|
* T[hash] -> tx->wid map
|
|
*/
|
|
|
|
layouts.walletdb = {
|
|
binary: true,
|
|
p: function p(hash) {
|
|
assert(typeof hash === 'string');
|
|
const key = Buffer.allocUnsafe(1 + (hash.length / 2));
|
|
key[0] = 0x70;
|
|
key.write(hash, 1, 'hex');
|
|
return key;
|
|
},
|
|
pp: function pp(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length >= 21);
|
|
return key.toString('hex', 1);
|
|
},
|
|
P: function P(wid, hash) {
|
|
assert(typeof wid === 'number');
|
|
assert(typeof hash === 'string');
|
|
const key = Buffer.allocUnsafe(1 + 4 + (hash.length / 2));
|
|
key[0] = 0x50;
|
|
key.writeUInt32BE(wid, 1, true);
|
|
key.write(hash, 5, 'hex');
|
|
return key;
|
|
},
|
|
Pp: function Pp(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length >= 25);
|
|
return key.toString('hex', 5);
|
|
},
|
|
r: function r(wid, index, hash) {
|
|
assert(typeof wid === 'number');
|
|
assert(typeof index === 'number');
|
|
assert(typeof hash === 'string');
|
|
const key = Buffer.allocUnsafe(1 + 4 + 4 + (hash.length / 2));
|
|
key[0] = 0x72;
|
|
key.writeUInt32BE(wid, 1, true);
|
|
key.writeUInt32BE(index, 5, true);
|
|
key.write(hash, 9, 'hex');
|
|
return key;
|
|
},
|
|
rr: function rr(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length >= 29);
|
|
return key.toString('hex', 9);
|
|
},
|
|
w: function w(wid) {
|
|
assert(typeof wid === 'number');
|
|
const key = Buffer.allocUnsafe(5);
|
|
key[0] = 0x77;
|
|
key.writeUInt32BE(wid, 1, true);
|
|
return key;
|
|
},
|
|
ww: function ww(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 5);
|
|
return key.readUInt32BE(1, true);
|
|
},
|
|
l: function l(id) {
|
|
assert(typeof id === 'string');
|
|
const len = Buffer.byteLength(id, 'ascii');
|
|
const key = Buffer.allocUnsafe(1 + len);
|
|
key[0] = 0x6c;
|
|
if (len > 0)
|
|
key.write(id, 1, 'ascii');
|
|
return key;
|
|
},
|
|
ll: function ll(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length >= 1);
|
|
return key.toString('ascii', 1);
|
|
},
|
|
a: function a(wid, index) {
|
|
assert(typeof wid === 'number');
|
|
assert(typeof index === 'number');
|
|
const key = Buffer.allocUnsafe(9);
|
|
key[0] = 0x61;
|
|
key.writeUInt32BE(wid, 1, true);
|
|
key.writeUInt32BE(index, 5, true);
|
|
return key;
|
|
},
|
|
i: function i(wid, name) {
|
|
assert(typeof wid === 'number');
|
|
assert(typeof name === 'string');
|
|
const len = Buffer.byteLength(name, 'ascii');
|
|
const key = Buffer.allocUnsafe(5 + len);
|
|
key[0] = 0x69;
|
|
key.writeUInt32BE(wid, 1, true);
|
|
if (len > 0)
|
|
key.write(name, 5, 'ascii');
|
|
return key;
|
|
},
|
|
ii: function ii(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length >= 5);
|
|
return [key.readUInt32BE(1, true), key.toString('ascii', 5)];
|
|
},
|
|
n: function n(wid, index) {
|
|
assert(typeof wid === 'number');
|
|
assert(typeof index === 'number');
|
|
const key = Buffer.allocUnsafe(9);
|
|
key[0] = 0x6e;
|
|
key.writeUInt32BE(wid, 1, true);
|
|
key.writeUInt32BE(index, 5, true);
|
|
return key;
|
|
},
|
|
R: Buffer.from([0x52]),
|
|
h: function h(height) {
|
|
assert(typeof height === 'number');
|
|
const key = Buffer.allocUnsafe(5);
|
|
key[0] = 0x68;
|
|
key.writeUInt32BE(height, 1, true);
|
|
return key;
|
|
},
|
|
b: function b(height) {
|
|
assert(typeof height === 'number');
|
|
const key = Buffer.allocUnsafe(5);
|
|
key[0] = 0x62;
|
|
key.writeUInt32BE(height, 1, true);
|
|
return key;
|
|
},
|
|
bb: function bb(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 5);
|
|
return key.readUInt32BE(1, true);
|
|
},
|
|
o: function o(hash, index) {
|
|
assert(typeof hash === 'string');
|
|
assert(typeof index === 'number');
|
|
const key = Buffer.allocUnsafe(37);
|
|
key[0] = 0x6f;
|
|
key.write(hash, 1, 'hex');
|
|
key.writeUInt32BE(index, 33, true);
|
|
return key;
|
|
},
|
|
oo: function oo(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 37);
|
|
return [key.toString('hex', 1, 33), key.readUInt32BE(33, true)];
|
|
},
|
|
T: function T(hash, index) {
|
|
assert(typeof hash === 'string');
|
|
const key = Buffer.allocUnsafe(33);
|
|
key[0] = 0x54;
|
|
key.write(hash, 1, 'hex');
|
|
return key;
|
|
},
|
|
Tt: function Tt(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 33);
|
|
return key.toString('hex', 1, 33);
|
|
}
|
|
};
|
|
|
|
/*
|
|
* TXDB Database Layout:
|
|
* t[hash] -> extended tx
|
|
* c[hash][index] -> coin
|
|
* d[hash][index] -> undo coin
|
|
* s[hash][index] -> spent by hash
|
|
* o[hash][index] -> orphan inputs
|
|
* p[hash] -> dummy (pending flag)
|
|
* m[time][hash] -> dummy (tx by time)
|
|
* h[height][hash] -> dummy (tx by height)
|
|
* T[account][hash] -> dummy (tx by account)
|
|
* P[account][hash] -> dummy (pending tx by account)
|
|
* M[account][time][hash] -> dummy (tx by time + account)
|
|
* H[account][height][hash] -> dummy (tx by height + account)
|
|
* C[account][hash][index] -> dummy (coin by account)
|
|
* r[hash] -> dummy (replace by fee chain)
|
|
*/
|
|
|
|
layouts.txdb = {
|
|
binary: true,
|
|
prefix: function prefix(wid) {
|
|
assert(typeof wid === 'number');
|
|
const out = Buffer.allocUnsafe(5);
|
|
out[0] = 0x74;
|
|
out.writeUInt32BE(wid, 1);
|
|
return out;
|
|
},
|
|
R: Buffer.from([0x52]),
|
|
r: function r(acct) {
|
|
assert(typeof acct === 'number');
|
|
const key = Buffer.allocUnsafe(5);
|
|
key[0] = 0x72;
|
|
key.writeUInt32BE(acct, 1, true);
|
|
return key;
|
|
},
|
|
rr: function rr(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 5);
|
|
return key.readUInt32BE(1, true);
|
|
},
|
|
hi: function hi(ch, hash, index) {
|
|
assert(typeof hash === 'string');
|
|
assert(typeof index === 'number');
|
|
const key = Buffer.allocUnsafe(37);
|
|
key[0] = ch;
|
|
key.write(hash, 1, 'hex');
|
|
key.writeUInt32BE(index, 33, true);
|
|
return key;
|
|
},
|
|
hii: function hii(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 37);
|
|
return [key.toString('hex', 1, 33), key.readUInt32BE(33, true)];
|
|
},
|
|
ih: function ih(ch, index, hash) {
|
|
assert(typeof index === 'number');
|
|
assert(typeof hash === 'string');
|
|
const key = Buffer.allocUnsafe(37);
|
|
key[0] = ch;
|
|
key.writeUInt32BE(index, 1, true);
|
|
key.write(hash, 5, 'hex');
|
|
return key;
|
|
},
|
|
ihh: function ihh(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 37);
|
|
return [key.readUInt32BE(1, true), key.toString('hex', 5, 37)];
|
|
},
|
|
iih: function iih(ch, index, num, hash) {
|
|
assert(typeof index === 'number');
|
|
assert(typeof num === 'number');
|
|
assert(typeof hash === 'string');
|
|
const key = Buffer.allocUnsafe(41);
|
|
key[0] = ch;
|
|
key.writeUInt32BE(index, 1, true);
|
|
key.writeUInt32BE(num, 5, true);
|
|
key.write(hash, 9, 'hex');
|
|
return key;
|
|
},
|
|
iihh: function iihh(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 41);
|
|
return [
|
|
key.readUInt32BE(1, true),
|
|
key.readUInt32BE(5, true),
|
|
key.toString('hex', 9, 41)
|
|
];
|
|
},
|
|
ihi: function ihi(ch, index, hash, num) {
|
|
assert(typeof index === 'number');
|
|
assert(typeof hash === 'string');
|
|
assert(typeof num === 'number');
|
|
const key = Buffer.allocUnsafe(41);
|
|
key[0] = ch;
|
|
key.writeUInt32BE(index, 1, true);
|
|
key.write(hash, 5, 'hex');
|
|
key.writeUInt32BE(num, 37, true);
|
|
return key;
|
|
},
|
|
ihii: function ihii(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 41);
|
|
return [
|
|
key.readUInt32BE(1, true),
|
|
key.toString('hex', 5, 37),
|
|
key.readUInt32BE(37, true)
|
|
];
|
|
},
|
|
ha: function ha(ch, hash) {
|
|
assert(typeof hash === 'string');
|
|
const key = Buffer.allocUnsafe(33);
|
|
key[0] = ch;
|
|
key.write(hash, 1, 'hex');
|
|
return key;
|
|
},
|
|
haa: function haa(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 33);
|
|
return key.toString('hex', 1, 33);
|
|
},
|
|
t: function t(hash) {
|
|
return this.ha(0x74, hash);
|
|
},
|
|
tt: function tt(key) {
|
|
return this.haa(key);
|
|
},
|
|
c: function c(hash, index) {
|
|
return this.hi(0x63, hash, index);
|
|
},
|
|
cc: function cc(key) {
|
|
return this.hii(key);
|
|
},
|
|
d: function d(hash, index) {
|
|
return this.hi(0x64, hash, index);
|
|
},
|
|
dd: function dd(key) {
|
|
return this.hii(key);
|
|
},
|
|
s: function s(hash, index) {
|
|
return this.hi(0x73, hash, index);
|
|
},
|
|
ss: function ss(key) {
|
|
return this.hii(key);
|
|
},
|
|
p: function p(hash) {
|
|
return this.ha(0x70, hash);
|
|
},
|
|
pp: function pp(key) {
|
|
return this.haa(key);
|
|
},
|
|
m: function m(time, hash) {
|
|
return this.ih(0x6d, time, hash);
|
|
},
|
|
mm: function mm(key) {
|
|
return this.ihh(key);
|
|
},
|
|
h: function h(height, hash) {
|
|
return this.ih(0x68, height, hash);
|
|
},
|
|
hh: function hh(key) {
|
|
return this.ihh(key);
|
|
},
|
|
T: function T(account, hash) {
|
|
return this.ih(0x54, account, hash);
|
|
},
|
|
Tt: function Tt(key) {
|
|
return this.ihh(key);
|
|
},
|
|
P: function P(account, hash) {
|
|
return this.ih(0x50, account, hash);
|
|
},
|
|
Pp: function Pp(key) {
|
|
return this.ihh(key);
|
|
},
|
|
M: function M(account, time, hash) {
|
|
return this.iih(0x4d, account, time, hash);
|
|
},
|
|
Mm: function Mm(key) {
|
|
return this.iihh(key);
|
|
},
|
|
H: function H(account, height, hash) {
|
|
return this.iih(0x48, account, height, hash);
|
|
},
|
|
Hh: function Hh(key) {
|
|
return this.iihh(key);
|
|
},
|
|
C: function C(account, hash, index) {
|
|
return this.ihi(0x43, account, hash, index);
|
|
},
|
|
Cc: function Cc(key) {
|
|
return this.ihii(key);
|
|
},
|
|
b: function b(height) {
|
|
assert(typeof height === 'number');
|
|
const key = Buffer.allocUnsafe(5);
|
|
key[0] = 0x62;
|
|
key.writeUInt32BE(height, 1, true);
|
|
return key;
|
|
},
|
|
bb: function bb(key) {
|
|
assert(Buffer.isBuffer(key));
|
|
assert(key.length === 5);
|
|
return key.readUInt32BE(1, true);
|
|
}
|
|
};
|