wao 0.6.0 → 0.6.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/esm/weavedrive.js CHANGED
@@ -1,13 +1,10 @@
1
- import Arweave from "arweave"
2
- import { toGraphObj } from "./utils.js"
3
- import { map } from "ramda"
4
-
5
1
  const KB = 1024
6
2
  const MB = KB * 1024
7
3
  const CACHE_SZ = 32 * KB
8
4
  const CHUNK_SZ = 128 * MB
9
5
  const NOTIFY_SZ = 512 * MB
10
6
  const log = console.log
7
+
11
8
  export default class WeaveDrive {
12
9
  constructor(ar) {
13
10
  this.drive = function WeaveDrive(mod, FS) {
@@ -18,44 +15,6 @@ export default class WeaveDrive {
18
15
  FS.streams[fd].node.cache = new Uint8Array(0)
19
16
  },
20
17
 
21
- joinUrl({ url, path }) {
22
- if (!path) return url
23
- if (path.startsWith("/"))
24
- return this.joinUrl({ url, path: path.slice(1) })
25
-
26
- url = new URL(url)
27
- url.pathname += path
28
- return url.toString()
29
- },
30
-
31
- async customFetch(path, options) {
32
- /**
33
- * mod.ARWEAVE may be a comma-delimited list of urls.
34
- * So we parse it into an array that we sequentially consume
35
- * using fetch, and return the first successful response.
36
- *
37
- * The first url is considered "primary". So if all urls fail
38
- * to produce a successful response, then we return the primary's
39
- * error response
40
- */
41
- const urlList = mod.ARWEAVE.includes(",")
42
- ? mod.ARWEAVE.split(",").map(url => url.trim())
43
- : [mod.ARWEAVE]
44
-
45
- let p
46
- for (const url of urlList) {
47
- const res = fetch(this.joinUrl({ url, path }), options)
48
- if (await res.then(r => r.ok).catch(() => false)) return res
49
- if (!p) p = res
50
- }
51
-
52
- /**
53
- * None succeeded so fallback to the primary and accept
54
- * whatever it returned
55
- */
56
- return p
57
- },
58
-
59
18
  async create(id) {
60
19
  var properties = { isDevice: false, contents: null }
61
20
 
@@ -66,19 +25,14 @@ export default class WeaveDrive {
66
25
 
67
26
  // Create the file in the emscripten FS
68
27
 
69
- // This check/mkdir was added for AOP 6 Boot loader because create is
70
- // called first because were only loading Data, we needed to create
71
- // the directory. See: https://github.com/permaweb/aos/issues/342
72
- if (!FS.analyzePath("/data/").exists) {
73
- FS.mkdir("/data/")
74
- }
28
+ if (!FS.analyzePath("/data/").exists) FS.mkdir("/data/")
75
29
 
76
30
  var node = FS.createFile("/", "data/" + id, properties, true, false)
77
31
  // Set initial parameters
78
32
  /*
79
- var bytesLength = await this.customFetch(`/${id}`, {
80
- method: "HEAD",
81
- }).then(res => res.headers.get("Content-Length"))
33
+ var bytesLength = await this.customFetch(`/${id}`, {
34
+ method: "HEAD",
35
+ }).then(res => res.headers.get("Content-Length"))
82
36
  */
83
37
  let data = await ar.data(id)
84
38
  const bytesLength = data?.length ?? 0
@@ -102,21 +56,21 @@ export default class WeaveDrive {
102
56
  return stream
103
57
  },
104
58
  async createBlockHeader(id) {
105
- const customFetch = this.customFetch
106
- // todo: add a bunch of retries
107
- async function retry(x) {
108
- return new Promise(r => {
109
- setTimeout(function () {
110
- r(customFetch(`/block/height/${id}`))
111
- }, x * 10000)
112
- })
113
- }
114
- var result = await this.customFetch(`/block/height/${id}`)
115
- .then(res => (!res.ok ? retry(1) : res))
116
- .then(res => (!res.ok ? retry(2) : res))
117
- .then(res => (!res.ok ? retry(3) : res))
118
- .then(res => (!res.ok ? retry(4) : res))
119
- .then(res => res.text())
59
+ var result = ""
60
+ try {
61
+ // todo: implement indep_hash
62
+ // fetch(`/block/height/${id}`)
63
+ const block = ar.mem.blockmap[ar.mem.blocks[id]]
64
+ if (block) {
65
+ result = JSON.stringify({
66
+ id: block.id,
67
+ timestamp: block.timestamp,
68
+ previous_block: block.previous,
69
+ txs: block.txs,
70
+ height: id,
71
+ })
72
+ }
73
+ } catch (e) {}
120
74
 
121
75
  var bytesLength = result.length
122
76
 
@@ -132,33 +86,12 @@ export default class WeaveDrive {
132
86
  return stream
133
87
  },
134
88
  async createTxHeader(id) {
135
- const customFetch = this.customFetch
136
- async function toAddress(owner) {
137
- return Arweave.utils.bufferTob64Url(
138
- await Arweave.crypto.hash(Arweave.utils.b64UrlToBuffer(owner)),
139
- )
140
- }
141
- async function retry(x) {
142
- return new Promise(r => {
143
- setTimeout(function () {
144
- r(customFetch(`/tx/${id}`))
145
- }, x * 10000)
146
- })
147
- }
148
- // todo: add a bunch of retries
149
- var result = await this.customFetch(`/tx/${id}`)
150
- .then(res => (!res.ok ? retry(1) : res))
151
- .then(res => (!res.ok ? retry(2) : res))
152
- .then(res => (!res.ok ? retry(3) : res))
153
- .then(res => (!res.ok ? retry(4) : res))
154
- .then(res => res.json())
155
- .then(async entry => ({
156
- ...entry,
157
- ownerAddress: await toAddress(entry.owner),
158
- }))
159
- //.then(x => (console.error(x), x))
160
- .then(x => JSON.stringify(x))
161
-
89
+ var result = ""
90
+ // fetch(`/tx/${id}`)
91
+ try {
92
+ let tx = ar.mem.txs[id]
93
+ if (tx) result = JSON.stringify(tx)
94
+ } catch (e) {}
162
95
  var node = FS.createDataFile(
163
96
  "/",
164
97
  "tx/" + id,
@@ -170,89 +103,25 @@ export default class WeaveDrive {
170
103
  return stream
171
104
  },
172
105
  async createDataItemTxHeader(id) {
173
- const gqlQuery = this.gqlQuery
174
- var GET_TRANSACTION_QUERY = `
175
- query GetTransactions ($transactionIds: [ID!]!) {
176
- transactions(ids: $transactionIds) {
177
- edges {
178
- node {
179
- id
180
- anchor
181
- data {
182
- size
183
- }
184
- signature
185
- recipient
186
- owner {
187
- address
188
- key
189
- }
190
- fee {
191
- ar
192
- winston
193
- }
194
- quantity {
195
- winston
196
- ar
197
- }
198
- tags {
199
- name
200
- value
201
- }
202
- bundledIn {
203
- id
204
- }
205
- block {
206
- id
207
- timestamp
208
- height
209
- previous
210
- }
211
- }
212
- }
213
- }
214
- }`
215
- var variables = { transactionIds: [id] }
216
- async function retry(x) {
217
- return new Promise(r => {
218
- setTimeout(function () {
219
- r(gqlQuery(GET_TRANSACTION_QUERY, variables))
220
- }, x * 10000)
106
+ let result = (
107
+ await ar.gql.txs({
108
+ id,
109
+ fields: [
110
+ "id",
111
+ "anchor",
112
+ { data: ["size"] },
113
+ "signature",
114
+ "recipient",
115
+ "owner",
116
+ "fee",
117
+ "quantity",
118
+ "tags",
119
+ "bundledIn",
120
+ "block",
121
+ ],
221
122
  })
222
- }
223
-
224
- const gqlExists = await this.gqlExists()
225
- if (!gqlExists) {
226
- return "GQL Not Found!"
227
- }
228
-
229
- // todo: add a bunch of retries
230
- var result = await this.gqlQuery(GET_TRANSACTION_QUERY, variables)
231
- .then(res => (!res.ok ? retry(1) : res))
232
- .then(res => (!res.ok ? retry(2) : res))
233
- .then(res => (!res.ok ? retry(3) : res))
234
- .then(res => (!res.ok ? retry(4) : res))
235
- .then(res => res.json())
236
- .then(res => {
237
- return res?.data?.transactions?.edges?.[0]?.node
238
- ? res.data.transactions.edges[0].node
239
- : "No results"
240
- })
241
- .then(async entry => {
242
- return typeof entry == "string"
243
- ? entry
244
- : {
245
- format: 3,
246
- ...entry,
247
- }
248
- })
249
- .then(x => {
250
- return typeof x == "string" ? x : JSON.stringify(x)
251
- })
252
-
253
- if (result === "No results") {
254
- return result
255
- }
123
+ )[0]
124
+ result = result ? JSON.stringify(result) : "No results"
256
125
  FS.createDataFile(
257
126
  "/",
258
127
  "tx2/" + id,
@@ -364,17 +233,9 @@ export default class WeaveDrive {
364
233
  )
365
234
  //console.log("WeaveDrive: fd: ", fd, " Read length: ", to_read, " Reading ahead:", to - to_read - stream.position)
366
235
 
367
- // Fetch with streaming
368
- /*
369
- const response = await this.customFetch(`/${stream.node.name}`, {
370
- method: "GET",
371
- redirect: "follow",
372
- headers: { Range: `bytes=${stream.position}-${to}` },
373
- })
374
-
375
- const reader = response.body.getReader()
376
- */
236
+ // fetch(`/${stream.node.name}`)
377
237
  const data = await ar.data(stream.node.name)
238
+
378
239
  // Extract the Range header to determine the start and end of the requested chunk
379
240
  const start = 0
380
241
  const end = data.length
@@ -465,9 +326,7 @@ export default class WeaveDrive {
465
326
  close(fd) {
466
327
  var stream = 0
467
328
  for (var i = 0; i < FS.streams.length; i++) {
468
- if (FS.streams[i].fd === fd) {
469
- stream = FS.streams[i]
470
- }
329
+ if (FS.streams[i].fd === fd) stream = FS.streams[i]
471
330
  }
472
331
  FS.close(stream)
473
332
  },
@@ -516,10 +375,9 @@ export default class WeaveDrive {
516
375
 
517
376
  // General helpder functions
518
377
  async checkAdmissible(ID) {
519
- if (mod.mode && mod.mode == "test") {
520
- // CAUTION: If the module is initiated with `mode = test` we don't check availability.
521
- return true
522
- }
378
+ // CAUTION: If the module is initiated with `mode = test` we don't check availability.
379
+ if (mod.mode && mod.mode == "test") return true
380
+
523
381
  // Check if we are attempting to load the On-Boot id, if so allow it
524
382
  // this was added for AOP 6 Boot loader See: https://github.com/permaweb/aos/issues/342
525
383
  const bootTag = this.getTagValue("On-Boot", mod.spawn.tags)
@@ -546,7 +404,6 @@ export default class WeaveDrive {
546
404
  )
547
405
  return false
548
406
  }
549
-
550
407
  const modes = ["Assignments", "Individual", "Library"]
551
408
  // Get the Availability-Type from the spawned process's Module or Process item
552
409
  // First check the module for its defaults
@@ -579,66 +436,30 @@ export default class WeaveDrive {
579
436
  )
580
437
  // Init a set of GraphQL queries to run in order to find a valid attestation
581
438
  // Every WeaveDrive process has at least the "Assignments" availability check form.
582
-
583
- const assignmentsHaveID = await this.queryHasResult(
584
- `query {
585
- transactions(
586
- owners: ${attestors},
587
- block: {min: 0, max: ${blockHeight}},
588
- tags: [
589
- { name: "Type", values: ["Attestation"] },
590
- { name: "Message", values: ["${ID}"]}
591
- { name: "Data-Protocol", values: ["ao"] },
592
- ]
593
- )
594
- {
595
- edges {
596
- node {
597
- tags {
598
- name
599
- value
600
- }
601
- }
439
+ const exists = async tags => {
440
+ const common = {
441
+ owners: attestors,
442
+ block: [0, blockHeight],
443
+ fields: ["tags"],
602
444
  }
445
+ return (await ar.gql.txs({ ...common, tags })).length > 0
603
446
  }
604
- }`,
605
- )
447
+ const assignmentsHaveID = await exists({
448
+ Type: "Attestation",
449
+ Message: ID,
450
+ "Data-Protocol": "ao",
451
+ })
606
452
  if (assignmentsHaveID) return true
607
453
 
608
454
  if (processMode == "Individual") {
609
- const individualsHaveID = await this.queryHasResult(
610
- `query {
611
- transactions(
612
- owners: ${attestors},
613
- block: {min: 0, max: ${blockHeight}},
614
- tags: [
615
- { name: "Type", values: ["Available"]},
616
- { name: "ID", values: ["${ID}"]}
617
- { name: "Data-Protocol", values: ["WeaveDrive"] },
618
- ]
619
- )
620
- {
621
- edges {
622
- node {
623
- tags {
624
- name
625
- value
626
- }
627
- }
628
- }
629
- }
630
- }`,
631
- )
632
-
455
+ const individualsHaveID = await exists({
456
+ Type: "Available",
457
+ ID,
458
+ "Data-Protocol": "WeaveDrive",
459
+ })
633
460
  if (individualsHaveID) return true
634
461
  }
635
462
 
636
- // Halt message processing if the process requires Library mode.
637
- // This should signal 'Cannot Process' to the CU, not that the message itself is
638
- // invalid. Subsequently, the CU should not be slashable for saying that the process
639
- // execution failed on this message. The CU must also not continue to execute further
640
- // messages on this process. Attesting to them would be slashable, as the state would
641
- // be incorrect.
642
463
  if (processMode == "Library") {
643
464
  throw "This WeaveDrive implementation does not support Library attestations yet!"
644
465
  }
@@ -653,9 +474,7 @@ export default class WeaveDrive {
653
474
  getTagValues(key, tags) {
654
475
  var values = []
655
476
  for (let i = 0; i < tags.length; i++) {
656
- if (tags[i].name == key) {
657
- values.push(tags[i].value)
658
- }
477
+ if (tags[i].name == key) values.push(tags[i].value)
659
478
  }
660
479
  return values
661
480
  },
@@ -664,51 +483,6 @@ export default class WeaveDrive {
664
483
  const values = this.getTagValues(key, tags)
665
484
  return values.pop()
666
485
  },
667
-
668
- async queryHasResult(query, variables) {
669
- const json = await this.gqlQuery(query, variables).then(res =>
670
- res.json(),
671
- )
672
- return !!json?.data?.transactions?.edges?.length
673
- },
674
-
675
- async gqlExists() {
676
- const query = `query {
677
- transactions(
678
- first: 1
679
- ) {
680
- pageInfo {
681
- hasNextPage
682
- }
683
- }
684
- }
685
- `
686
-
687
- const gqlExists = await this.gqlQuery(query, {}).then(res => res.ok)
688
- return gqlExists
689
- },
690
-
691
- async gqlQuery(query, variables) {
692
- let json = null
693
- try {
694
- const { tar, args } = toGraphObj({ query, variables })
695
- let res2 = null
696
- if (tar === "transactions") {
697
- res2 = await ar.gql.txs({ ...args })
698
- } else if (tar === "blocks") {
699
- res2 = await ar.gql.blocks({ ...args })
700
- }
701
- const edges = map(v => ({ node: v, cursor: v.cursor }), res2)
702
- json = {
703
- data: {
704
- transactions: { pageInfo: { hasNextPage: true }, edges },
705
- },
706
- }
707
- } catch (e) {
708
- log(e)
709
- }
710
- return { json: () => json }
711
- },
712
486
  }
713
487
  }
714
488
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wao",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",