trac-msb 0.0.1
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/msb.mjs +15 -0
- package/package.json +34 -0
- package/src/functions.js +26 -0
- package/src/index.js +369 -0
package/msb.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import MainSettlementBus from './src/index.js';
|
|
2
|
+
const opts = {
|
|
3
|
+
stores_directory : 'stores/',
|
|
4
|
+
store_name : process.argv[2],
|
|
5
|
+
bootstrap: '3ad0f48d685fdf10c551e596c48596a99ff373c65845d8827da8b7862a476979',
|
|
6
|
+
channel: Buffer.alloc(32).fill('00botracnetworkmainsettlementbus'),
|
|
7
|
+
tx : Buffer.alloc(32).fill('botracnetworkmainsettlementbustx')
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const msb = new MainSettlementBus(opts);
|
|
11
|
+
|
|
12
|
+
msb.ready().then(() => {
|
|
13
|
+
console.log('MSB is ready.');
|
|
14
|
+
msb.interactiveMode();
|
|
15
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "trac-msb",
|
|
3
|
+
"main": "src/index.js",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"pear": {
|
|
6
|
+
"name": "trac-msb",
|
|
7
|
+
"type": "terminal"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "pear run -d .",
|
|
12
|
+
"test": "brittle test/*.test.js"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"autobase": "7.0.45",
|
|
16
|
+
"b4a": "1.6.7",
|
|
17
|
+
"bare-fs": "4.0.1",
|
|
18
|
+
"brittle": "3.0.0",
|
|
19
|
+
"corestore": "7.0.22",
|
|
20
|
+
"debounceify": "1.1.0",
|
|
21
|
+
"ed25519-key-generator": "file:../ed25519-key-generator",
|
|
22
|
+
"hyperbee": "2.23.0",
|
|
23
|
+
"hypercore": "11.0.48",
|
|
24
|
+
"hypercore-crypto": "3.4.0",
|
|
25
|
+
"hyperdht": "6.19.0",
|
|
26
|
+
"hyperswarm": "4.8.4",
|
|
27
|
+
"is-options": "1.0.2",
|
|
28
|
+
"pear-interface": "1.0.0",
|
|
29
|
+
"protomux-wakeup": "^2.2.1",
|
|
30
|
+
"ready-resource": "^1.0.0",
|
|
31
|
+
"safety-catch": "1.0.2",
|
|
32
|
+
"xache": "1.2.0"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/functions.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import BlindPairing from "blind-pairing";
|
|
2
|
+
|
|
3
|
+
//TODO: if something is missing, add additonal sanitization
|
|
4
|
+
// parsed.op === 'pre-tx' -> moved out of the scope this check because we can re-use this function in the apply
|
|
5
|
+
// TODO: Split sanitization on pre and post TX
|
|
6
|
+
export function sanitizeTransaction(parsedTx) {
|
|
7
|
+
return (
|
|
8
|
+
typeof parsedTx === 'object' &&
|
|
9
|
+
parsedTx !== null &&
|
|
10
|
+
typeof parsedTx.op === 'string' &&
|
|
11
|
+
typeof parsedTx.tx === 'string' &&
|
|
12
|
+
typeof parsedTx.w === 'string' &&
|
|
13
|
+
typeof parsedTx.i === 'string' &&
|
|
14
|
+
typeof parsedTx.ipk === 'string' &&
|
|
15
|
+
typeof parsedTx.is === 'string'
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function addWriter(input, peer){
|
|
20
|
+
const splitted = input.split(' ');
|
|
21
|
+
if(splitted[0] === '/add_writer'){
|
|
22
|
+
await peer.base.append({ type: 'addWriter', key: splitted[splitted.length - 1] });
|
|
23
|
+
} else if(splitted[0] === '/add_writer2') {
|
|
24
|
+
await peer.base.append({ type: 'addWriter2', key: splitted[splitted.length - 1] });
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
/** @typedef {import('pear-interface')} */ /* global Pear */
|
|
2
|
+
import Autobase from 'autobase';
|
|
3
|
+
import Hyperswarm from 'hyperswarm';
|
|
4
|
+
import ReadyResource from 'ready-resource';
|
|
5
|
+
import b4a from 'b4a';
|
|
6
|
+
import Hyperbee from 'hyperbee';
|
|
7
|
+
import readline from 'readline';
|
|
8
|
+
import crypto from 'hypercore-crypto';
|
|
9
|
+
import { sanitizeTransaction, addWriter } from './functions.js';
|
|
10
|
+
import w from 'protomux-wakeup';
|
|
11
|
+
import * as edKeyGen from "ed25519-key-generator"
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import Corestore from 'corestore';
|
|
14
|
+
|
|
15
|
+
const wakeup = new w();
|
|
16
|
+
|
|
17
|
+
export class MainSettlementBus extends ReadyResource {
|
|
18
|
+
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
super();
|
|
21
|
+
this.STORES_DIRECTORY = options.stores_directory;
|
|
22
|
+
this.KEY_PAIR_PATH = `${this.STORES_DIRECTORY}${options.store_name}/keypair.json`
|
|
23
|
+
this.signingKeyPair = null;
|
|
24
|
+
this.store = new Corestore(this.STORES_DIRECTORY + options.store_name);
|
|
25
|
+
this.swarm = null;
|
|
26
|
+
this.tx = options.tx || null;
|
|
27
|
+
this.tx_pool = [];
|
|
28
|
+
this.enable_txchannel = typeof options.enable_txchannel !== "undefined" && options.enable_txchannel === false ? false : true;
|
|
29
|
+
this.enable_wallet = typeof options.enable_wallet !== "undefined" && options.enable_wallet === false ? false : true;
|
|
30
|
+
this.base = null;
|
|
31
|
+
this.key = null;
|
|
32
|
+
this.channel = options.channel || null;
|
|
33
|
+
this.connectedNodes = 1;
|
|
34
|
+
this.replicate = options.replicate !== false;
|
|
35
|
+
this.writerLocalKey = null;
|
|
36
|
+
this.isStreaming = false;
|
|
37
|
+
this.bootstrap = options.bootstrap || null;
|
|
38
|
+
this.opts = options;
|
|
39
|
+
this.connectedPeers = new Set();
|
|
40
|
+
this.bee = null;
|
|
41
|
+
|
|
42
|
+
this.pool();
|
|
43
|
+
this.msbListener();
|
|
44
|
+
this._boot();
|
|
45
|
+
this.ready().catch(noop);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_boot() {
|
|
49
|
+
const _this = this;
|
|
50
|
+
this.base = new Autobase(this.store, this.bootstrap, {
|
|
51
|
+
valueEncoding: 'json',
|
|
52
|
+
|
|
53
|
+
open(store) {
|
|
54
|
+
_this.bee = new Hyperbee(store.get('view'), {
|
|
55
|
+
extension: false,
|
|
56
|
+
keyEncoding: 'utf-8',
|
|
57
|
+
valueEncoding: 'json'
|
|
58
|
+
})
|
|
59
|
+
return _this.bee;
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
apply: async (nodes, view, base) => {
|
|
63
|
+
|
|
64
|
+
for (const node of nodes) {
|
|
65
|
+
const op = node.value;
|
|
66
|
+
const postTx = op.value;
|
|
67
|
+
if (op.type === 'tx') {
|
|
68
|
+
if (null === await view.get(op.key) &&
|
|
69
|
+
sanitizeTransaction(postTx) &&
|
|
70
|
+
postTx.op === 'post-tx' &&
|
|
71
|
+
crypto.verify(Buffer.from(postTx.tx, 'utf-8'), Buffer.from(postTx.is, 'hex'), Buffer.from(postTx.ipk, 'hex')) &&// sender verification
|
|
72
|
+
crypto.verify(Buffer.from(postTx.tx, 'utf-8'), Buffer.from(postTx.ws, 'hex'), Buffer.from(postTx.wp, 'hex')) &&// writer verification
|
|
73
|
+
Buffer.byteLength(JSON.stringify(postTx)) <= 4096
|
|
74
|
+
) {
|
|
75
|
+
await view.put(op.key, op.value);
|
|
76
|
+
console.log(`TX: ${op.key} appended. Signed length: `, _this.base.view.core.signedLength);
|
|
77
|
+
}
|
|
78
|
+
} else if (op.type === 'addWriter') {
|
|
79
|
+
const writerKey = b4a.from(op.key, 'hex');
|
|
80
|
+
await base.addWriter(writerKey);
|
|
81
|
+
console.log(`Writer added: ${op.key}`);
|
|
82
|
+
} else if (op.type === 'addWriter2') {
|
|
83
|
+
const writerKey = b4a.from(op.key, 'hex');
|
|
84
|
+
await base.addWriter(writerKey, { isIndexer : false });
|
|
85
|
+
console.log(`Writer added: ${op.key} non-indexer`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
this.base.on('warning', (e) => console.log(e))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async _open() {
|
|
94
|
+
await this.base.ready();
|
|
95
|
+
if(this.enable_wallet){
|
|
96
|
+
await this.#initKeyPair();
|
|
97
|
+
}
|
|
98
|
+
console.log('View Length:', this.base.view.core.length);
|
|
99
|
+
console.log('View Signed Length:', this.base.view.core.signedLength);
|
|
100
|
+
console.log('MSB Key:', Buffer(this.base.view.core.key).toString('hex'));
|
|
101
|
+
this.writerLocalKey = b4a.toString(this.base.local.key, 'hex');
|
|
102
|
+
if (this.replicate) await this._replicate();
|
|
103
|
+
if (this.enable_txchannel) {
|
|
104
|
+
await this.txChannel();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async close() {
|
|
109
|
+
if (this.swarm) {
|
|
110
|
+
await this.swarm.destroy();
|
|
111
|
+
}
|
|
112
|
+
await this.base.close();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async txChannel() {
|
|
116
|
+
this.tx_swarm = new Hyperswarm({ maxPeers: 1024, maxParallel: 512, maxServerConnections: 256 });
|
|
117
|
+
this.tx_swarm.on('connection', async (connection, peerInfo) => {
|
|
118
|
+
const _this = this;
|
|
119
|
+
const peerName = b4a.toString(connection.remotePublicKey, 'hex');
|
|
120
|
+
this.connectedPeers.add(peerName);
|
|
121
|
+
this.connectedNodes++;
|
|
122
|
+
|
|
123
|
+
connection.on('close', () => {
|
|
124
|
+
this.connectedNodes--;
|
|
125
|
+
this.connectedPeers.delete(peerName);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
connection.on('error', (error) => { });
|
|
129
|
+
|
|
130
|
+
connection.on('data', async (msg) => {
|
|
131
|
+
|
|
132
|
+
if(_this.base.isIndexer) return;
|
|
133
|
+
|
|
134
|
+
// TODO: decide if a tx rejection should be responded with
|
|
135
|
+
if(_this.tx_pool.length >= 1000) {
|
|
136
|
+
console.log('pool full');
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if(Buffer.byteLength(msg) > 3072) return;
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
|
|
144
|
+
const parsedPreTx = JSON.parse(msg);
|
|
145
|
+
|
|
146
|
+
if (sanitizeTransaction(parsedPreTx) &&
|
|
147
|
+
parsedPreTx.op === 'pre-tx' &&
|
|
148
|
+
crypto.verify(Buffer.from(parsedPreTx.tx, 'utf-8'), Buffer.from(parsedPreTx.is, 'hex'), Buffer.from(parsedPreTx.ipk, 'hex')) &&
|
|
149
|
+
parsedPreTx.w === _this.writerLocalKey &&
|
|
150
|
+
null === await _this.base.view.get(parsedPreTx.tx)
|
|
151
|
+
) {
|
|
152
|
+
const signature = crypto.sign(Buffer.from(parsedPreTx.tx, 'utf-8'), this.signingKeyPair.secretKey);
|
|
153
|
+
const append_tx = {
|
|
154
|
+
op: 'post-tx',
|
|
155
|
+
tx: parsedPreTx.tx,
|
|
156
|
+
is: parsedPreTx.is,
|
|
157
|
+
w: parsedPreTx.w,
|
|
158
|
+
i: parsedPreTx.i,
|
|
159
|
+
ipk: parsedPreTx.ipk,
|
|
160
|
+
ch: parsedPreTx.ch,
|
|
161
|
+
in: parsedPreTx.in,
|
|
162
|
+
ws: signature.toString('hex'),
|
|
163
|
+
wp: this.signingKeyPair.publicKey.toString('hex'),
|
|
164
|
+
};
|
|
165
|
+
_this.tx_pool.push({ tx: parsedPreTx.tx, append_tx : append_tx });
|
|
166
|
+
}
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.log(e)
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const channelBuffer = this.tx;
|
|
174
|
+
this.tx_swarm.join(channelBuffer, { server: true, client: true });
|
|
175
|
+
await this.tx_swarm.flush();
|
|
176
|
+
console.log('Joined MSB TX channel');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async pool(){
|
|
180
|
+
while(true){
|
|
181
|
+
if(this.tx_pool.length > 0){
|
|
182
|
+
const length = this.tx_pool.length;
|
|
183
|
+
for(let i = 0; i < length; i++){
|
|
184
|
+
await this.base.append({ type: 'tx', key: this.tx_pool[i].tx, value: this.tx_pool[i].append_tx });
|
|
185
|
+
await this.sleep(5);
|
|
186
|
+
}
|
|
187
|
+
this.tx_pool.splice(0, length);
|
|
188
|
+
}
|
|
189
|
+
await this.sleep(10);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async sleep(ms) {
|
|
194
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async _replicate() {
|
|
198
|
+
if (!this.swarm) {
|
|
199
|
+
const keyPair = await this.store.createKeyPair('hyperswarm');
|
|
200
|
+
this.swarm = new Hyperswarm({ keyPair, maxPeers: 1024, maxParallel: 512, maxServerConnections: 256 });
|
|
201
|
+
|
|
202
|
+
console.log(`Channel: ${this.channel}`);
|
|
203
|
+
console.log(`Writer key: ${this.writerLocalKey}`)
|
|
204
|
+
console.log(`isIndexer: ${this.base.isIndexer}`);
|
|
205
|
+
this.swarm.on('connection', async (connection, peerInfo) => {
|
|
206
|
+
const peerName = b4a.toString(connection.remotePublicKey, 'hex');
|
|
207
|
+
this.connectedPeers.add(peerName);
|
|
208
|
+
wakeup.addStream(connection);
|
|
209
|
+
this.store.replicate(connection);
|
|
210
|
+
this.connectedNodes++;
|
|
211
|
+
|
|
212
|
+
connection.on('close', () => {
|
|
213
|
+
this.connectedNodes--;
|
|
214
|
+
this.connectedPeers.delete(peerName);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
connection.on('error', (error) => { });
|
|
218
|
+
|
|
219
|
+
if (!this.isStreaming) {
|
|
220
|
+
this.emit('readyMsb');
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const channelBuffer = this.channel
|
|
225
|
+
this.swarm.join(channelBuffer, { server: true, client: true });
|
|
226
|
+
await this.swarm.flush();
|
|
227
|
+
console.log('Joined channel for peer discovery');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
msbListener() {
|
|
232
|
+
this.on('readyMsb', async () => {
|
|
233
|
+
if (!this.isStreaming) {
|
|
234
|
+
this.isStreaming = true;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async verifyDag() {
|
|
240
|
+
try {
|
|
241
|
+
console.log('--- DAG Monitoring ---');
|
|
242
|
+
const dagView = await this.base.view.core.treeHash();
|
|
243
|
+
const lengthdagView = this.base.view.core.length;
|
|
244
|
+
const dagSystem = await this.base.system.core.treeHash();
|
|
245
|
+
const lengthdagSystem = this.base.system.core.length;
|
|
246
|
+
console.log('this.base.view.core.signedLength:', this.base.view.core.signedLength);
|
|
247
|
+
console.log("this.base.signedLength", this.base.signedLength);
|
|
248
|
+
console.log("this.base.linearizer.indexers.length", this.base.linearizer.indexers.length);
|
|
249
|
+
console.log("this.base.indexedLength", this.base.indexedLength);
|
|
250
|
+
//console.log("this.base.system.core", this.base.system.core);
|
|
251
|
+
console.log(`writerLocalKey: ${this.writerLocalKey}`);
|
|
252
|
+
console.log(`base.key: ${this.base.key.toString('hex')}`);
|
|
253
|
+
console.log('discoveryKey:', b4a.toString(this.base.discoveryKey, 'hex'));
|
|
254
|
+
|
|
255
|
+
console.log(`VIEW Dag: ${dagView.toString('hex')} (length: ${lengthdagView})`);
|
|
256
|
+
console.log(`SYSTEM Dag: ${dagSystem.toString('hex')} (length: ${lengthdagSystem})`);
|
|
257
|
+
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error('Error during DAG monitoring:', error.message);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async interactiveMode() {
|
|
264
|
+
const rl = readline.createInterface({
|
|
265
|
+
input: process.stdin,
|
|
266
|
+
output: process.stdout,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
console.log('MSB started. Available commands:');
|
|
270
|
+
console.log('- /add_writer: enter a peer writer key as argument to get included as writer.');
|
|
271
|
+
console.log('- /add_writer2: enter a peer writer key as argument to get included as non-indexing writer.');
|
|
272
|
+
console.log('- /dag: check system properties such as writer key, DAG, etc.');
|
|
273
|
+
console.log('- /exit: Exit the program');
|
|
274
|
+
|
|
275
|
+
rl.on('line', async (input) => {
|
|
276
|
+
switch (input) {
|
|
277
|
+
case '/dag':
|
|
278
|
+
await this.verifyDag();
|
|
279
|
+
break;
|
|
280
|
+
case '/exit':
|
|
281
|
+
console.log('Exiting...');
|
|
282
|
+
rl.close();
|
|
283
|
+
await this.close();
|
|
284
|
+
process.exit(0);
|
|
285
|
+
break;
|
|
286
|
+
default:
|
|
287
|
+
if (input.startsWith('/add_writer')) {
|
|
288
|
+
await addWriter(input, this);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
rl.prompt();
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
rl.prompt();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async #getMnemonicInteractiveMode() {
|
|
298
|
+
const rl = readline.createInterface({
|
|
299
|
+
input: process.stdin,
|
|
300
|
+
output: process.stdout
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const question = (query) => {
|
|
304
|
+
return new Promise(resolve => {
|
|
305
|
+
rl.question(query, resolve);
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
let mnemonic;
|
|
310
|
+
let choice = '';
|
|
311
|
+
while (!choice.trim()) {
|
|
312
|
+
choice = await question("[1]. Generate new mnemonic phrase\n[2]. Restore keypair from backed up mnemonic phrase\nYour choice (1/2): ");
|
|
313
|
+
switch (choice) {
|
|
314
|
+
case '1':
|
|
315
|
+
mnemonic = undefined
|
|
316
|
+
break;
|
|
317
|
+
case '2':
|
|
318
|
+
const mnemonicInput = await question("Enter your mnemonic phrase: ");
|
|
319
|
+
mnemonic = edKeyGen.sanitizeMnemonic(mnemonicInput);
|
|
320
|
+
break;
|
|
321
|
+
default:
|
|
322
|
+
console.log("Invalid choice. Please select again");
|
|
323
|
+
choice = '';
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
rl.close();
|
|
328
|
+
return mnemonic;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async #initKeyPair() {
|
|
332
|
+
// TODO: User shouldn't be allowed to store it in unencrypted form. ASK for a password to encrypt it. ENCRYPT(HASH(PASSWORD,SALT),FILE)/DECRYPT(HASH(PASSWORD,SALT),ENCRYPTED_FILE)?
|
|
333
|
+
try {
|
|
334
|
+
// Check if the key file exists
|
|
335
|
+
if (fs.existsSync(this.KEY_PAIR_PATH)) {
|
|
336
|
+
const keyPair = JSON.parse(fs.readFileSync(this.KEY_PAIR_PATH));
|
|
337
|
+
this.signingKeyPair = {
|
|
338
|
+
publicKey: Buffer.from(keyPair.publicKey, 'hex'),
|
|
339
|
+
secretKey: Buffer.from(keyPair.secretKey, 'hex')
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
console.log("Key file was not found. How do you wish to proceed?");
|
|
343
|
+
const mnemonic = await this.#getMnemonicInteractiveMode();
|
|
344
|
+
|
|
345
|
+
const generatedSecrets = edKeyGen.generateKeyPair(mnemonic);
|
|
346
|
+
const keyPair = {
|
|
347
|
+
publicKey: Buffer.from(generatedSecrets.publicKey).toString('hex'),
|
|
348
|
+
secretKey: Buffer.from(generatedSecrets.secretKey).toString('hex')
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
//TODO: ASK USER TO WRITE FIRST SECOND AND LAST WORD OR SOMETHING SIMILAR TO CONFIRM THEY HAVE WRITTEN IT DOWN
|
|
352
|
+
if (!mnemonic) console.log("This is your mnemonic:\n", generatedSecrets.mnemonic, "\nPlease back it up in a safe location")
|
|
353
|
+
|
|
354
|
+
fs.writeFileSync(this.KEY_PAIR_PATH, JSON.stringify(keyPair));
|
|
355
|
+
this.signingKeyPair = {
|
|
356
|
+
publicKey: generatedSecrets.publicKey,
|
|
357
|
+
secretKey: generatedSecrets.secretKey,
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
console.log("DEBUG: Key pair generated and stored in", this.KEY_PAIR_PATH);
|
|
361
|
+
}
|
|
362
|
+
} catch (err) {
|
|
363
|
+
console.error(err);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function noop() { }
|
|
369
|
+
export default MainSettlementBus;
|