trac-msb 0.1.76 → 0.1.78

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.
@@ -1,295 +0,0 @@
1
- import w from 'protomux-wakeup';
2
- import b4a from 'b4a';
3
- import Hyperswarm from 'hyperswarm';
4
- import {
5
- EventType,
6
- TRAC_NAMESPACE,
7
- MAX_PEERS,
8
- MAX_PARALLEL,
9
- MAX_SERVER_CONNECTIONS,
10
- MAX_CLIENT_CONNECTIONS,
11
- OperationType,
12
- EntryType
13
- } from './utils/constants.js';
14
- import { sleep } from './utils/functions.js';
15
- import Check from './utils/check.js';
16
- import Wallet from 'trac-wallet';
17
- import Protomux from 'protomux'
18
- import c from 'compact-encoding'
19
-
20
- const wakeup = new w();
21
-
22
- class Network {
23
- constructor(base) {
24
- this.tx_pool = [];
25
- this.pool(base);
26
- this.check = new Check();
27
- this.admin_stream = null
28
- this.admin = null
29
- this.validator_stream = null
30
- this.validator = null;
31
- this.custom_stream = null;
32
- this.custom_node = null
33
- }
34
-
35
- static async replicate(disable_rate_limit, msb, network, enable_txchannel, base, writingKey, bootstrap, swarm, walletEnabled, store, wallet, channel, isStreaming, handleIncomingEvent, emit) {
36
- if (!swarm) {
37
-
38
- let keyPair;
39
- if (!walletEnabled) {
40
- keyPair = await store.createKeyPair(TRAC_NAMESPACE);
41
- } else {
42
- keyPair = {
43
- publicKey: b4a.from(wallet.publicKey, 'hex'),
44
- secretKey: b4a.from(wallet.secretKey, 'hex')
45
- };
46
- }
47
-
48
- let clean = Date.now();
49
- let conns = {};
50
-
51
- swarm = new Hyperswarm({ keyPair, bootstrap : bootstrap, maxPeers: MAX_PEERS, maxParallel: MAX_PARALLEL, maxServerConnections: MAX_SERVER_CONNECTIONS, maxClientConnections : MAX_CLIENT_CONNECTIONS});
52
-
53
- console.log(`Channel: ${b4a.toString(channel)}`);
54
- swarm.on('connection', async (connection) => {
55
-
56
- const mux = Protomux.from(connection)
57
- connection.userData = mux
58
-
59
- const message_channel = mux.createChannel({
60
- protocol: b4a.toString(channel, 'utf8'),
61
- onopen() {
62
- },
63
- onclose() {
64
- }
65
- })
66
- message_channel.open()
67
- const message = message_channel.addMessage({
68
- encoding: c.json,
69
- async onmessage(msg) {
70
- try {
71
-
72
- if (msg === 'get_validator') {
73
- const nonce = Wallet.generateNonce().toString('hex');
74
- const _msg = {
75
- op: 'validator',
76
- key: writingKey,
77
- address: wallet.publicKey,
78
- channel: b4a.toString(channel, 'utf8')
79
- };
80
- const sig = wallet.sign(JSON.stringify(_msg) + nonce);
81
- message.send({response: _msg, sig, nonce})
82
- swarm.leavePeer(connection.remotePublicKey)
83
- } else if (msg === 'get_admin') {
84
- const res = await msb.get(EntryType.ADMIN);
85
- if (wallet.publicKey !== res.tracPublicKey) return;
86
- const nonce = Wallet.generateNonce().toString('hex');
87
- const _msg = {
88
- op: 'admin',
89
- key: writingKey,
90
- address: wallet.publicKey,
91
- channel: b4a.toString(channel, 'utf8')
92
- };
93
- const sig = wallet.sign(JSON.stringify(_msg) + nonce);
94
- message.send({response: _msg, sig, nonce})
95
- swarm.leavePeer(connection.remotePublicKey)
96
- } else if (msg === 'get_node') {
97
-
98
- const nonce = Wallet.generateNonce().toString('hex');
99
- const _msg = {
100
- op: 'node',
101
- key: writingKey,
102
- address: wallet.publicKey,
103
- channel: b4a.toString(channel, 'utf8')
104
- };
105
- const sig = wallet.sign(JSON.stringify(_msg) + nonce);
106
- message.send({response: _msg, sig, nonce})
107
- swarm.leavePeer(connection.remotePublicKey)
108
-
109
- } else if (msg.response !== undefined && msg.response.op !== undefined && msg.response.op === 'validator') {
110
- const res = await msb.get(msg.response.address);
111
- if (res === null) return;
112
- const verified = wallet.verify(msg.sig, JSON.stringify(msg.response) + msg.nonce, msg.response.address)
113
- if (verified && msg.response.channel === b4a.toString(channel, 'utf8') && network.validator_stream === null) {
114
- console.log('Validator stream established', msg.response.address)
115
- network.validator_stream = connection;
116
- network.validator = msg.response.address;
117
- }
118
- swarm.leavePeer(connection.remotePublicKey)
119
- } else if (msg.response !== undefined && msg.response.op !== undefined && msg.response.op === 'admin') {
120
- const res = await msb.get(EntryType.ADMIN);
121
- if (res === null || res.tracPublicKey !== msg.response.address) return;
122
- const verified = wallet.verify(msg.sig, JSON.stringify(msg.response) + msg.nonce, res.tracPublicKey)
123
- if (verified && msg.response.channel === b4a.toString(channel, 'utf8')) {
124
- console.log('Admin stream established', res.tracPublicKey)
125
- network.admin_stream = connection;
126
- network.admin = res.tracPublicKey;
127
- }
128
- swarm.leavePeer(connection.remotePublicKey)
129
- }
130
- else if (msg.response !== undefined && msg.response.op !== undefined && msg.response.op === 'node'){
131
-
132
- const verified = wallet.verify(msg.sig, JSON.stringify(msg.response) + msg.nonce, msg.response.address)
133
- if (verified && msg.response.channel === b4a.toString(channel, 'utf8')) {
134
-
135
- console.log('Node stream established', msg.response.address)
136
- network.custom_stream = connection;
137
- network.custom_node = msg.response.address;
138
- }
139
- swarm.leavePeer(connection.remotePublicKey)
140
- } else if (msg.type !== undefined && msg.key !== undefined && msg.value !== undefined && msg.type === 'addWriter') {
141
- const adminEntry = await msb.get(EntryType.ADMIN);
142
- if (null === adminEntry || (adminEntry.tracPublicKey !== wallet.publicKey)) return;
143
- const nodeEntry = await msb.get(msg.value.pub);
144
- const isAlreadyWriter = null !== nodeEntry && nodeEntry.isWriter;
145
- const isAllowedToRequestRole = await msb._isAllowedToRequestRole(msg.key, adminEntry);
146
- const canAddWriter = base.writable && !isAlreadyWriter && isAllowedToRequestRole;
147
- if (msg.key !== wallet.publicKey && canAddWriter) {
148
- await handleIncomingEvent(msg);
149
- }
150
- swarm.leavePeer(connection.remotePublicKey)
151
- } else if (msg.type !== undefined && msg.key !== undefined && msg.value !== undefined && msg.type === 'removeWriter') {
152
- const adminEntry = await msb.get(EntryType.ADMIN);
153
- if (null === adminEntry || (adminEntry.tracPublicKey !== wallet.publicKey)) return;
154
- const nodeEntry = await msb.get(msg.value.pub);
155
- const isAlreadyWriter = null !== nodeEntry && nodeEntry.isWriter;
156
- const canRemoveWriter = base.writable && isAlreadyWriter
157
- if (msg.key !== wallet.publicKey && canRemoveWriter) {
158
- await handleIncomingEvent(msg);
159
- }
160
- swarm.leavePeer(connection.remotePublicKey)
161
- } else if (msg.type !== undefined && msg.key !== undefined && msg.value !== undefined && msg.type === 'addAdmin') {
162
- const adminEntry = await msb.get(EntryType.ADMIN);
163
- if (null === adminEntry || (adminEntry.tracPublicKey !== msg.key)) return;
164
- await handleIncomingEvent(msg);
165
- swarm.leavePeer(connection.remotePublicKey)
166
- }
167
- else if (msg.type !== undefined && msg.key !== undefined && msg.value !== undefined && msg.type === 'whitelisted') {
168
- await handleIncomingEvent(msg);
169
- swarm.leavePeer(connection.remotePublicKey)
170
- } else {
171
- if (base.isIndexer || !base.writable) return;
172
-
173
- if (true !== disable_rate_limit) {
174
- const peer = b4a.toString(connection.remotePublicKey, 'hex');
175
- const _now = Date.now();
176
-
177
- if (_now - clean >= 120_000) {
178
- clean = _now;
179
- conns = {};
180
- }
181
-
182
- if (conns[peer] === undefined) {
183
- conns[peer] = {prev: _now, now: 0, tx_cnt: 0}
184
- }
185
-
186
- conns[peer].now = _now;
187
- conns[peer].tx_cnt += 1;
188
-
189
- if (conns[peer].now - conns[peer].prev >= 60_000) {
190
- delete conns[peer];
191
- }
192
-
193
- if (conns[peer] !== undefined && conns[peer].now - conns[peer].prev >= 1000 && conns[peer].tx_cnt >= 50) {
194
- swarm.leavePeer(connection.remotePublicKey);
195
- connection.end()
196
- }
197
- }
198
-
199
- if (network.tx_pool.length >= 1000) {
200
- console.log('pool full');
201
- return
202
- }
203
-
204
- if (b4a.byteLength(JSON.stringify(msg)) > 3072) return;
205
-
206
- const parsedPreTx = msg;
207
-
208
- if (network.check.sanitizePreTx(parsedPreTx) &&
209
- wallet.verify(b4a.from(parsedPreTx.is, 'hex'), b4a.from(parsedPreTx.tx + parsedPreTx.in), b4a.from(parsedPreTx.ipk, 'hex')) &&
210
- parsedPreTx.wp === wallet.publicKey &&
211
- null === await base.view.get(parsedPreTx.tx)
212
- ) {
213
- const nonce = Wallet.generateNonce().toString('hex');
214
- const signature = wallet.sign(b4a.from(parsedPreTx.tx + nonce), b4a.from(wallet.secretKey, 'hex'));
215
- const append_tx = {
216
- op: OperationType.POST_TX,
217
- tx: parsedPreTx.tx,
218
- is: parsedPreTx.is,
219
- w: writingKey,
220
- i: parsedPreTx.i,
221
- ipk: parsedPreTx.ipk,
222
- ch: parsedPreTx.ch,
223
- in: parsedPreTx.in,
224
- bs: parsedPreTx.bs,
225
- mbs: parsedPreTx.mbs,
226
- ws: signature.toString('hex'),
227
- wp: wallet.publicKey,
228
- wn: nonce
229
- };
230
- network.tx_pool.push({tx: parsedPreTx.tx, append_tx: append_tx});
231
- }
232
-
233
- swarm.leavePeer(connection.remotePublicKey)
234
- }
235
- } catch (e) {
236
- console.log(e);
237
- }
238
- }
239
- })
240
-
241
- connection.messenger = message;
242
-
243
- connection.on('close', () => {
244
- if (network.validator_stream === connection) {
245
- network.validator_stream = null;
246
- network.validator = null;
247
- }
248
- if (network.admin_stream === connection) {
249
- network.admin_stream = null;
250
- network.admin = null;
251
- }
252
-
253
- if (network.custom_stream === connection) {
254
- network.custom_stream = null;
255
- network.custom_node = null;
256
- }
257
-
258
- message_channel.close()
259
- });
260
-
261
- // must be called AFTER the protomux init above
262
- const stream = store.replicate(connection);
263
- wakeup.addStream(stream);
264
-
265
- connection.on('error', (error) => { });
266
-
267
- if (!isStreaming) {
268
- emit(EventType.READY_MSB);
269
- }
270
- });
271
-
272
- swarm.join(channel, { server: true, client: true });
273
- await swarm.flush();
274
- }
275
- return swarm;
276
- }
277
-
278
- async pool(base) {
279
- while (true) {
280
- if (this.tx_pool.length > 0) {
281
- const length = this.tx_pool.length;
282
- const batch = [];
283
- for (let i = 0; i < length; i++) {
284
- if (i >= 10) break;
285
- batch.push({ type: OperationType.TX, key: this.tx_pool[i].tx, value: this.tx_pool[i].append_tx });
286
- }
287
- await base.append(batch);
288
- this.tx_pool.splice(0, batch.length);
289
- }
290
- await sleep(5);
291
- }
292
- }
293
- }
294
-
295
- export default Network;
@@ -1,163 +0,0 @@
1
- import Validator from 'fastest-validator';
2
- import { isHexString } from './functions.js';
3
- import {OperationType} from './constants.js';
4
- class Check {
5
- #_validator;
6
- #_sanitizeAdminAndWritersOperations;
7
- #_sanitizeIndexerOrWhitelistOperations;
8
- #_sanitizePreTx;
9
- #_sanitizePostTx;
10
-
11
- constructor() {
12
- this.#_validator = new Validator({
13
- useNewCustomCheckerFunction: true,
14
- messages: {
15
- bufferedHex: "The '{field}' field must be a hex! Actual: {actual}",
16
- hexString: "The '{field}' field must be a valid hex string! Actual: {actual}"
17
- },
18
- customFunctions: {
19
- hexCheck: (value, errors) => {
20
- let buf = null;
21
- let result = false;
22
- try {
23
- buf = b4a.from(value, 'hex');
24
- result = value === b4a.toString(buf, 'hex');
25
- } catch (e) {
26
- }
27
- return result;
28
- },
29
- hexStringCheck: (value, errors) => {
30
- try {
31
- return isHexString(value);
32
- } catch (e) {
33
- }
34
- return false;
35
- }
36
- }
37
- });
38
-
39
- this.#_validator.add("is_hex", function ({ schema, messages }, path, context) {
40
- return {
41
- source: `
42
- const result = context.customFunctions.hexCheck(value, errors);
43
- if(false === result) ${this.makeError({ type: "bufferedHex", actual: "value", messages })}
44
- return value;
45
- `
46
- };
47
- });
48
-
49
- this.#_validator.add("is_hex_string", function ({ schema, messages }, path, context) {
50
- return {
51
- source: `
52
- const result = context.customFunctions.hexStringCheck(value, errors);
53
- if(false === result) ${this.makeError({ type: "hexString", actual: "value", messages })}
54
- return value;
55
- `
56
- };
57
- });
58
-
59
- this.#_sanitizeAdminAndWritersOperations = this.#compileSanitizationAdminAndWriterOperationsSchema();
60
- this.#_sanitizeIndexerOrWhitelistOperations = this.#compileIndexerOrWhitelistOperationSchema();
61
- this.#_sanitizePreTx = this.#compilePreTxSchema();
62
- this.#_sanitizePostTx = this.#compilePostTxSchema();
63
- }
64
- //TODO: rename this function
65
- #compileSanitizationAdminAndWriterOperationsSchema() {
66
- // TODO: Create constants for int values below
67
- const schema = {
68
- $$strict: true,
69
- type: { type: 'string', enum: [OperationType.ADD_ADMIN, OperationType.ADD_WRITER, OperationType.REMOVE_WRITER], required: true },
70
- key: { type: "is_hex_string", length: 64, required: true },
71
- value: {
72
- $$strict: true,
73
- $$type: "object",
74
- pub: { type: 'is_hex_string', length: 64, required: true },
75
- wk: { type: 'is_hex_string', length: 64, required: true },
76
- nonce: { type: 'is_hex_string', length: 64, required: true },
77
- sig: { type: 'is_hex_string', length: 128, required: true },
78
-
79
- }
80
- }
81
- return this.#_validator.compile(schema);
82
- }
83
-
84
- sanitizeAdminAndWritersOperations(op) {
85
- return this.#_sanitizeAdminAndWritersOperations(op) === true;
86
- }
87
- //TODO: rename this function
88
- #compileIndexerOrWhitelistOperationSchema() {
89
- // TODO: Create constants for int values below
90
- const schema = {
91
- $$strict: true,
92
- type: { type: 'string', enum: [OperationType.ADD_INDEXER, OperationType.REMOVE_INDEXER, OperationType.APPEND_WHITELIST, OperationType.BAN_VALIDATOR], required: true },
93
- key: { type: "is_hex_string", length: 64, required: true },
94
- value: {
95
- $$strict: true,
96
- $$type: "object",
97
- nonce: { type: 'is_hex_string', length: 64, required: true },
98
- sig: { type: 'is_hex_string', length: 128, required: true },
99
-
100
- }
101
- }
102
- return this.#_validator.compile(schema);
103
- }
104
-
105
- sanitizeIndexerOrWhitelistOperations(op) {
106
- return this.#_sanitizeIndexerOrWhitelistOperations(op) === true;
107
- }
108
-
109
- #compilePreTxSchema() {
110
- // TODO: Create constants for int values below
111
- const schema = {
112
- $$strict: true,
113
- op: { type: 'string', enum: ['pre-tx'], required: true },
114
- tx: { type: 'is_hex_string', required: true }, // TODO: if we will use only 256 bit hash then change to length: 64
115
- is: { type: 'is_hex_string', length: 128, required: true },
116
- wp: { type: 'is_hex_string', length: 64, required: true },
117
- i: { type: 'is_hex_string', length: 64, required: true },
118
- ipk: { type: 'is_hex_string', length: 64, required: true },
119
- ch: { type: 'is_hex_string', required: true }, // TODO: if we will use only 256 bit hash then change to length: 64
120
- in: { type: 'is_hex_string', length: 64, required: true },
121
- bs: { type: 'is_hex_string', length: 64, required: true },
122
- mbs: { type: 'is_hex_string', length: 64, required: true },
123
- };
124
- return this.#_validator.compile(schema);
125
- }
126
-
127
- sanitizePreTx(op) {
128
- return this.#_sanitizePreTx(op) === true;
129
- }
130
-
131
- #compilePostTxSchema() {
132
- // TODO: Create constants for int values below
133
- const schema = {
134
- $$strict: true,
135
- type: { type: 'string', enum: ['tx'], required: true },
136
- key: { type: 'is_hex_string', required: true }, // TODO: if we will use only 256 bit hash then change to length: 64
137
- value: {
138
- $$strict: true,
139
- $$type: "object",
140
- op: { type: 'string', enum: ['post-tx'], required: true },
141
- tx: { type: 'is_hex_string', required: true }, // TODO: if we will use only 256 bit hash then change to length: 64
142
- is: { type: 'is_hex_string', length: 128, required: true },
143
- w: { type: 'is_hex_string', length: 64, required: true },
144
- i: { type: 'is_hex_string', length: 64, required: true },
145
- ipk: { type: 'is_hex_string', length: 64, required: true },
146
- ch: { type: 'is_hex_string', required: true }, // TODO: if we will use only 256 bit hash then change to length: 64
147
- in: { type: 'is_hex_string', length: 64, required: true },
148
- bs: { type: 'is_hex_string', length: 64, required: true },
149
- mbs: { type: 'is_hex_string', length: 64, required: true },
150
- ws: { type: 'is_hex_string', length: 128, required: true },
151
- wp: { type: 'is_hex_string', length: 64, required: true },
152
- wn: { type: 'is_hex_string', length: 64, required: true }
153
- }
154
- };
155
- return this.#_validator.compile(schema);
156
- }
157
-
158
- sanitizePostTx(op) {
159
- return this.#_sanitizePostTx(op) === true;
160
- }
161
- }
162
-
163
- export default Check;
@@ -1,63 +0,0 @@
1
- export const EntryType = Object.freeze({
2
- ADMIN: 'admin',
3
- WHITELIST: 'whitelist',
4
- INDEXERS: 'indexers',
5
- });
6
-
7
- export const OperationType = Object.freeze({
8
- ADD_ADMIN: 'addAdmin',
9
- APPEND_WHITELIST: 'appendWhitelist',
10
- ADD_WRITER: 'addWriter',
11
- REMOVE_WRITER: 'removeWriter',
12
- ADD_INDEXER: 'addIndexer',
13
- REMOVE_INDEXER: 'removeIndexer',
14
- BAN_VALIDATOR: 'banValidator',
15
- WHITELISTED: 'whitelisted',
16
- TX: 'tx',
17
- PRE_TX: 'pre-tx',
18
- POST_TX: 'post-tx',
19
- });
20
-
21
- export const EventType = Object.freeze({
22
- ADMIN_EVENT: 'adminEvent',
23
- WRITER_EVENT: 'writerEvent',
24
- IS_INDEXER: 'is-indexer',
25
- IS_NON_INDEXER: 'is-non-indexer',
26
- READY_MSB: 'ready-msb',
27
- WRITABLE: 'writable',
28
- UNWRITABLE: 'unwritable',
29
- WARNING: 'warning',
30
- });
31
-
32
- export const WHITELIST_FILEPATH = './Whitelist/pubkeys.csv';
33
- export const LISTENER_TIMEOUT = 10000;
34
- export const TRAC_NAMESPACE = 'TracNetwork';
35
- export const WHITELIST_PREFIX = 'whitelist/';
36
- export const MAX_INDEXERS = 3;
37
- export const MIN_INDEXERS = 1;
38
- export const WHITELIST_SLEEP_INTERVAL = 1000;
39
- export const MAX_PEERS = 64;
40
- export const MAX_PARALLEL = 64;
41
- export const MAX_SERVER_CONNECTIONS = Infinity;
42
- export const MAX_CLIENT_CONNECTIONS = Infinity;
43
- export const UPDATER_INTERVAL = 1_000;
44
-
45
- const constants = {
46
- EntryType,
47
- OperationType,
48
- EventType,
49
- WHITELIST_FILEPATH,
50
- LISTENER_TIMEOUT,
51
- TRAC_NAMESPACE,
52
- MAX_INDEXERS,
53
- MIN_INDEXERS,
54
- WHITELIST_SLEEP_INTERVAL,
55
- MAX_PEERS,
56
- MAX_PARALLEL,
57
- MAX_SERVER_CONNECTIONS,
58
- UPDATER_INTERVAL,
59
- WHITELIST_PREFIX
60
- };
61
-
62
- export default constants;
63
-
@@ -1,31 +0,0 @@
1
- import fs from 'fs';
2
- import {WHITELIST_FILEPATH} from '../utils/constants.js';
3
-
4
- // TODO: The methods in fileUtils need to be refactoed and generalized to improve code reusability
5
- // -- For example, the readPublicKeysFromFile method is specific to reading a whitelist file set in constants.
6
- // -- In the future, we might want to generalize this method to read any file and return its content.
7
- async function readPublicKeysFromFile() {
8
- try {
9
- const data = await fs.promises.readFile(WHITELIST_FILEPATH, 'utf8');
10
- const pubKeys = data
11
- .split('\n')
12
- .map(line => line.trim())
13
- .filter(line => line.length > 0);
14
-
15
- if (pubKeys.length === 0) {
16
- console.log('The file does not contain any public keys');
17
- }
18
-
19
- return pubKeys;
20
- } catch (err) {
21
- if (err.code === 'ENOENT') {
22
- console.log('Whitelist file not found');
23
- }
24
- console.log(`Failed to read public keys from the whitelist file: ${err.message}`);
25
- }
26
- }
27
-
28
-
29
- export default {
30
- readPublicKeysFromFile
31
- }
@@ -1,70 +0,0 @@
1
- import b4a from 'b4a';
2
- import sodium from 'sodium-native';
3
- import {peer} from "hyperdht/lib/messages.js";
4
-
5
- // TODO: (?) Should we allow 0x prefix?
6
- // TODO: (?) Should an mepty string be considered valid?
7
- export function isHexString(string) {
8
- return typeof string === 'string' && /^[0-9a-fA-F]+$/.test(string) && string.length % 2 === 0;
9
- }
10
-
11
- export async function verifyDag(base, swarm, wallet, writerKey) {
12
- try {
13
- console.log('--- Stats ---');
14
- const dagView = await base.view.core.treeHash();
15
- const lengthdagView = base.view.core.length;
16
- const dagSystem = await base.system.core.treeHash();
17
- const lengthdagSystem = base.system.core.length;
18
- console.log(`isIndexer: ${base.isIndexer}`);
19
- console.log(`isWriter: ${base.writable}`);
20
- console.log('wallet.publicKey:', wallet !== null ? wallet.publicKey : 'unset');
21
- console.log('msb.writerKey:', writerKey);
22
- console.log('swarm.connections.size:', swarm.connections.size);
23
- console.log('base.view.core.signedLength:', base.view.core.signedLength);
24
- console.log('base.view.core.length:', base.view.core.length);
25
- console.log("base.signedLength", base.signedLength);
26
- console.log("base.indexedLength", base.indexedLength);
27
- console.log("base.linearizer.indexers.length", base.linearizer.indexers.length);
28
- console.log(`base.key: ${base.key.toString('hex')}`);
29
- console.log('discoveryKey:', b4a.toString(base.discoveryKey, 'hex'));
30
- console.log(`VIEW Dag: ${dagView.toString('hex')} (length: ${lengthdagView})`);
31
- console.log(`SYSTEM Dag: ${dagSystem.toString('hex')} (length: ${lengthdagSystem})`);
32
- const wl = await base.view.get('wrl');
33
- console.log('Total Registered Writers:', wl !== null ? wl.value : 0);
34
-
35
- } catch (error) {
36
- console.error('Error during DAG monitoring:', error.message);
37
- }
38
- }
39
-
40
- export async function sleep(ms) {
41
- return new Promise(resolve => setTimeout(resolve, ms));
42
- }
43
-
44
- export async function createHash(type, message) {
45
- if (type === 'sha256') {
46
- const out = b4a.alloc(sodium.crypto_hash_sha256_BYTES);
47
- sodium.crypto_hash_sha256(out,!b4a.isBuffer(message) ? b4a.from(message) : message);
48
- return b4a.toString(out, 'hex');
49
- }
50
- if (global.Pear !== undefined) {
51
- let _type = '';
52
- switch (type.toLowerCase()) {
53
- case 'sha1': _type = 'SHA-1'; break;
54
- case 'sha384': _type = 'SHA-384'; break;
55
- case 'sha512': _type = 'SHA-512'; break;
56
- default: throw new Error('Unsupported algorithm.');
57
- }
58
- const encoder = new TextEncoder();
59
- const data = encoder.encode(b4a.isBuffer(message) ? b4a.toString(message, 'utf-8') : message);
60
- const hash = await crypto.subtle.digest(_type, data);
61
- const hashArray = Array.from(new Uint8Array(hash));
62
- return hashArray
63
- .map((b) => b.toString(16).padStart(2, "0"))
64
- .join("");
65
- } else {
66
- // this is only available here for completeness and in fact will never be used in the MSB.
67
- // just keep it as it is.
68
- return crypto.createHash(type).update(!b4a.isBuffer(message) ? b4a.from(message) : message).digest('hex')
69
- }
70
- }