@hazae41/bobine 0.0.8 → 0.0.10

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
@@ -17,9 +17,9 @@ https://bobine.tech/
17
17
 
18
18
  \* There are no built-in accounting concepts, only pure generic APIs for cryptography and storage
19
19
 
20
- ## Running
20
+ ## Usage
21
21
 
22
- ### Binary
22
+ ### Running the server
23
23
 
24
24
  Install the binary with Deno
25
25
 
@@ -58,13 +58,15 @@ Run the server
58
58
  bobine serve --env=./.env.local
59
59
  ```
60
60
 
61
- ### Library
61
+ Or you can install `@hazae41/bobine` and use the `serve()` function
62
62
 
63
- Install `@hazae41/bobine` and use the `serve()` function
63
+ ### Making your own module
64
64
 
65
- ## HTTP API
65
+ You can clone my [AssemblyScript starter](https://github.com/hazae41/create-bobine-assemblyscript-module) to get started with AssemblyScript
66
66
 
67
- ### POST /api/create
67
+ ### Using the HTTP API
68
+
69
+ #### POST /api/create
68
70
 
69
71
  Creates a new module using some WebAssembly code and some unique salt
70
72
 
@@ -76,7 +78,7 @@ Accepts a form data with the following fields
76
78
 
77
79
  - `effort` as bytes = some unique 32 bytes whose sha256 `hash` validates `((2n ** 256n) / BigInt("0x" + hash.toHex())) > (code.length + salt.length)`
78
80
 
79
- ### POST /api/execute
81
+ #### POST /api/execute
80
82
 
81
83
  Execute some function on a module
82
84
 
@@ -90,7 +92,7 @@ Accepts a form data with the following fields
90
92
 
91
93
  - `effort` as bytes = some unique 32 bytes whose sha256 `hash` whose result in `((2n ** 256n) / BigInt("0x" + hash.toHex()))` will be the maximum number of sparks (gas) used
92
94
 
93
- ### POST /api/simulate
95
+ #### POST /api/simulate
94
96
 
95
97
  Simulate some function on a module (it won't write anything to storage and will execute in mode `2` so verifications such as signatures can be skipped)
96
98
 
@@ -104,11 +106,11 @@ Accepts a form data with the following fields
104
106
 
105
107
  - `effort` as bytes = some unique 32 bytes whose sha256 `hash` whose result in `((2n ** 256n) / BigInt("0x" + hash.toHex()))` will be the maximum number of sparks (gas) used
106
108
 
107
- ## WebAssembly API
109
+ ### Using the WebAssembly API
108
110
 
109
111
  The WebAssembly VM extensively uses reference types for its API and for module-to-module communication
110
112
 
111
- ### AssemblyScript
113
+ #### Using the WebAssembly API via AssemblyScript
112
114
 
113
115
  You can use [stdbob](https://github.com/hazae41/stdbob) to easily import AssemblyScript declarations for all internal modules
114
116
 
@@ -126,9 +128,7 @@ And you can declare external modules by using the module address as hex
126
128
  declare function add(x: externref, y: externref): externref
127
129
  ```
128
130
 
129
- ### All internal modules
130
-
131
- #### blobs
131
+ #### Blobs module
132
132
 
133
133
  You can pass bytes between modules by storing them in the blob storage and loading them via reference
134
134
 
@@ -142,7 +142,7 @@ You can pass bytes between modules by storing them in the blob storage and loadi
142
142
 
143
143
  - `blob.to_hex/from_hex/to_base64/from_base64(blob: blobref): blobref` = convert blobs to/from hex/base64 without loading them into memory
144
144
 
145
- #### bigints
145
+ #### BigInts module
146
146
 
147
147
  You can work with infinite-precision bigints
148
148
 
@@ -168,7 +168,7 @@ You can work with infinite-precision bigints
168
168
 
169
169
  - `bigints.from_base10(base16: blobref): bigintref` = convert base10 utf8 bytes to bigint
170
170
 
171
- #### packs
171
+ #### Packs module
172
172
 
173
173
  You can pack various arguments (numbers, refs) into a pack which can be passed between modules and/or encoded/decoded into bytes
174
174
 
