trac-peer 0.3.1 → 0.4.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.
Files changed (61) hide show
  1. package/.github/workflows/publish.yml +10 -1
  2. package/{src/dev → dev}/pokemonContract.js +3 -3
  3. package/{src/dev → dev}/pokemonProtocol.js +10 -7
  4. package/package.json +9 -5
  5. package/rpc/services.js +13 -12
  6. package/scripts/run-peer.mjs +35 -21
  7. package/src/api.js +74 -73
  8. package/src/{contract.js → artifacts/contract.js} +14 -58
  9. package/src/{feature.js → artifacts/feature.js} +3 -4
  10. package/src/{protocol.js → artifacts/protocol.js} +62 -47
  11. package/src/base/check.js +115 -0
  12. package/src/config/config.js +149 -0
  13. package/src/config/env.js +63 -0
  14. package/src/contractCheck.js +90 -0
  15. package/src/index.js +124 -759
  16. package/src/msbClient.js +78 -38
  17. package/src/operations/addAdmin/index.js +44 -0
  18. package/src/operations/addIndexer/index.js +64 -0
  19. package/src/operations/addWriter/index.js +64 -0
  20. package/src/operations/autoAddWriter/index.js +48 -0
  21. package/src/operations/deleteMessage/index.js +83 -0
  22. package/src/operations/enableTransactions/index.js +58 -0
  23. package/src/operations/enableWhitelist/index.js +59 -0
  24. package/src/operations/feature/index.js +64 -0
  25. package/src/operations/index.js +52 -0
  26. package/src/operations/msg/index.js +108 -0
  27. package/src/operations/muteStatus/index.js +72 -0
  28. package/src/operations/pinMessage/index.js +82 -0
  29. package/src/operations/removeWriter/index.js +64 -0
  30. package/src/operations/setAutoAddWriters/index.js +65 -0
  31. package/src/operations/setChatStatus/index.js +62 -0
  32. package/src/operations/setMod/index.js +60 -0
  33. package/src/operations/setNick/index.js +89 -0
  34. package/src/operations/setWhitelistStatus/index.js +60 -0
  35. package/src/operations/tx/index.js +142 -0
  36. package/src/operations/unpinMessage/index.js +73 -0
  37. package/src/operations/updateAdmin/index.js +63 -0
  38. package/src/tasks/transactionObserver.js +91 -0
  39. package/src/tasks/updater.js +57 -0
  40. package/src/terminal/handlers.js +494 -0
  41. package/src/terminal/index.js +123 -0
  42. package/src/transaction/transactionPool.js +38 -0
  43. package/src/utils/scheduler.js +118 -0
  44. package/src/utils/types.js +81 -0
  45. package/src/wallet.js +2 -1
  46. package/tests/acceptance/acceptance.test.js +4 -1
  47. package/tests/acceptance/rpc.test.js +81 -85
  48. package/tests/helpers/tmpdir.js +58 -0
  49. package/tests/unit/applyGuards.test.js +23 -26
  50. package/tests/unit/baseContractProtocol.test.js +10 -9
  51. package/tests/unit/cliTx.test.js +128 -53
  52. package/tests/unit/msbTxValidation.test.js +286 -0
  53. package/tests/unit/operations.test.js +560 -0
  54. package/tests/unit/simFunds.test.js +122 -0
  55. package/tests/unit/unit.test.js +3 -0
  56. package/src/check.js +0 -565
  57. package/src/cli.js +0 -275
  58. package/src/dev/HyperMallConctract.js +0 -990
  59. package/src/dev/HyperMallProtocol.js +0 -689
  60. package/src/functions.js +0 -495
  61. package/src/permissions.js +0 -63
@@ -22,7 +22,16 @@ jobs:
22
22
  node-version: 22
23
23
  cache: 'npm'
24
24
  - run: npm ci
25
- - run: npm run test:all
25
+ - name: Install bare
26
+ run: npm i -g bare
27
+ - name: Verify bare install
28
+ run: |
29
+ which bare
30
+ bare --version
31
+ - name: Unit tests (node + bare)
32
+ run: npm run test:unit:all
33
+ - name: Acceptance tests (node + bare)
34
+ run: npm run test:acceptance:all
26
35
  release:
27
36
  needs: test
28
37
  if: startsWith(github.ref, 'refs/tags/')
@@ -1,4 +1,4 @@
1
- import BaseContract from "../contract.js";
1
+ import BaseContract from "../src/artifacts/contract.js";
2
2
 
