autobee 2.6.0 → 2.7.0

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.
@@ -494,13 +494,14 @@ const encoding18 = {
494
494
  c.uint.preencode(state, m.flushes)
495
495
  encoding22.preencode(state, m.view)
496
496
  encoding18_3.preencode(state, m.heads)
497
- state.end++ // max flag is 2 so always one byte
497
+ state.end++ // max flag is 4 so always one byte
498
498
 
499
499
  if (m.indexers) encoding18_4.preencode(state, m.indexers)
500
500
  if (m.pending) encoding18_5.preencode(state, m.pending)
501
+ if (m.hash) c.fixed8.preencode(state, m.hash)
501
502
  },
502
503
  encode(state, m) {
503
- const flags = (m.indexers ? 1 : 0) | (m.pending ? 2 : 0)
504
+ const flags = (m.indexers ? 1 : 0) | (m.pending ? 2 : 0) | (m.hash ? 4 : 0)
504
505
 
505
506
  c.uint.encode(state, m.timestamp)
506
507
  c.uint.encode(state, m.flushes)
@@ -510,6 +511,7 @@ const encoding18 = {
510
511
 
511
512
  if (m.indexers) encoding18_4.encode(state, m.indexers)
512
513
  if (m.pending) encoding18_5.encode(state, m.pending)
514
+ if (m.hash) c.fixed8.encode(state, m.hash)
513
515
  },
514
516
  decode(state) {
515
517
  const v = c.uint.decode(state)
@@ -526,7 +528,8 @@ const encoding18 = {
526
528
  view: r2,
527
529
  heads: r3,
528
530
  indexers: (flags & 1) !== 0 ? encoding18_4.decode(state) : null,
529
- pending: (flags & 2) !== 0 ? encoding18_5.decode(state) : null
531
+ pending: (flags & 2) !== 0 ? encoding18_5.decode(state) : null,
532
+ hash: (flags & 4) !== 0 ? c.fixed8.decode(state) : null
530
533
  }
531
534
  }
532
535
  }
@@ -1215,9 +1218,19 @@ const encoding37_6 = c.array(encoding36)
1215
1218
  // @autobee/oplog-message-v4
1216
1219
  const encoding37 = {
1217
1220
  preencode(state, m) {
1221
+ const flags =
1222
+ (m.batch ? 1 : 0) |
1223
+ (m.views ? 2 : 0) |
1224
+ (m.trusted ? 4 : 0) |
1225
+ (m.witness ? 8 : 0) |
1226
+ (m.approvals ? 16 : 0) |
1227
+ (m.optimistic ? 32 : 0) |
1228
+ (m.value ? 64 : 0) |
1229
+ (m.hash ? 128 : 0)
1230
+
1218
1231
  c.uint.preencode(state, m.timestamp)
1219
1232
  encoding37_1.preencode(state, m.links)
1220
- state.end++ // max flag is 64 so always one byte
1233
+ c.uint.preencode(state, flags)
1221
1234
 
1222
1235
  if (m.batch) encoding24.preencode(state, m.batch)
1223
1236
  if (m.views) encoding25.preencode(state, m.views)
@@ -1225,6 +1238,7 @@ const encoding37 = {
1225
1238
  if (m.witness) encoding35.preencode(state, m.witness)
1226
1239
  if (m.approvals) encoding37_6.preencode(state, m.approvals)
1227
1240
  if (m.value) c.buffer.preencode(state, m.value)
1241
+ if (m.hash) c.fixed8.preencode(state, m.hash)
1228
1242
  },
1229
1243
  encode(state, m) {
1230
1244
  const flags =
@@ -1234,7 +1248,8 @@ const encoding37 = {
1234
1248
  (m.witness ? 8 : 0) |
1235
1249
  (m.approvals ? 16 : 0) |
1236
1250
  (m.optimistic ? 32 : 0) |
1237
- (m.value ? 64 : 0)
1251
+ (m.value ? 64 : 0) |
1252
+ (m.hash ? 128 : 0)
1238
1253
 
1239
1254
  c.uint.encode(state, m.timestamp)
1240
1255
  encoding37_1.encode(state, m.links)
@@ -1246,6 +1261,7 @@ const encoding37 = {
1246
1261
  if (m.witness) encoding35.encode(state, m.witness)
1247
1262
  if (m.approvals) encoding37_6.encode(state, m.approvals)
1248
1263
  if (m.value) c.buffer.encode(state, m.value)
1264
+ if (m.hash) c.fixed8.encode(state, m.hash)
1249
1265
  },
1250
1266
  decode(state) {
1251
1267
  const v = c.uint.decode(state)
@@ -1263,7 +1279,8 @@ const encoding37 = {
1263
1279
  witness: (flags & 8) !== 0 ? encoding35.decode(state) : null,
1264
1280
  approvals: (flags & 16) !== 0 ? encoding37_6.decode(state) : null,
1265
1281
  optimistic: (flags & 32) !== 0,
1266
- value: (flags & 64) !== 0 ? c.buffer.decode(state) : null
1282
+ value: (flags & 64) !== 0 ? c.buffer.decode(state) : null,
1283
+ hash: (flags & 128) !== 0 ? c.fixed8.decode(state) : null
1267
1284
  }
1268
1285
  }
1269
1286
  }
@@ -434,6 +434,11 @@
434
434
  "array": true,
435
435
  "type": "bool",
436
436
  "version": 1
437
+ },
438
+ {
439
+ "name": "hash",
440
+ "type": "fixed8",
441
+ "version": 1
437
442
  }
438
443
  ]
439
444
  },