@@ -225,7 +225,7 @@ function writePack(pack: packref) {
225
225
 
226
226
  - `packs.length(pack: packref): i32` = get the length of a pack
227
227
 
228
- #### env
228
+ #### Environment module
229
229
 
230
230
  Get infos about the executing environment
231
231
 
@@ -233,7 +233,7 @@ Get infos about the executing environment
233
233
 
234
234
  - `env.uuid(): blobref` = get the unique uuid of this environment (similar to a chain id)
235
235
 
236
- #### modules
236
+ #### Modules module
237
237
 
238
238
  Modules are identified by their address as a blob of bytes (pure sha256-output 32-length bytes without any encoding)
239
239
 
@@ -245,7 +245,7 @@ Modules are identified by their address as a blob of bytes (pure sha256-output 3
245
245
 
246
246
  - `modules.self(): blobref` = get your module address as blob
247
247
 
248
- #### storage
248
+ #### Storage module
249
249
 
250
250
  You can use a private storage (it works like storage and events at the same time)
251
251
 
@@ -253,13 +253,13 @@ You can use a private storage (it works like storage and events at the same time
253
253
 
254
254
  - `storage.get(key: blobref): blobref` = get the latest value from storage at key
255
255
 
256
- #### sha256
256
+ #### SHA-256 module
257
257
 
258
258
  Use the SHA-256 hashing algorithm
259
259
 
260
260
  - `sha256.digest(payload: blobref): blobref` = hash the payload and returns the digest
261
261
 
262
- #### ed25519
262
+ #### Ed25519 module
263
263
 
264
264
  Use the Ed25519 signing algorithm
265
265
 
@@ -267,11 +267,11 @@ Use the Ed25519 signing algorithm
267
267
 
268
268
  - `ed25519.sign(payload: blobref): blobref` = (experimental) sign payload using the miner's private key
269
269
 
270
- #### symbols (experimental)
270
+ #### Symbols module (experimental)
271
271
 
272
272
  - `symbols.create(): symbolref` = create a unique reference that can be passed around
273
273
 
274
- #### refs (experimental)
274
+ #### References module (experimental)
275
275
 
276
276
  - `refs.numerize(ref: symbolref/blobref/packref): i32` = translate any reference into a unique private pointer that can be stored into data structures
277
277
 
@@ -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,6 @@ 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;
9
+ type Value = null | Pack | number | Uint8Array | string | bigint;
10
10
  function readOrThrow(cursor: Cursor): Pack;
11
11
  }
@@ -1,4 +1,4 @@
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) {
@@ -11,22 +11,27 @@ export class Pack {
11
11
  size += 1;
12
12
  continue;
13
13
  }
14
- if (typeof value === "number") {
15
- size += 1 + 4;
14
+ if (value instanceof Pack) {
15
+ size += 1 + value.sizeOrThrow();
16
16
  continue;
17
17
  }
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;
18
+ if (typeof value === "number") {
19
+ size += 1 + 4;
22
20
  continue;
23
21
  }
24
22
  if (value instanceof Uint8Array) {
25
23
  size += 1 + 4 + value.length;
26
24
  continue;
27
25
  }
28
- if (value instanceof Pack) {
29
- size += 1 + value.sizeOrThrow();
26
+ if (typeof value === "string") {
27
+ const data = new TextEncoder().encode(value);
28
+ size += 1 + 4 + data.length;
29
+ continue;
30
+ }
31
+ if (typeof value === "bigint") {
32
+ const text = value.toString(16);
33
+ const data = Uint8Array.fromHex(text.length % 2 === 1 ? "0" + text : text);
34
+ size += 1 + 4 + data.length;
30
35
  continue;
31
36
  }
32
37
  throw new Error("Unknown pack value");
@@ -40,17 +45,14 @@ export class Pack {
40
45
  cursor.writeUint8OrThrow(1);
41
46
  continue;
42
47
  }
43
- if (typeof value === "number") {
48
+ if (value instanceof Pack) {
44
49
  cursor.writeUint8OrThrow(2);
45
- cursor.writeFloat64OrThrow(value, true);
50
+ value.writeOrThrow(cursor);
46
51
  continue;
47
52
  }
48
- if (typeof value === "bigint") {
53
+ if (typeof value === "number") {
49
54
  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);
55
+ cursor.writeFloat64OrThrow(value, true);
54
56
  continue;
55
57
  }
56
58
  if (value instanceof Uint8Array) {
@@ -59,9 +61,19 @@ export class Pack {
59
61
  cursor.writeOrThrow(value);
60
62
  continue;
61
63
  }
62
- if (value instanceof Pack) {
64
+ if (typeof value === "string") {
63
65
  cursor.writeUint8OrThrow(5);
64
- value.writeOrThrow(cursor);
66
+ const data = new TextEncoder().encode(value);
67
+ cursor.writeUint32OrThrow(data.length, true);
68
+ cursor.writeOrThrow(data);
69
+ continue;
70
+ }
71
+ if (typeof value === "bigint") {
72
+ cursor.writeUint8OrThrow(6);
73
+ const text = value.toString(16);
74
+ const data = Uint8Array.fromHex(text.length % 2 === 1 ? "0" + text : text);
75
+ cursor.writeUint32OrThrow(data.length, true);
76
+ cursor.writeOrThrow(data);
65
77
  continue;
66
78
  }
67
79
  throw new Error("Unknown pack value");
@@ -82,13 +94,11 @@ export class Pack {
82
94
  continue;
83
95
  }
84
96
  if (type === 2) {
85
- values.push(cursor.readFloat64OrThrow(true));
97
+ values.push(Pack.readOrThrow(cursor));
86
98
  continue;
87
99
  }
88
100
  if (type === 3) {
89
- const size = cursor.readUint32OrThrow(true);
90
- const data = cursor.readOrThrow(size);
91
- values.push(BigInt("0x" + data.toHex()));
101
+ values.push(cursor.readFloat64OrThrow(true));
92
102
  continue;
93
103
  }
94
104
  if (type === 4) {
@@ -97,7 +107,15 @@ export class Pack {
97
107
  continue;
98
108
  }
99
109
  if (type === 5) {
100
- values.push(Pack.readOrThrow(cursor));
110
+ const size = cursor.readUint32OrThrow(true);
111
+ const data = cursor.readOrThrow(size);
112
+ values.push(new TextDecoder().decode(data));
113
+ continue;
114
+ }
115
+ if (type === 6) {
116
+ const size = cursor.readUint32OrThrow(true);
117
+ const data = cursor.readOrThrow(size);
118
+ values.push(BigInt("0x" + data.toHex()));
101
119
  continue;
102
120
  }
103
121
  throw new Error("Unknown pack type");
package/out/mod.js CHANGED
@@ -15,24 +15,9 @@ export async function main(args) {
15
15
  await server.main(subargs);
16
16
  return;
17
17
  }
18
- if (arg === "create") {
19
- console.log("Create command is not implemented yet.");
20
- return;
21
- }
22
- if (arg === "execute") {
23
- console.log("Execute command is not implemented yet.");
24
- return;
25
- }
26
- if (arg === "simulate") {
27
- console.log("Simulate command is not implemented yet.");
28
- return;
29
- }
30
18
  break;
31
19
  }
32
- console.log("- serve [--env=<env file as path>] [--port=<port>] [--dev]");
33
- console.log("- create <wasm file as path> [salt as hex]");
34
- console.log("- execute <module as hex> <function name> [args as pack as hex]");
35
- console.log("- simulate <module as hex> <function name> [args as pack as hex]");
20
+ console.log("serve [--env=<env file as path>] [--port=<port>] [--dev]");
36
21
  return;
37
22
  }
38
23
  if (import.meta.main) {
@@ -2,7 +2,7 @@ import { readFileSync } from "node:fs";
2
2
  import process from "node:process";
3
3
  import { serveWithEnv } from "./mod.js";
4
4
  export async function main(args) {
5
- const config = {};
5
+ const options = {};
6
6
  for (let i = 0; i < args.length; i++) {
7
7
  const arg = args[i];
8
8
  if (arg.startsWith("--env=")) {
@@ -10,15 +10,15 @@ export async function main(args) {
10
10
  continue;
11
11
  }
12
12
  if (arg.startsWith("--port=")) {
13
- config.port = Number(arg.slice("--port=".length));
13
+ options.port = Number(arg.slice("--port=".length));
14
14
  continue;
15
15
  }
16
16
  if (arg.startsWith("--cert=")) {
17
- config.cert = readFileSync(arg.slice("--cert=".length), "utf8");
17
+ options.cert = readFileSync(arg.slice("--cert=".length), "utf8");
18
18
  continue;
19
19
  }
20
20
  if (arg.startsWith("--key=")) {
21
- config.key = readFileSync(arg.slice("--key=".length), "utf8");
21
+ options.key = readFileSync(arg.slice("--key=".length), "utf8");
22
22
  continue;
23
23
  }
24
24
  if (arg === "--dev=true") {
@@ -35,7 +35,7 @@ export async function main(args) {
35
35
  }
36
36
  throw new Error(`Unknown argument: ${arg}`);
37
37
  }
38
- const { port = Number(process.env.PORT) || 8080, cert = process.env.CERT != null ? readFileSync(process.env.CERT, "utf8") : undefined, key = process.env.KEY != null ? readFileSync(process.env.KEY, "utf8") : undefined, } = config;
38
+ const { port = Number(process.env.PORT) || 8080, cert = process.env.CERT != null ? readFileSync(process.env.CERT, "utf8") : undefined, key = process.env.KEY != null ? readFileSync(process.env.KEY, "utf8") : undefined, } = options;
39
39
  const server = await serveWithEnv();
40
40
  const route = async (request) => {
41
41
  if (request.method === "OPTIONS")
@@ -89,14 +89,14 @@ function run(module, method, params, mode, maxsparks) {
89
89
  const view = new Uint8Array(memory.buffer, offset >>> 0, length >>> 0);
90
90
  return view.slice();
91
91
  },
92
- size: (blob) => {
93
- return blob.length;
94
- },
95
92
  load: (blob, offset) => {
96
93
  const { memory } = current.instance.exports;
97
94
  const view = new Uint8Array(memory.buffer, offset >>> 0, blob.length);
98
95
  view.set(blob);
99
96
  },
97
+ length: (blob) => {
98
+ return blob.length;
99
+ },
100
100
  concat: (left, right) => {
101
101
  const concat = new Uint8Array(left.length + right.length);
102
102
  concat.set(left, 0);
@@ -106,17 +106,55 @@ function run(module, method, params, mode, maxsparks) {
106
106
  equals: (left, right) => {
107
107
  return !Buffer.compare(left, right);
108
108
  },
109
- from_base16: (text) => {
110
- return Uint8Array.fromHex(new TextDecoder().decode(text));
109
+ includes: (haystack, needle) => {
110
+ return haystack.toHex().includes(needle.toHex());
111
111
  },
112
- from_base64: (text) => {
113
- return Uint8Array.fromBase64(new TextDecoder().decode(text));
112
+ slice: (blob, start, end) => {
113
+ return blob.slice(start >>> 0, end >>> 0);
114
+ },
115
+ from_base16: (text) => {
116
+ return Uint8Array.fromHex(text);
114
117
  },
115
118
  to_base16: (bytes) => {
116
- return new TextEncoder().encode(bytes.toHex());
119
+ return bytes.toHex();
120
+ },
121
+ from_base64: (text) => {
122
+ return Uint8Array.fromBase64(text);
117
123
  },
118
124
  to_base64: (bytes) => {
119
- return new TextEncoder().encode(bytes.toBase64());
125
+ return bytes.toBase64();
126
+ },
127
+ };
128
+ imports["texts"] = {
129
+ length: (text) => {
130
+ return new TextEncoder().encode(text).length;
131
+ },
132
+ concat: (left, right) => {
133
+ return left + right;
134
+ },
135
+ equals: (left, right) => {
136
+ return left === right;
137
+ },
138
+ includes: (haystack, needle) => {
139
+ return haystack.includes(needle);
140
+ },
141
+ slice: (text, start, end) => {
142
+ return text.slice(start >>> 0, end >>> 0);
143
+ },
144
+ from_utf8: (bytes) => {
145
+ return new TextDecoder().decode(bytes);
146
+ },
147
+ to_utf8: (text) => {
148
+ return new TextEncoder().encode(text);
149
+ },
150
+ to_uppercase: (text) => {
151
+ return text.toUpperCase();
152
+ },
153
+ to_lowercase: (text) => {
154
+ return text.toLowerCase();
155
+ },
156
+ trim: (text) => {
157
+ return text.trim();
120
158
  }
121
159
  };
122
160
  imports["packs"] = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@hazae41/bobine",
4
- "version": "0.0.8",
4
+ "version": "0.0.10",
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"