3
3
  export const GEN1_POKEMON = [
4
4
  { id: 1, name: "Bulbasaur" },
@@ -155,8 +155,8 @@ export const GEN1_POKEMON = [
155
155
  ];
156
156
 
157
157
  class PokemonContract extends BaseContract {
158
- constructor(protocol) {
159
- super(protocol);
158
+ constructor(protocol, config) {
159
+ super(protocol, config);
160
160
  this.addFunction("catch");
161
161
  }
162
162
 
@@ -1,4 +1,4 @@
1
- import BaseProtocol from "../protocol.js";
1
+ import BaseProtocol from "../src/artifacts/protocol.js";
2
2
  import { bufferToBigInt, bigIntToDecimalString } from "trac-msb/src/utils/amountSerialization.js";
3
3
 
4
4
  class PokemonProtocol extends BaseProtocol {
@@ -30,6 +30,7 @@ class PokemonProtocol extends BaseProtocol {
30
30
 
31
31
  async customCommand(input) {
32
32
  if (typeof input !== "string") return;
33
+
33
34
  if (input.startsWith("/get")) {
34
35
  const m = input.match(/(?:^|\s)--key(?:=|\s+)(\"[^\"]+\"|'[^']+'|\S+)/);
35
36
  const raw = m ? m[1].trim() : null;
@@ -45,19 +46,21 @@ class PokemonProtocol extends BaseProtocol {
45
46
  console.log(v);
46
47
  return;
47
48
  }
49
+
48
50
  if (input.startsWith("/msb")) {
49
51
  const txv = await this.peer.msbClient.getTxvHex();
50
52
  const peerMsbAddress = this.peer.msbClient.pubKeyHexToAddress(this.peer.wallet.publicKey);
51
- const entry = peerMsbAddress ? await this.peer.msb.state.getNodeEntryUnsigned(peerMsbAddress) : null;
52
- const balance = entry?.balance ? bigIntToDecimalString(bufferToBigInt(entry.balance)) : null;
53
- const fee = bigIntToDecimalString(bufferToBigInt(this.peer.msb.state.getFee()));
54
- const validators = this.peer.msb.network?.validatorConnectionManager?.connectionCount?.() ?? 0;
53
+ const entry = await this.peer.msbClient.getNodeEntryUnsigned(peerMsbAddress);
54
+ const balance = entry?.balance ? bigIntToDecimalString(bufferToBigInt(entry.balance)) : 0;
55
+ const feeBuf = this.peer.msbClient.getFee();
56
+ const fee = feeBuf ? bigIntToDecimalString(bufferToBigInt(feeBuf)) : 0;
57
+ const validators = this.peer.msbClient.getConnectedValidatorsCount();
55
58
  console.log({
56
59
  networkId: this.peer.msbClient.networkId,
57
60
  msbBootstrap: this.peer.msbClient.bootstrapHex,
58
61
  txv,
59
- msbSignedLength: this.peer.msb.state.getSignedLength(),
60
- msbUnsignedLength: this.peer.msb.state.getUnsignedLength(),
62
+ msbSignedLength: this.peer.msbClient.getSignedLength(),
63
+ msbUnsignedLength: this.peer.msbClient.getUnsignedLength(),
61
64
  connectedValidators: validators,
62
65
  peerMsbAddress,
63
66
  peerMsbBalance: balance,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "trac-peer",
3
3
  "main": "src/index.js",
4
- "version": "0.3.1",
4
+ "version": "0.4.1",
5
5
  "type": "module",
6
6
  "pear": {
7
7
  "name": "trac-peer",
@@ -24,9 +24,13 @@
24
24
  "peer:smoke": "node scripts/smoke-msb-sync.mjs",
25
25
  "peer:pear": "pear run -d scripts/run-peer.mjs",
26
26
  "peer:pear-rpc": "pear run -d scripts/run-peer.mjs --rpc",
27
- "test:unit:node": "node tests/unit/unit.test.js",
28
- "test:acceptance:node": "node tests/acceptance/acceptance.test.js",
29
- "test:all": "npm run test:unit:node && npm run test:acceptance:node"
27
+ "test:unit:node": "brittle-node -t 60000 tests/unit/unit.test.js",
28
+ "test:unit:bare": "brittle-bare -t 60000 tests/unit/unit.test.js",
29
+ "test:unit:all": "(npm run test:unit:node && npm run test:unit:bare) || exit 1",
30
+ "test:acceptance:node": "brittle-node -t 120000 tests/acceptance/acceptance.test.js",
31
+ "test:acceptance:bare": "brittle-bare -t 120000 tests/acceptance/acceptance.test.js",
32
+ "test:acceptance:all": "(npm run test:acceptance:node && npm run test:acceptance:bare) || exit 1",
33
+ "test:all": "npm run test:unit:all && npm run test:acceptance:all"
30
34
  },
31
35
  "dependencies": {
32
36
  "@tracsystems/blake3": "^0.0.15",
@@ -97,7 +101,7 @@
97
101
  "tls": "npm:bare-node-tls",
98
102
  "trac-crypto-api": "^0.1.3",
99
103
  "trac-msb": "^0.2.9",
100
- "trac-wallet": "^0.0.43-msb-r2.9",
104
+ "trac-wallet": "^1.0.1",
101
105
  "tty": "npm:bare-node-tty",
102
106
  "url": "npm:bare-node-url",
103
107
  "util": "npm:bare-node-util",
package/rpc/services.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import b4a from "b4a";
2
2
  import { fastestToJsonSchema } from "./utils/schemaToJson.js";
3
+ import { createHash } from "../src/utils/types.js";
3
4
 
4
5
  const asHex32 = (value, field) => {
5
6
  const hex = String(value ?? "").trim().toLowerCase();
@@ -10,7 +11,7 @@ const asHex32 = (value, field) => {
10
11
  const isObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
11
12
 
12
13
  const requireApi = (peer) => {
13
- const api = peer?.protocol_instance?.api;
14
+ const api = peer?.protocol.instance?.api;
14
15
  if (!api) throw new Error("Protocol API not initialized.");
15
16
  return api;
16
17
  };
@@ -22,7 +23,7 @@ export async function getStatus(peer) {
22
23
  ? String(peer.bootstrap)
23
24
  : null;
24
25
 
25
- const peerMsbAddress = peer.msbClient?.isReady() ? peer.msbClient.pubKeyHexToAddress(peer.wallet.publicKey) : null;
26
+ const peerMsbAddress = peer.msbClient.pubKeyHexToAddress(peer.wallet.publicKey);
26
27
 
27
28
  const admin = peer.base?.view ? await peer.base.view.get("admin") : null;
28
29
  const chatStatus = peer.base?.view ? await peer.base.view.get("chat_status") : null;
@@ -43,10 +44,10 @@ export async function getStatus(peer) {
43
44
  chatStatus: chatStatus?.value ?? null,
44
45
  },
45
46
  msb: {
46
- ready: peer.msbClient?.isReady?.() ?? false,
47
- bootstrapHex: peer.msbClient?.bootstrapHex ?? null,
48
- networkId: peer.msbClient?.networkId ?? null,
49
- signedLength: peer.msbClient?.isReady?.() ? peer.msbClient.getSignedLength() : null,
47
+ ready: true,
48
+ bootstrapHex: peer.msbClient.bootstrapHex,
49
+ networkId: peer.msbClient.networkId,
50
+ signedLength: peer.msbClient.getSignedLength()
50
51
  },
51
52
  };
52
53
  }
@@ -78,7 +79,7 @@ const convertContractOpSchema = (fv) => {
78
79
  };
79
80
 
80
81
  export async function getContractSchema(peer) {
81
- const contract = peer?.contract_instance;
82
+ const contract = peer?.contract?.instance;
82
83
  if (!contract) throw new Error("Contract instance not initialized.");
83
84
 
84
85
  const registrations = contract.metadata ?? {};
@@ -106,11 +107,11 @@ export async function getContractSchema(peer) {
106
107
  schemaFormat: "json-schema",
107
108
  contract: {
108
109
  contractClass: contract.constructor?.name ?? null,
109
- protocolClass: peer.protocol_instance?.constructor?.name ?? null,
110
+ protocolClass: peer.protocol.instance?.constructor?.name ?? null,
110
111
  txTypes,
111
112
  ops,
112
113
  },
113
- api: peer.protocol_instance?.getApiSchema ? peer.protocol_instance.getApiSchema() : { methods: {} },
114
+ api: peer.protocol.instance?.getApiSchema ? peer.protocol.instance.getApiSchema() : { methods: {} },
114
115
  };
115
116
  }
116
117
 
@@ -125,14 +126,14 @@ export async function contractPrepareTx(peer, { prepared_command, address, nonce
125
126
  const addr = asHex32(address, "address");
126
127
  const n = asHex32(nonce, "nonce");
127
128
 
128
- if (peer?.protocol_instance?.safeJsonStringify == null) {
129
+ if (peer?.protocol.instance?.safeJsonStringify == null) {
129
130
  throw new Error("safeJsonStringify is not available on protocol instance.");
130
131
  }
131
132
 
132
- const json = peer.protocol_instance.safeJsonStringify(prepared_command);
133
+ const json = peer.protocol.instance.safeJsonStringify(prepared_command);
133
134
  if (json == null) throw new Error("Failed to stringify prepared_command.");
134
135
 
135
- const command_hash = await peer.createHash("blake3", json);
136
+ const command_hash = await createHash(json);
136
137
  const tx = await api.generateTx(addr, command_hash, n);
137
138
  return { tx, command_hash };
138
139
  }
@@ -2,15 +2,15 @@ import b4a from "b4a";
2
2
  import path from "path";
3
3
  import fs from "fs";
4
4
  import PeerWallet from "trac-wallet";
5
- import { Peer, Wallet } from "../src/index.js";
5
+ import { Peer, Wallet, createConfig as createPeerConfig, ENV as PEER_ENV } from "../src/index.js";
6
6
  import { MainSettlementBus } from "trac-msb/src/index.js";
7
- import { createConfig, ENV } from "trac-msb/src/config/env.js"
7
+ import { createConfig as createMsbConfig, ENV as MSB_ENV } from "trac-msb/src/config/env.js"
8
8
  import { startRpcServer } from "../rpc/rpc_server.js";
9
9
  import { DEFAULT_RPC_HOST, DEFAULT_RPC_PORT, DEFAULT_MAX_BODY_BYTES } from "../rpc/constants.js";
10
- import { startInteractiveCli } from "../src/cli.js";
10
+ import { Terminal } from "../src/terminal/index.js";
11
11
  import { ensureTextCodecs } from "../src/textCodec.js";
12
- import PokemonProtocol from "../src/dev/pokemonProtocol.js";
13
- import PokemonContract from "../src/dev/pokemonContract.js";
12
+ import PokemonProtocol from "../dev/pokemonProtocol.js";
13
+ import PokemonContract from "../dev/pokemonContract.js";
14
14
 
15
15
  let process = globalThis.process;
16
16
  if (globalThis.Pear !== undefined) {
@@ -18,8 +18,13 @@ if (globalThis.Pear !== undefined) {
18
18
  process = bareProcess;
19
19
  }
20
20
 
21
+ const pearApp = typeof Pear !== "undefined" ? (Pear.app ?? Pear.config) : undefined;
22
+ const runtimeArgs = typeof process !== "undefined" ? process.argv.slice(2) : [];
23
+ const argv = pearApp?.args ?? runtimeArgs;
24
+ const positionalStoreName = argv.find((a) => a !== undefined && !String(a).startsWith("--")) ?? null;
25
+
21
26
  const createMsb = (options) => {
22
- const config = createConfig(ENV.MAINNET, options)
27
+ const config = createMsbConfig(MSB_ENV.MAINNET, options)
23
28
  return new MainSettlementBus(config);
24
29
  }
25
30
 
@@ -72,7 +77,7 @@ const readHexFile = (filePath, byteLength) => {
72
77
  return null;
73
78
  };
74
79
 
75
- const args = toArgMap(process.argv.slice(2));
80
+ const args = toArgMap(argv);
76
81
 
77
82
  const rpcEnabled =
78
83
  args["rpc"] === true || args["rpc"] === "true" || process.env.PEER_RPC === "true" || process.env.PEER_RPC === "1";
@@ -115,7 +120,7 @@ const msbStoresDirectory =
115
120
  const msbStoreName =
116
121
  (args["msb-store-name"] && String(args["msb-store-name"])) ||
117
122
  process.env.MSB_STORE_NAME ||
118
- "peer-msb";
123
+ null;
119
124
 
120
125
  const msbBootstrap =
121
126
  (args["msb-bootstrap"] && String(args["msb-bootstrap"])) ||
@@ -135,8 +140,8 @@ const peerStoresDirectory =
135
140
  const peerStoreNameRaw =
136
141
  (args["peer-store-name"] && String(args["peer-store-name"])) ||
137
142
  process.env.PEER_STORE_NAME ||
143
+ (positionalStoreName ? String(positionalStoreName) : null) ||
138
144
  "peer";
139
- const peerStoreName = ensureTrailingSlash(peerStoreNameRaw);
140
145
 
141
146
  const subnetBootstrapHex =
142
147
  (args["subnet-bootstrap"] && String(args["subnet-bootstrap"])) ||
@@ -166,13 +171,14 @@ if (!msbBootstrapHex || !msbChannel) {
166
171
  // Important: this starts a *local MSB node* (its own store) that joins your already-running MSB network.
167
172
  // trac-peer currently requires an MSB instance to broadcast and to observe confirmed state.
168
173
 
169
- const msbStoresFullPath = `${ensureTrailingSlash(msbStoresDirectory)}/${msbStoreName}`;
170
- const msbKeyPairPath = `${msbStoresFullPath}/db/keypair.json`;
174
+ const effectiveMsbStoreName = msbStoreName ?? `${peerStoreNameRaw}-msb`;
175
+ const msbStoresFullPath = path.join(ensureTrailingSlash(msbStoresDirectory), effectiveMsbStoreName);
176
+ const msbKeyPairPath = path.join(msbStoresFullPath, "db", "keypair.json");
171
177
  await ensureKeypairFile(msbKeyPairPath);
172
178
 
173
179
  const peerKeyPairPath = path.join(
174
180
  peerStoresDirectory,
175
- peerStoreName,
181
+ peerStoreNameRaw,
176
182
  "db",
177
183
  "keypair.json"
178
184
  );
@@ -202,22 +208,25 @@ if (subnetBootstrap) {
202
208
  }
203
209
  }
204
210
 
205
- const msb = createMsb({ bootstrap: msbBootstrap, channel: msbChannel, storeName: msbStoreName, storesDirectory: msbStoresDirectory})
211
+ const msb = createMsb({ bootstrap: msbBootstrap, channel: msbChannel, storeName: effectiveMsbStoreName, storesDirectory: msbStoresDirectory})
206
212
  await msb.ready();
207
213
 
208
214
  // DevProtocol and DevContract moved to shared src files
215
+ const peerConfig = createPeerConfig(PEER_ENV.MAINNET, {
216
+ storesDirectory: ensureTrailingSlash(peerStoresDirectory),
217
+ storeName: peerStoreNameRaw,
218
+ bootstrap: subnetBootstrap ? b4a.from(subnetBootstrap, "hex") : null,
219
+ channel: subnetChannel,
220
+ enableInteractiveMode: rpcEnabled ? false : true,
221
+ apiTxExposed: apiTxExposedEffective,
222
+ });
209
223
 
210
224
  const peer = new Peer({
211
- stores_directory: ensureTrailingSlash(peerStoresDirectory),
212
- store_name: peerStoreName,
225
+ config: peerConfig,
213
226
  msb,
214
227
  wallet: new Wallet(),
215
228
  protocol: PokemonProtocol,
216
229
  contract: PokemonContract,
217
- bootstrap: subnetBootstrap ? b4a.from(subnetBootstrap, "hex") : null,
218
- channel: subnetChannel,
219
- enable_interactive_mode: true,
220
- api_tx_exposed: apiTxExposedEffective,
221
230
  });
222
231
  await peer.ready();
223
232
 
@@ -227,7 +236,7 @@ if (rpcEnabled) {
227
236
  }
228
237
 
229
238
  const peerMsbAddress = peer.msbClient.pubKeyHexToAddress(peer.wallet.publicKey);
230
- const effectiveSubnetBootstrapHex = peer.base?.key ? b4a.toString(peer.base.key, "hex") : (b4a.isBuffer(peer.bootstrap) ? b4a.toString(peer.bootstrap, "hex") : String(peer.bootstrap));
239
+ const effectiveSubnetBootstrapHex = peer.base?.key ? b4a.toString(peer.base.key, "hex") : (b4a.isBuffer(peer.config.bootstrap) ? b4a.toString(peer.config.bootstrap, "hex") : String(peer.config.bootstrap));
231
240
  if (!subnetBootstrap) {
232
241
  fs.mkdirSync(path.dirname(subnetBootstrapFile), { recursive: true });
233
242
  fs.writeFileSync(subnetBootstrapFile, `${effectiveSubnetBootstrapHex}\n`);
@@ -261,7 +270,12 @@ console.log(' - /get --key "txl"');
261
270
  console.log("==========================================================");
262
271
  console.log("");
263
272
 
264
- await startInteractiveCli(peer);
273
+ if (peer.config.enableInteractiveMode) {
274
+ const terminal = new Terminal(peer);
275
+ await terminal.start();
276
+ } else {
277
+ console.log("Interactive CLI disabled.");
278
+ }
265
279
 
266
280
  process.on("SIGINT", async () => {
267
281
  if (rpcServer) await new Promise((resolve) => rpcServer.close(resolve));