@hazae41/bobine 0.0.9 → 0.0.11

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/README.md CHANGED
@@ -21,8 +21,6 @@ https://bobine.tech/
21
21
 
22
22
  ### Running the server
23
23
 
24
- #### Running the server via binary
25
-
26
24
  Install the binary with Deno
27
25
 
28
26
  ```bash
@@ -60,25 +58,11 @@ Run the server
60
58
  bobine serve --env=./.env.local
61
59
  ```
62
60
 
63
- #### Running the server via library
64
-
65
- Install `@hazae41/bobine` and use the `serve()` function
66
-
67
- ### Creating a module
68
-
69
- #### Creating a module via binary
70
-
71
- Install the binary with Deno
72
-
73
- ```bash
74
- deno install -gf -A jsr:@hazae41/bobine
75
- ```
61
+ Or you can install `@hazae41/bobine` and use the `serve()` function
76
62
 
77
- Deploy your .wasm file
63
+ ### Making your own module
78
64
 
79
- ```bash
80
- bobine create ./module.wasm --server=http://localhost:8080
81
- ```
65
+ You can clone my [AssemblyScript starter](https://github.com/hazae41/create-bobine-assemblyscript-module) to get started with AssemblyScript
82
66
 
83
67
  ### Using the HTTP API
84
68
 
@@ -1,17 +1,28 @@
1
1
  import * as Wasm from "@hazae41/wasm";
2
2
  export function meter(module, from, name) {
3
- const wtype = module.body.sections.find(section => section.kind === Wasm.TypeSection.kind);
4
- const wimport = module.body.sections.find(section => section.kind === Wasm.ImportSection.kind);
5
- const wexport = module.body.sections.find(section => section.kind === Wasm.ExportSection.kind);
6
- const wcode = module.body.sections.find(section => section.kind === Wasm.CodeSection.kind);
7
- if (wtype == null)
8
- throw new Error(`No type section`);
9
- if (wimport == null)
10
- throw new Error(`No import section`);
11
- if (wexport == null)
12
- throw new Error(`No export section`);
13
- if (wcode == null)
14
- throw new Error(`No code section`);
3
+ let wtype = module.body.sections.find(section => section.kind === Wasm.TypeSection.kind);
4
+ if (wtype == null) {
5
+ wtype = new Wasm.TypeSection([]);
6
+ module.body.sections.unshift(wtype);
7
+ }
8
+ let wimport = module.body.sections.find(section => section.kind === Wasm.ImportSection.kind);
9
+ if (wimport == null) {
10
+ wimport = new Wasm.ImportSection([]);
11
+ const before = module.body.sections.findLastIndex(section => section.kind < Wasm.ImportSection.kind);
12
+ module.body.sections.splice(before + 1, 0, wimport);
13
+ }
14
+ let wexport = module.body.sections.find(section => section.kind === Wasm.ExportSection.kind);
15
+ if (wexport == null) {
16
+ wexport = new Wasm.ExportSection([]);
17
+ const before = module.body.sections.findLastIndex(section => section.kind < Wasm.ExportSection.kind);
18
+ module.body.sections.splice(before + 1, 0, wexport);
19
+ }
20
+ let wcode = module.body.sections.find(section => section.kind === Wasm.CodeSection.kind);
21
+ if (wcode == null) {
22
+ wcode = new Wasm.CodeSection([]);
23
+ const before = module.body.sections.findLastIndex(section => section.kind < Wasm.CodeSection.kind);
24
+ module.body.sections.splice(before + 1, 0, wcode);
25
+ }
15
26
  const wstart = module.body.sections.find(section => section.kind === Wasm.StartSection.kind);
16
27
  wtype.descriptors.push({ prefix: Wasm.TypeSection.FuncType.kind, subtypes: [], body: new Wasm.TypeSection.FuncType([0x7f], []) });
17
28
  wimport.descriptors.unshift({ from: new TextEncoder().encode(from), name: new TextEncoder().encode(name), body: new Wasm.ImportSection.FunctionImport(wtype.descriptors.length - 1) });
@@ -6,6 +6,8 @@ export declare class Pack {
6
6
  writeOrThrow(cursor: Cursor): void;
7
7
  }
8
8
  export declare namespace Pack {
9
- type Value = null | number | bigint | Uint8Array | Pack;
10
- function readOrThrow(cursor: Cursor): Pack;
9
+ type Value = null | number | Uint8Array | string | bigint | Array<Value>;
10
+ function readOrThrow(cursor: Cursor): Array<Value>;
11
+ function sizeOrThrow(values: Array<Value>): number;
12
+ function writeOrThrow(values: Array<Value>, cursor: Cursor): void;
11
13
  }
@@ -1,32 +1,88 @@
1
- /// <reference types="../bytes/lib.d.ts"/>
1
+ // deno-lint-ignore-file no-namespace
2
2
  export class Pack {
3
3
  values;
4
4
  constructor(values) {
5
5
  this.values = values;
6
6
  }
7
7
  sizeOrThrow() {
8
+ return Pack.sizeOrThrow(this.values);
9
+ }
10
+ writeOrThrow(cursor) {
11
+ Pack.writeOrThrow(this.values, cursor);
12
+ }
13
+ }
14
+ (function (Pack) {
15
+ function readOrThrow(cursor) {
16
+ const values = [];
17
+ while (true) {
18
+ const type = cursor.readUint8OrThrow();
19
+ if (type === 0)
20
+ break;
21
+ if (type === 1) {
22
+ values.push(null);
23
+ continue;
24
+ }
25
+ if (type === 2) {
26
+ values.push(Pack.readOrThrow(cursor));
27
+ continue;
28
+ }
29
+ if (type === 3) {
30
+ values.push(cursor.readFloat64OrThrow(true));
31
+ continue;
32
+ }
33
+ if (type === 4) {
34
+ const size = cursor.readUint32OrThrow(true);
35
+ values.push(cursor.readOrThrow(size));
36
+ continue;
37
+ }
38
+ if (type === 5) {
39
+ const size = cursor.readUint32OrThrow(true);
40
+ const data = cursor.readOrThrow(size);
41
+ values.push(new TextDecoder().decode(data));
42
+ continue;
43
+ }
44
+ if (type === 6) {
45
+ const negative = cursor.readUint8OrThrow();
46
+ const size = cursor.readUint32OrThrow(true);
47
+ const data = cursor.readOrThrow(size);
48
+ const absolute = BigInt("0x" + data.toHex());
49
+ values.push(negative ? -absolute : absolute);
50
+ continue;
51
+ }
52
+ throw new Error("Unknown pack type");
53
+ }
54
+ return values;
55
+ }
56
+ Pack.readOrThrow = readOrThrow;
57
+ function sizeOrThrow(values) {
8
58
  let size = 0;
9
- for (const value of this.values) {
59
+ for (const value of values) {
10
60
  if (value == null) {
11
61
  size += 1;
12
62
  continue;
13
63
  }
14
- if (typeof value === "number") {
15
- size += 1 + 4;
64
+ if (Array.isArray(value)) {
65
+ size += 1 + sizeOrThrow(value);
16
66
  continue;
17
67
  }
18
- if (typeof value === "bigint") {
19
- const text = value.toString(16);
20
- const data = Uint8Array.fromHex(text.length % 2 === 1 ? "0" + text : text);
21
- size += 1 + 4 + data.length;
68
+ if (typeof value === "number") {
69
+ size += 1 + 4;
22
70
  continue;
23
71
  }
24
72
  if (value instanceof Uint8Array) {
25
73
  size += 1 + 4 + value.length;
26
74
  continue;
27
75
  }
28
- if (value instanceof Pack) {
29
- size += 1 + value.sizeOrThrow();
76
+ if (typeof value === "string") {
77
+ const data = new TextEncoder().encode(value);
78
+ size += 1 + 4 + data.length;
79
+ continue;
80
+ }
81
+ if (typeof value === "bigint") {
82
+ const absolute = value < 0n ? -value : value;
83
+ const text = absolute.toString(16);
84
+ const data = Uint8Array.fromHex(text.length % 2 === 1 ? "0" + text : text);
85
+ size += 1 + 1 + 4 + data.length;
30
86
  continue;
31
87
  }
32
88
  throw new Error("Unknown pack value");
@@ -34,23 +90,21 @@ export class Pack {
34
90
  size += 1;
35
91
  return size;
36
92
  }
37
- writeOrThrow(cursor) {
38
- for (const value of this.values) {
93
+ Pack.sizeOrThrow = sizeOrThrow;
94
+ function writeOrThrow(values, cursor) {
95
+ for (const value of values) {
39
96
  if (value == null) {
40
97
  cursor.writeUint8OrThrow(1);
41
98
  continue;
42
99
  }
43
- if (typeof value === "number") {
100
+ if (Array.isArray(value)) {
44
101
  cursor.writeUint8OrThrow(2);
45
- cursor.writeFloat64OrThrow(value, true);
102
+ writeOrThrow(value, cursor);
46
103
  continue;
47
104
  }
48
- if (typeof value === "bigint") {
105
+ if (typeof value === "number") {
49
106
  cursor.writeUint8OrThrow(3);
50
- const text = value.toString(16);
51
- const data = Uint8Array.fromHex(text.length % 2 === 1 ? "0" + text : text);
52
- cursor.writeUint32OrThrow(data.length, true);
53
- cursor.writeOrThrow(data);
107
+ cursor.writeFloat64OrThrow(value, true);
54
108
  continue;
55
109
  }
56
110
  if (value instanceof Uint8Array) {
@@ -59,9 +113,21 @@ export class Pack {
59
113
  cursor.writeOrThrow(value);
60
114
  continue;
61
115
  }
62
- if (value instanceof Pack) {
116
+ if (typeof value === "string") {
63
117
  cursor.writeUint8OrThrow(5);
64
- value.writeOrThrow(cursor);
118
+ const data = new TextEncoder().encode(value);
119
+ cursor.writeUint32OrThrow(data.length, true);
120
+ cursor.writeOrThrow(data);
121
+ continue;
122
+ }
123
+ if (typeof value === "bigint") {
124
+ cursor.writeUint8OrThrow(6);
125
+ const [negative, absolute] = value < 0n ? [1, -value] : [0, value];
126
+ const text = absolute.toString(16);
127
+ const data = Uint8Array.fromHex(text.length % 2 === 1 ? "0" + text : text);
128
+ cursor.writeUint8OrThrow(negative);
129
+ cursor.writeUint32OrThrow(data.length, true);
130
+ cursor.writeOrThrow(data);
65
131
  continue;
66
132
  }
67
133
  throw new Error("Unknown pack value");
@@ -69,40 +135,5 @@ export class Pack {
69
135
  cursor.writeUint8OrThrow(0);
70
136
  return;
71
137
  }
72
- }
73
- (function (Pack) {
74
- function readOrThrow(cursor) {
75
- const values = [];
76
- while (true) {
77
- const type = cursor.readUint8OrThrow();
78
- if (type === 0)
79
- break;
80
- if (type === 1) {
81
- values.push(null);
82
- continue;
83
- }
84
- if (type === 2) {
85
- values.push(cursor.readFloat64OrThrow(true));
86
- continue;
87
- }
88
- if (type === 3) {
89
- const size = cursor.readUint32OrThrow(true);
90
- const data = cursor.readOrThrow(size);
91
- values.push(BigInt("0x" + data.toHex()));
92
- continue;
93
- }
94
- if (type === 4) {
95
- const size = cursor.readUint32OrThrow(true);
96
- values.push(cursor.readOrThrow(size));
97
- continue;
98
- }
99
- if (type === 5) {
100
- values.push(Pack.readOrThrow(cursor));
101
- continue;
102
- }
103
- throw new Error("Unknown pack type");
104
- }
105
- return new Pack(values);
106
- }
107
- Pack.readOrThrow = readOrThrow;
138
+ Pack.writeOrThrow = writeOrThrow;
108
139
  })(Pack || (Pack = {}));
@@ -4,7 +4,6 @@ import { RpcErr, RpcError, RpcMethodNotFoundError, RpcOk } from "@hazae41/jsonrp
4
4
  import * as Wasm from "@hazae41/wasm";
5
5
  import { Buffer } from "node:buffer";
6
6
  import { existsSync, readFileSync, symlinkSync, writeFileSync } from "node:fs";
7
- import { log } from "../../libs/debug/mod.js";
8
7
  import { meter } from "../../libs/metering/mod.js";
9
8
  import { Pack } from "../../libs/packs/mod.js";
10
9
  const config = await fetch(self.name).then(res => res.json());
@@ -13,9 +12,11 @@ function run(module, method, params, mode, maxsparks) {
13
12
  let sparks = 0n;
14
13
  const exports = {};
15
14
  const caches = new Map();
15
+ const logs = new Array();
16
+ const reads = new Array();
16
17
  const writes = new Array();
17
18
  const pack_encode = (pack) => {
18
- return Writable.writeToBytesOrThrow(pack);
19
+ return Writable.writeToBytesOrThrow(new Pack(pack));
19
20
  };
20
21
  const pack_decode = (bytes) => {
21
22
  return Readable.readFromBytesOrThrow(Pack, bytes);
@@ -48,7 +49,7 @@ function run(module, method, params, mode, maxsparks) {
48
49
  };
49
50
  const ed25519_sign = (subpayload) => {
50
51
  sparks_consume(BigInt(subpayload.length) * 256n);
51
- const payload = pack_encode(new Pack([Uint8Array.fromHex(module), subpayload]));
52
+ const payload = pack_encode([Uint8Array.fromHex(module), subpayload]);
52
53
  const result = new Int32Array(new SharedArrayBuffer(4 + 64));
53
54
  helper.postMessage({ method: "ed25519_sign", params: [payload], result });
54
55
  if (Atomics.wait(result, 0, 0) !== "ok")
@@ -79,8 +80,8 @@ function run(module, method, params, mode, maxsparks) {
79
80
  }
80
81
  };
81
82
  imports["console"] = {
82
- log: (blob) => {
83
- log?.(new TextDecoder().decode(blob));
83
+ log: (text) => {
84
+ logs.push(text);
84
85
  }
85
86
  };
86
87
  imports["blobs"] = {
@@ -89,14 +90,14 @@ function run(module, method, params, mode, maxsparks) {
89
90
  const view = new Uint8Array(memory.buffer, offset >>> 0, length >>> 0);
90
91
  return view.slice();
91
92
  },
92
- size: (blob) => {
93
- return blob.length;
94
- },
95
93
  load: (blob, offset) => {
96
94
  const { memory } = current.instance.exports;
97
95
  const view = new Uint8Array(memory.buffer, offset >>> 0, blob.length);
98
96
  view.set(blob);
99
97
  },
98
+ length: (blob) => {
99
+ return blob.length;
100
+ },
100
101
  concat: (left, right) => {
101
102
  const concat = new Uint8Array(left.length + right.length);
102
103
  concat.set(left, 0);
@@ -106,31 +107,69 @@ function run(module, method, params, mode, maxsparks) {
106
107
  equals: (left, right) => {
107
108
  return !Buffer.compare(left, right);
108
109
  },
109
- from_base16: (text) => {
110
- return Uint8Array.fromHex(new TextDecoder().decode(text));
110
+ includes: (haystack, needle) => {
111
+ return haystack.toHex().includes(needle.toHex());
111
112
  },
112
- from_base64: (text) => {
113
- return Uint8Array.fromBase64(new TextDecoder().decode(text));
113
+ slice: (blob, start, end) => {
114
+ return blob.slice(start >>> 0, end >>> 0);
115
+ },
116
+ from_base16: (text) => {
117
+ return Uint8Array.fromHex(text);
114
118
  },
115
119
  to_base16: (bytes) => {
116
- return new TextEncoder().encode(bytes.toHex());
120
+ return bytes.toHex();
121
+ },
122
+ from_base64: (text) => {
123
+ return Uint8Array.fromBase64(text);
117
124
  },
118
125
  to_base64: (bytes) => {
119
- return new TextEncoder().encode(bytes.toBase64());
126
+ return bytes.toBase64();
127
+ },
128
+ };
129
+ imports["texts"] = {
130
+ length: (text) => {
131
+ return new TextEncoder().encode(text).length;
132
+ },
133
+ concat: (left, right) => {
134
+ return left + right;
135
+ },
136
+ equals: (left, right) => {
137
+ return left === right;
138
+ },
139
+ includes: (haystack, needle) => {
140
+ return haystack.includes(needle);
141
+ },
142
+ slice: (text, start, end) => {
143
+ return text.slice(start >>> 0, end >>> 0);
144
+ },
145
+ from_utf8: (bytes) => {
146
+ return new TextDecoder().decode(bytes);
147
+ },
148
+ to_utf8: (text) => {
149
+ return new TextEncoder().encode(text);
150
+ },
151
+ to_uppercase: (text) => {
152
+ return text.toUpperCase();
153
+ },
154
+ to_lowercase: (text) => {
155
+ return text.toLowerCase();
156
+ },
157
+ trim: (text) => {
158
+ return text.trim();
120
159
  }
121
160
  };
122
161
  imports["packs"] = {
123
162
  create: (...values) => {
124
- return new Pack(values);
163
+ return values;
125
164
  },
126
165
  concat: (left, right) => {
127
- return new Pack([...left.values, ...right.values]);
166
+ return [...left, ...right];
128
167
  },
129
168
  length: (pack) => {
130
- return pack.values.length;
169
+ return pack.length;
131
170
  },
132
171
  get(pack, index) {
133
- const value = pack.values[index >>> 0];
172
+ const value = pack[index >>> 0];
134
173
  if (value === undefined)
135
174
  throw new Error("Not found");
136
175
  return value;
@@ -143,6 +182,9 @@ function run(module, method, params, mode, maxsparks) {
143
182
  }
144
183
  };
145
184
  imports["bigints"] = {
185
+ identity: (value) => {
186
+ return value;
187
+ },
146
188
  zero: () => {
147
189
  return 0n;
148
190
  },
@@ -206,21 +248,21 @@ function run(module, method, params, mode, maxsparks) {
206
248
  return BigInt("0x" + bytes.toHex());
207
249
  },
208
250
  from_base16: (text) => {
209
- return BigInt("0x" + new TextDecoder().decode(text));
251
+ return BigInt("0x" + text);
210
252
  },
211
253
  to_base16: (bigint) => {
212
- return new TextEncoder().encode(bigint.toString(16));
254
+ return bigint.toString(16);
213
255
  },
214
256
  from_base10: (text) => {
215
- return BigInt(new TextDecoder().decode(text));
257
+ return BigInt(text);
216
258
  },
217
259
  to_base10: (bigint) => {
218
- return new TextEncoder().encode(bigint.toString());
260
+ return bigint.toString();
219
261
  }
220
262
  };
221
263
  imports["modules"] = {
222
264
  create: (wasmAsBytes, saltAsBytes) => {
223
- const packAsBytes = pack_encode(new Pack([wasmAsBytes, saltAsBytes]));
265
+ const packAsBytes = pack_encode([wasmAsBytes, saltAsBytes]);
224
266
  const digestOfWasmAsBytes = sha256_digest(wasmAsBytes);
225
267
  const digestOfPackAsBytes = sha256_digest(packAsBytes);
226
268
  const digestOfWasmAsHex = digestOfWasmAsBytes.toHex();
@@ -269,6 +311,7 @@ function run(module, method, params, mode, maxsparks) {
269
311
  return null;
270
312
  const fresh = new Uint8Array(result.buffer, 4 + 4 + 4, result[2]).slice();
271
313
  cache.set(key, fresh);
314
+ reads.push([module, key, fresh]);
272
315
  return fresh;
273
316
  }
274
317
  };
@@ -342,37 +385,33 @@ function run(module, method, params, mode, maxsparks) {
342
385
  const { instance } = load(module);
343
386
  if (typeof instance.exports[method] !== "function")
344
387
  throw new Error("Not found");
345
- const result = pack_encode(new Pack([instance.exports[method](...pack_decode(params).values)]));
346
- return { result, writes, sparks };
388
+ const returned = [instance.exports[method](...pack_decode(params))];
389
+ if (mode !== 2)
390
+ return pack_encode([logs, reads, writes, returned, sparks]);
391
+ if (writes.length) {
392
+ const result = new Int32Array(new SharedArrayBuffer(4 + 4));
393
+ helper.postMessage({ method: "storage_set", params: [module, method, params, writes], result });
394
+ if (Atomics.wait(result, 0, 0) !== "ok")
395
+ throw new Error("Failed to wait");
396
+ if (result[0] === 2)
397
+ throw new Error("Internal error");
398
+ // NOOP
399
+ }
400
+ return pack_encode([logs, reads, writes, returned, sparks]);
347
401
  }
348
402
  self.addEventListener("message", (event) => {
349
403
  try {
350
404
  const request = event.data;
351
405
  if (request.method === "execute") {
352
406
  const [module, method, params, maxsparks] = request.params;
353
- const start = performance.now();
354
- const { result, writes, sparks } = run(module, method, params, 1, maxsparks);
355
- const until = performance.now();
356
- log?.(`Evaluated ${(until - start).toFixed(2)}ms with ${sparks} sparks`);
357
- if (writes.length) {
358
- const result = new Int32Array(new SharedArrayBuffer(4 + 4));
359
- helper.postMessage({ method: "storage_set", params: [module, method, params, writes], result });
360
- if (Atomics.wait(result, 0, 0) !== "ok")
361
- throw new Error("Failed to wait");
362
- if (result[0] === 2)
363
- throw new Error("Internal error");
364
- log?.(`Wrote ${writes.length} events to storage`);
365
- }
366
- self.postMessage(new RpcOk(request.id, result));
407
+ const proof = run(module, method, params, 1, maxsparks);
408
+ self.postMessage(new RpcOk(request.id, proof));
367
409
  return;
368
410
  }
369
411
  if (request.method === "simulate") {
370
412
  const [module, method, params, maxsparks] = request.params;
371
- const start = performance.now();
372
- const { result, sparks } = run(module, method, params, 2, maxsparks);
373
- const until = performance.now();
374
- log?.(`Evaluated ${(until - start).toFixed(2)}ms with ${sparks} sparks`);
375
- self.postMessage(new RpcOk(request.id, result));
413
+ const proof = run(module, method, params, 2, maxsparks);
414
+ self.postMessage(new RpcOk(request.id, proof));
376
415
  return;
377
416
  }
378
417
  if (request.method === "verify") {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@hazae41/bobine",
4
- "version": "0.0.9",
4
+ "version": "0.0.11",
5
5
  "description": "A blockchain in your garage",
6
6
  "repository": "github:hazae41/bobine",
7
7
  "author": "hazae41",
@@ -11,8 +11,8 @@
11
11
  "version": "deno -RW ./x.vsync.ts && git add deno.json",
12
12
  "prepare": "deno -RW ./x.dsync.ts && deno install",
13
13
  "prepack": "rm -rf ./out && tsc && tscousin",
14
- "produce": "deno run -A ./src/bin.ts serve --env=./.env.local",
15
- "develop": "deno run -A ./src/bin.ts serve --env=./.env.local --dev"
14
+ "produce": "deno run -A ./src/mod.ts serve --env=./.env.local",
15
+ "develop": "deno run -A ./src/mod.ts serve --env=./.env.local --dev"
16
16
  },
17
17
  "files": [
18
18
  "./out"
@@ -1 +0,0 @@
1
- export declare const log: (message: string) => void;
@@ -1,4 +0,0 @@
1
- import process from "node:process";
2
- export const log = process.env.NODE_ENV === "development"
3
- ? (message) => console.debug(message)
4
- : null;