@ocap/statedb-memory 1.20.15 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/db.js CHANGED
@@ -3,6 +3,7 @@ const Table = require('./table/base');
3
3
  const Account = require('./table/account');
4
4
  const Token = require('./table/token');
5
5
  const Rollup = require('./table/rollup');
6
+ const Balance = require('./table/balance');
6
7
 
7
8
  const { name, version } = require('../package.json');
8
9
 
@@ -13,17 +14,23 @@ class MemoryStateDB extends StateDB {
13
14
  this.name = name;
14
15
  this.version = version;
15
16
 
16
- this.account = new Account('account', 'address');
17
- this.asset = new Table('asset', 'address');
18
- this.factory = new Table('factory', 'address');
19
- this.delegation = new Table('delegation', 'address');
20
- this.tx = new Table('tx', 'hash');
21
- this.token = new Token('token', 'address');
22
- this.chain = new Table('chain', 'address');
23
- this.stake = new Table('stake', 'address');
24
- this.rollup = new Rollup('rollup', 'address');
25
- this.rollupBlock = new Table('rollupBlock', 'hash');
26
- this.evidence = new Table('evidence', 'hash');
17
+ this.balance = new Balance({ name: 'balance', uniqIndex: ['address', 'tokenAddress'] });
18
+ this.account = new Account({
19
+ name: 'account',
20
+ uniqIndex: 'address',
21
+ balanceTable: this.balance,
22
+ syncBalance: true,
23
+ });
24
+ this.factory = new Table({ name: 'factory', uniqIndex: 'address', syncBalance: true, balanceTable: this.balance });
25
+ this.stake = new Table({ name: 'stake', uniqIndex: 'address', syncBalance: true, balanceTable: this.balance });
26
+ this.asset = new Table({ name: 'asset', uniqIndex: 'address' });
27
+ this.delegation = new Table({ name: 'delegation', uniqIndex: 'address' });
28
+ this.tx = new Table({ name: 'tx', uniqIndex: 'hash' });
29
+ this.token = new Token({ name: 'token', uniqIndex: 'address' });
30
+ this.chain = new Table({ name: 'chain', uniqIndex: 'address' });
31
+ this.rollup = new Rollup({ name: 'rollup', uniqIndex: 'address' });
32
+ this.rollupBlock = new Table({ name: 'rollupBlock', uniqIndex: 'hash' });
33
+ this.evidence = new Table({ name: 'evidence', uniqIndex: 'hash' });
27
34
 
28
35
  this.attachReadyListeners();
29
36
  }
@@ -1,27 +1,19 @@
1
1
  const { ensureChecksumAddress } = require('@ocap/state/lib/states/account');
2
- const debug = require('debug')(require('../../package.json').name);
3
2
  const MemoryStateDB = require('./base');
4
3
 