@@ -1018,6 +1023,11 @@
1018
1023
  "name": "value",
1019
1024
  "type": "buffer",
1020
1025
  "version": 1
1026
+ },
1027
+ {
1028
+ "name": "hash",
1029
+ "type": "fixed8",
1030
+ "version": 1
1021
1031
  }
1022
1032
  ]
1023
1033
  }
package/index.js CHANGED
@@ -1196,9 +1196,14 @@ module.exports = class Autobee extends ReadyResource {
1196
1196
  node.weight = await resolveWeight(this, node)
1197
1197
  for (const n of batch) n.weight = node.weight
1198
1198
 
1199
- // if (topo.isLinkingAll(node, this.system.heads)) {
1200
- // return { undo: null, view: null, tip: [batch] }
1201
- // }
1199
+ if (
1200
+ node.hash &&
1201
+ this.system.hash &&
1202
+ b4a.equals(node.hash, this.system.hash) &&
1203
+ topo.isLinkingAll(node, this.system.heads)
1204
+ ) {
1205
+ return { undo: null, view: null, tip: [batch] }
1206
+ }
1202
1207
 
1203
1208
  const t = await topo.sort(this, batch)
1204
1209
 
@@ -1352,6 +1357,7 @@ module.exports = class Autobee extends ReadyResource {
1352
1357
  await this.local.ready()
1353
1358
 
1354
1359
  const links = this.system.getLinks(this.local.key)
1360
+ const hash = this.system.hash
1355
1361
 
1356
1362
  // never stamp before anything we link
1357
1363
  const t = Math.max(this._now(), this.system.timestamp)
@@ -1379,7 +1385,8 @@ module.exports = class Autobee extends ReadyResource {
1379
1385
  lnk,
1380
1386
  optimistic,
1381
1387
  i === 0 ? witness : null,
1382
- i === 0 ? approvals : null
1388
+ i === 0 ? approvals : null,
1389
+ i === 0 ? hash : null
1383
1390
  )
1384
1391
  batch.push(node)
1385
1392
  }
package/lib/system.js CHANGED
@@ -1,5 +1,7 @@
1
1
  const Hyperbee = require('hyperbee2')
2
2
  const Promotions = require('./promotions.js')
3
+ const sodium = require('sodium-native')
4
+ const c = require('compact-encoding')
3
5
  const b4a = require('b4a')
4
6
 
5
7
  const { getViewMap, getCoreManifest } = require('./migrations.js')
@@ -13,6 +15,10 @@ const INFO_LEGACY_KEY = b4a.concat([b4a.from([0, 0]), b4a.from('info')])
13
15
  const EMPTY_HEAD = { length: 0, key: null }
14
16
  const EMPTY = b4a.from([])
15
17
 
18
+ const HASH = c.fixed(sodium.crypto_shorthash_BYTES)
19
+ const HASH_KEY = b4a.from('autobee-orderkey') // crypto_shorthash_KEYBYTES
20
+ const HASH_SEED = b4a.alloc(sodium.crypto_shorthash_BYTES)
21
+
16
22
  class SystemSnapshot {
17
23
  constructor(bee) {
18
24
  this.bee = bee
@@ -41,6 +47,7 @@ module.exports = class Systembee {
41
47
  this.bee = new Hyperbee(store, opts)
42
48
  this.view = null
43
49
  this.heads = []
50
+ this.hash = null
44
51
  this.migration = null
45
52
  this.version = 0
46
53
  this.timestamp = 0
@@ -142,6 +149,7 @@ module.exports = class Systembee {
142
149
  this.view = info ? info.view : EMPTY_HEAD
143
150
  this.migration = null
144
151
  this.heads = info ? info.heads : []
152
+ this.hash = info ? info.hash : null
145
153
  this.timestamp = info ? info.timestamp : 0
146
154
  this.flushes = info ? info.flushes : 0
147
155
 
@@ -224,6 +232,8 @@ module.exports = class Systembee {
224
232
  this.heads.push({ key: node.key, length: node.length })
225
233
  if (node.timestamp > this.timestamp) this.timestamp = node.timestamp // TODO: support smoothing
226
234
 
235
+ this.hash = advanceHash(this.hash, node)
236
+
227
237
  // resolved sort weight, re-stamped on every reapplication - this is what
228
238
  // topo reads back out of the changes stream
229
239
  this.update(node.key, node.length, node.weight, -1, false, false, false, node.timestamp, null)
@@ -443,7 +453,8 @@ module.exports = class Systembee {
443
453
  timestamp: this.timestamp,
444
454
  flushes: this.flushes,
445
455
  indexers: null, // legacy
446
- pending: this.promotions.digest
456
+ pending: this.promotions.digest,
457
+ hash: this.hash
447
458
  }
448
459
 
449
460
  w.tryPut(INFO_KEY, encoding.encodeSystemInfo(info))
@@ -488,3 +499,24 @@ module.exports = class Systembee {
488
499
  return this.promotions.hint(key, opts)
489
500
  }
490
501
  }
502
+
503
+ function advanceHash(prev, node) {
504
+ const state = { start: 0, end: 0, buffer: null }
505
+
506
+ HASH.preencode(state, prev || HASH_SEED)
507
+ c.fixed32.preencode(state, node.key)
508
+ c.uint.preencode(state, node.length)
509
+ c.uint.preencode(state, node.weight)
510
+
511
+ state.buffer = b4a.allocUnsafe(state.end)
512
+
513
+ HASH.encode(state, prev || HASH_SEED)
514
+ c.fixed32.encode(state, node.key)
515
+ c.uint.encode(state, node.length)
516
+ c.uint.encode(state, node.weight)
517
+
518
+ const hash = b4a.allocUnsafe(sodium.crypto_shorthash_BYTES)
519
+ sodium.crypto_shorthash(hash, state.buffer, HASH_KEY)
520
+
521
+ return hash
522
+ }
package/lib/writers.js CHANGED
@@ -86,8 +86,17 @@ class ActiveWriters {
86
86
  return this.localWriter.getLatest()
87
87
  }
88
88
 
89
- appendLocal(value, timestamp, batch, links, optimistic, witness, approvals = null) {
90
- return this.localWriter.append(value, timestamp, batch, links, optimistic, witness, approvals)
89
+ appendLocal(value, timestamp, batch, links, optimistic, witness, approvals = null, hash = null) {
90
+ return this.localWriter.append(
91
+ value,
92
+ timestamp,
93
+ batch,
94
+ links,
95
+ optimistic,
96
+ witness,
97
+ approvals,
98
+ hash
99
+ )
91
100
  }
92
101
 
93
102
  async rotateLocalWriter(core) {
@@ -693,7 +702,7 @@ class Writer {
693
702
  return this.pending !== null
694
703
  }
695
704
 
696
- append(value, timestamp, batch, links, optimistic, witness, approvals = null) {
705
+ append(value, timestamp, batch, links, optimistic, witness, approvals = null, hash = null) {
697
706
  if (this.pending === null) this.pending = []
698
707
 
699
708
  const oplog = {
@@ -706,7 +715,8 @@ class Writer {
706
715
  witness: witness || null,
707
716
  approvals,
708
717
  optimistic: optimistic && !this.writers.writable,
709
- value
718
+ value,
719
+ hash
710
720
  }
711
721
 
712
722
  const node = createNode(this.core, this.appendLength++, -1, oplog)
@@ -783,7 +793,8 @@ function createNode(core, length, weight, oplog) {
783
793
  witness: oplog.witness || null,
784
794
  approvals: oplog.approvals || null,
785
795
  optimistic: oplog.optimistic,
786
- value: oplog.value
796
+ value: oplog.value,
797
+ hash: oplog.hash || null
787
798
  }
788
799
  }
789
800
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autobee",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "Bee based autobase",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Holepunch Inc.",
@@ -35,7 +35,8 @@
35
35
  "ready-guard": "^1.0.0",
36
36
  "ready-resource": "^1.2.0",
37
37
  "resolve-reject-promise": "^1.1.0",
38
- "safety-catch": "^1.0.3"
38
+ "safety-catch": "^1.0.3",
39
+ "sodium-native": "^5.1.0"
39
40
  },
40
41
  "devDependencies": {
41
42
  "brittle": "^4.1.0",