5
4
  class AccountStateDB extends MemoryStateDB {
6
- _get(address, { traceMigration = true } = {}) {
7
- const current = this.collection.by(this.uniqIndex, ensureChecksumAddress(address)) || null;
5
+ async _get(address, { traceMigration = true } = {}) {
6
+ const current = await super._get(ensureChecksumAddress(address));
8
7
  if (current && traceMigration && Array.isArray(current.migratedTo) && current.migratedTo.length) {
9
8
  return this._get(current.migratedTo[0]);
10
9
  }
11
10
 
12
- return current || null;
11
+ return current;
13
12
  }
14
13
 
15
- _create(id, attrs = {}) {
16
- if (this._get(id)) {
17
- throw new Error(`${this.name} already exists: ${id}`);
18
- }
19
-
20
- const newDoc = { [this.uniqIndex]: id, ...attrs };
21
- newDoc[this.uniqIndex] = ensureChecksumAddress(newDoc[this.uniqIndex]);
22
- this.collection.insert(newDoc);
23
- debug(`${this.name} create`, { id, ...attrs });
24
- return this._get(id);
14
+ _create(key, attrs = {}) {
15
+ const address = ensureChecksumAddress(key);
16
+ return super._create(address, { ...attrs, [this.uniqIndex]: address });
25
17
  }
26
18
  }
27
19
 
@@ -0,0 +1,42 @@
1
+ const { ensureChecksumAddress } = require('@ocap/state/lib/states/account');
2
+ const MemoryStateDB = require('./base');
3
+
4
+ class BalanceTable extends MemoryStateDB {
5
+ async getBalance(address) {
6
+ const tokens = await this.collection.find({ address: ensureChecksumAddress(address) });
7
+ return (tokens || []).reduce((acc, token) => {
8
+ acc[token.tokenAddress] = token.balance;
9
+ return acc;
10
+ }, {});
11
+ }
12
+
13
+ async updateBalance({ address, tokens, context = {} }, ctx) {
14
+ if (!Object.keys(tokens).length) return {};
15
+
16
+ const tokenBalances = await this.getBalance(address);
17
+ const updatedTokens = Object.keys(tokens)
18
+ .filter(
19
+ (token) => (tokenBalances[token] && tokenBalances[token] !== '0') || (tokens[token] && tokens[token] !== '0')
20
+ )
21
+ .filter((token) => tokenBalances[token] !== tokens[token]);
22
+
23
+ // eslint-disable-next-line array-callback-return
24
+ await Promise.all(
25
+ updatedTokens.map(async (token) => {
26
+ const key = { address, tokenAddress: token };
27
+
28
+ if (tokenBalances[token]) {
29
+ await this.update(key, { ...key, balance: tokens[token], context }, ctx);
30
+ } else {
31
+ await this.create(key, { ...key, balance: tokens[token], context }, ctx);
32
+ }
33
+
34
+ tokenBalances[token] = tokens[token];
35
+ })
36
+ );
37
+
38
+ return tokens;
39
+ }
40
+ }
41
+
42
+ module.exports = BalanceTable;
package/lib/table/base.js CHANGED
@@ -8,55 +8,122 @@ const db = new Lokijs('ocap-memory-statedb.db');
8
8
  const debug = require('debug')(require('../../package.json').name);
9
9
 
10
10
  class MemoryTable extends StateDBTable {
11
- constructor(name, uniqIndex) {
12
- super();
11
+ /**
12
+ * @param {Object} param
13
+ * @param {string} param.name db name
14
+ * @param {string|string[]} param.uniqIndex primary keys
15
+ * @param {boolean} param.syncBalance sync balance table when create / update / get
16
+ * @param {BalanceTable} param.balanceTable balance table
17
+ */
18
+ constructor({ name, uniqIndex, balanceTable, syncBalance = false }) {
19
+ super(uniqIndex);
13
20
 
14
21
  this.name = name;
15
22
  this.uniqIndex = uniqIndex;
23
+ this.balanceTable = balanceTable;
24
+ this.syncBalance = syncBalance;
16
25
 
17
- this.collection = db.addCollection(name, { unique: [uniqIndex], clone: true });
26
+ if (this.syncBalance && !this.balanceTable) {
27
+ throw new Error('balanceTable is required when syncBalance is true');
28
+ }
29
+
30
+ this.collection = db.addCollection(name, { unique: [this.primaryKey], clone: true });
18
31
  this.markReady();
19
32
  }
20
33
 
21
- _create(id, attrs = {}) {
22
- if (this._get(id)) {
23
- throw new Error(`${this.name} already exists: ${id}`);
34
+ async _create(key, attrs) {
35
+ const id = this.generatePrimaryKey(key);
36
+ // Don't call this._get here cause _get may be overwritten
37
+ const doc = await MemoryTable.prototype._get.call(this, id);
38
+ if (doc) {
39
+ throw new Error(`${this.name} already exists: ${key}`);
40
+ }
41
+
42
+ debug(`insert ${this.name}`, attrs);
43
+
44
+ const insertAttrs = { ...attrs };
45
+ // insert without tokens cause we've migrate token to balance table
46
+ if (this.syncBalance) {
47
+ delete insertAttrs.tokens;
24
48
  }
25
49
 
26
- this.collection.insert({ [this.uniqIndex]: id, ...attrs });
27
- debug(`${this.name} create`, { id, ...attrs });
28
- return this._get(id);
50
+ const result = await this.collection.insert({ [this.primaryKey]: id, ...insertAttrs });
51
+
52
+ if (this.syncBalance && attrs.tokens) {
53
+ debug(`update balance for ${this.name}`, attrs);
54
+
55
+ result.tokens = await this.balanceTable.updateBalance({
56
+ address: attrs.address,
57
+ tokens: attrs.tokens,
58
+ context: attrs.context,
59
+ });
60
+ }
61
+
62
+ return result;
29
63
  }
30
64
 
31
- _get(id) {
32
- return id ? this.collection.by(this.uniqIndex, id) : null;
65
+ async _get(key) {
66
+ if (!key) return null;
67
+
68
+ const id = this.generatePrimaryKey(key);
69
+ const result = await this.collection.by(this.primaryKey, id);
70
+
71
+ if (result && this.syncBalance) {
72
+ const balance = await this.balanceTable.getBalance(result.address);
73
+ result.tokens = { ...(result.tokens || {}), ...balance };
74
+ }
75
+
76
+ return result;
33
77
  }
34
78
 
35
79
  _history() {
36
80
  return [];
37
81
  }
38
82
 
39
- _update(id, updates) {
40
- const doc = this.collection.by(this.uniqIndex, id);
83
+ async _update(key, updates) {
84
+ const id = this.generatePrimaryKey(key);
85
+ // Don't call this._get here cause _get may be overwritten
86
+ const doc = await MemoryTable.prototype._get.call(this, id);
41
87
  if (!doc) {
42
- throw new Error(`${this.name} does not exists: ${id}`);
88
+ throw new Error(`${this.name} does not exists: ${key}`);
43
89
  }
44
90
 
45
91
  Object.assign(doc, updates);
46
- this.collection.update(doc);
92
+
93
+ const updateAttrs = { ...doc };
94
+ // insert without tokens cause we've migrate token to balance table
95
+ if (this.syncBalance) {
96
+ delete updateAttrs.tokens;
97
+ }
98
+
99
+ await this.collection.update(updateAttrs);
100
+
101
+ if (this.syncBalance && doc.tokens) {
102
+ debug(`update balance for ${this.name}`, doc);
103
+
104
+ doc.tokens = await this.balanceTable.updateBalance({
105
+ address: doc.address,
106
+ tokens: doc.tokens,
107
+ context: doc.context,
108
+ });
109
+ }
110
+
47
111
  return doc;
48
112
  }
49
113
 
50
114
  updateOrCreate(exist, state, ctx) {
51
- if (!state[this.uniqIndex]) {
115
+ const id = this.generatePrimaryKey(state);
116
+ const attrs = omit(state, this.uniqIndex);
117
+
118
+ if (!id) {
52
119
  throw new Error('Cannot update or create without uniq index');
53
120
  }
54
121
 
55
122
  if (exist) {
56
- return this.update(state[this.uniqIndex], omit(state, [this.uniqIndex]), ctx);
123
+ return this.update(id, attrs, ctx);
57
124
  }
58
125
 
59
- return this.create(state[this.uniqIndex], omit(state, [this.uniqIndex]), ctx);
126
+ return this.create(id, attrs, ctx);
60
127
  }
61
128
 
62
129
  _reset() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ocap/statedb-memory",
3
3
  "description": "OCAP statedb adapter that uses memory as backend statedb, just for test purpose",
4
- "version": "1.20.15",
4
+ "version": "1.21.0",
5
5
  "author": "wangshijun <shijun@arcblock.io> (https://www.arcblock.io)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/ArcBlock/blockchain/issues",
@@ -36,9 +36,9 @@
36
36
  "debug": "^4.3.6",
37
37
  "lodash": "^4.17.21",
38
38
  "lokijs": "^1.5.12",
39
- "@ocap/statedb": "1.20.15",
40
- "@ocap/util": "1.20.15",
41
- "@ocap/state": "1.20.15"
39
+ "@ocap/statedb": "1.21.0",
40
+ "@ocap/util": "1.21.0",
41
+ "@ocap/state": "1.21.0"
42
42
  },
43
43
  "scripts": {
44
44
  "lint": "eslint tests lib",