@optimystic/db-p2p-storage-rn 0.24.2 → 0.25.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/README.md +1 -1
- package/dist/src/keys.d.ts +8 -0
- package/dist/src/keys.d.ts.map +1 -1
- package/dist/src/keys.js +20 -2
- package/dist/src/keys.js.map +1 -1
- package/dist/src/leveldb-storage.d.ts +7 -2
- package/dist/src/leveldb-storage.d.ts.map +1 -1
- package/dist/src/leveldb-storage.js +19 -3
- package/dist/src/leveldb-storage.js.map +1 -1
- package/package.json +3 -3
- package/src/keys.ts +22 -2
- package/src/leveldb-storage.ts +227 -203
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ on-device LevelDB. Provides:
|
|
|
6
6
|
|
|
7
7
|
- **`LevelDBRawStorage`** — implements `IRawStorage` so an RN node persists
|
|
8
8
|
block metadata, revisions, pending transactions, committed transactions,
|
|
9
|
-
and materialized blocks.
|
|
9
|
+
commit proofs, and materialized blocks.
|
|
10
10
|
- **`LevelDBKVStore`** — implements `IKVStore` for the persistent
|
|
11
11
|
transaction state used to recover crashed two-phase commits.
|
|
12
12
|
- **`loadOrCreateRNPeerKey`** — generates an Ed25519 libp2p private key on
|
package/dist/src/keys.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - revisions: rev (8-byte big-endian unsigned via DataView.setBigUint64)
|
|
14
14
|
* - pending: actionId UTF-8 (terminal)
|
|
15
15
|
* - transactions: actionId UTF-8 (terminal)
|
|
16
|
+
* - proofs: rev (8-byte big-endian unsigned, same as revisions)
|
|
16
17
|
* - materialized: actionId UTF-8 (terminal)
|
|
17
18
|
*
|
|
18
19
|
* `kv` and `identity` keys are flat — no `blockId` envelope — under their
|
|
@@ -27,6 +28,7 @@ export declare const TAG_REVISIONS = 2;
|
|
|
27
28
|
export declare const TAG_PENDING = 3;
|
|
28
29
|
export declare const TAG_TRANSACTIONS = 4;
|
|
29
30
|
export declare const TAG_MATERIALIZED = 5;
|
|
31
|
+
export declare const TAG_PROOFS = 6;
|
|
30
32
|
export declare const TAG_KV = 16;
|
|
31
33
|
export declare const TAG_IDENTITY = 32;
|
|
32
34
|
export declare function metadataKey(blockId: string): Uint8Array;
|
|
@@ -49,6 +51,12 @@ export declare function revisionKey(blockId: string, rev: number): Uint8Array;
|
|
|
49
51
|
export declare function revisionFromKey(key: Uint8Array): number;
|
|
50
52
|
export declare function pendingKey(blockId: string, actionId: string): Uint8Array;
|
|
51
53
|
export declare function transactionKey(blockId: string, actionId: string): Uint8Array;
|
|
54
|
+
/**
|
|
55
|
+
* Proofs are keyed by `(blockId, rev)` with the SAME 8-byte big-endian rev suffix as
|
|
56
|
+
* `revisionKey`, under their own tag — deliberately not the action keyspace, since an
|
|
57
|
+
* action id is chosen by whoever originates a write (see `RawStoreDriver.getProof`).
|
|
58
|
+
*/
|
|
59
|
+
export declare function proofKey(blockId: string, rev: number): Uint8Array;
|
|
52
60
|
export declare function materializedKey(blockId: string, actionId: string): Uint8Array;
|
|
53
61
|
/** Returns the inclusive lower / exclusive upper range covering every key for `(tag, blockId, *)`. */
|
|
54
62
|
export declare function blockEnvelopeRange(tag: number, blockId: string): {
|
package/dist/src/keys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/keys.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,eAAO,MAAM,YAAY,IAAO,CAAC;AACjC,eAAO,MAAM,aAAa,IAAO,CAAC;AAClC,eAAO,MAAM,WAAW,IAAO,CAAC;AAChC,eAAO,MAAM,gBAAgB,IAAO,CAAC;AACrC,eAAO,MAAM,gBAAgB,IAAO,CAAC;AACrC,eAAO,MAAM,UAAU,IAAO,CAAC;AAC/B,eAAO,MAAM,MAAM,KAAO,CAAC;AAC3B,eAAO,MAAM,YAAY,KAAO,CAAC;AA0BjC,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAEvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,IAAI;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAE,CAEnE;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAI9D;AAeD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAEpE;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAGvD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAExE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAEjE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAE7E;AAED,sGAAsG;AACtG,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAE,CAapG;AAED,+FAA+F;AAC/F,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIxE;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAE7C;AAED,wGAAwG;AACxG,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAE,CAcjF;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAErD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAEvD"}
|
package/dist/src/keys.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - revisions: rev (8-byte big-endian unsigned via DataView.setBigUint64)
|
|
14
14
|
* - pending: actionId UTF-8 (terminal)
|
|
15
15
|
* - transactions: actionId UTF-8 (terminal)
|
|
16
|
+
* - proofs: rev (8-byte big-endian unsigned, same as revisions)
|
|
16
17
|
* - materialized: actionId UTF-8 (terminal)
|
|
17
18
|
*
|
|
18
19
|
* `kv` and `identity` keys are flat — no `blockId` envelope — under their
|
|
@@ -27,6 +28,7 @@ export const TAG_REVISIONS = 0x02;
|
|
|
27
28
|
export const TAG_PENDING = 0x03;
|
|
28
29
|
export const TAG_TRANSACTIONS = 0x04;
|
|
29
30
|
export const TAG_MATERIALIZED = 0x05;
|
|
31
|
+
export const TAG_PROOFS = 0x06;
|
|
30
32
|
export const TAG_KV = 0x10;
|
|
31
33
|
export const TAG_IDENTITY = 0x20;
|
|
32
34
|
const textEncoder = new TextEncoder();
|
|
@@ -71,13 +73,21 @@ export function blockIdFromMetadataKey(key) {
|
|
|
71
73
|
const blockIdLen = view.getUint32(1, false);
|
|
72
74
|
return textDecoder.decode(key.subarray(5, 5 + blockIdLen));
|
|
73
75
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
/**
|
|
77
|
+
* `tag || len(blockId) || blockId || rev (8 BE)`. The fixed-width big-endian suffix is
|
|
78
|
+
* what makes a rev-keyed store scan in numeric order; `revisionFromKey` decodes it back.
|
|
79
|
+
* Shared by every rev-keyed store so their encodings cannot drift apart.
|
|
80
|
+
*/
|
|
81
|
+
function revScopedKey(tag, blockId, rev) {
|
|
82
|
+
const envelope = encodeBlockEnvelope(tag, blockId);
|
|
76
83
|
const out = new Uint8Array(envelope.length + 8);
|
|
77
84
|
out.set(envelope, 0);
|
|
78
85
|
new DataView(out.buffer, out.byteOffset).setBigUint64(envelope.length, BigInt(rev), false);
|
|
79
86
|
return out;
|
|
80
87
|
}
|
|
88
|
+
export function revisionKey(blockId, rev) {
|
|
89
|
+
return revScopedKey(TAG_REVISIONS, blockId, rev);
|
|
90
|
+
}
|
|
81
91
|
/** Decode the trailing 8-byte big-endian rev from a `revisionKey`-encoded key. */
|
|
82
92
|
export function revisionFromKey(key) {
|
|
83
93
|
const view = new DataView(key.buffer, key.byteOffset, key.byteLength);
|
|
@@ -89,6 +99,14 @@ export function pendingKey(blockId, actionId) {
|
|
|
89
99
|
export function transactionKey(blockId, actionId) {
|
|
90
100
|
return concat(encodeBlockEnvelope(TAG_TRANSACTIONS, blockId), textEncoder.encode(actionId));
|
|
91
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Proofs are keyed by `(blockId, rev)` with the SAME 8-byte big-endian rev suffix as
|
|
104
|
+
* `revisionKey`, under their own tag — deliberately not the action keyspace, since an
|
|
105
|
+
* action id is chosen by whoever originates a write (see `RawStoreDriver.getProof`).
|
|
106
|
+
*/
|
|
107
|
+
export function proofKey(blockId, rev) {
|
|
108
|
+
return revScopedKey(TAG_PROOFS, blockId, rev);
|
|
109
|
+
}
|
|
92
110
|
export function materializedKey(blockId, actionId) {
|
|
93
111
|
return concat(encodeBlockEnvelope(TAG_MATERIALIZED, blockId), textEncoder.encode(actionId));
|
|
94
112
|
}
|
package/dist/src/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/keys.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ActionId, BlockId } from '@optimystic/db-core';
|
|
2
|
-
import { KvRawStorage, type RawStoreDriver } from '@optimystic/db-p2p';
|
|
2
|
+
import { KvRawStorage, type RawStoreDriver, type StoreIdentity } from '@optimystic/db-p2p';
|
|
3
3
|
import { type LevelDBLike } from './leveldb-like.js';
|
|
4
4
|
/**
|
|
5
|
-
* LevelDB {@link RawStoreDriver}: the
|
|
5
|
+
* LevelDB {@link RawStoreDriver}: the six logical block-storage stores mapped
|
|
6
6
|
* into a single ordered byte keyspace, partitioned by a leading tag byte (see
|
|
7
7
|
* `./keys.ts`). LevelDB is already one ordered byte-keyspace, so this driver is
|
|
8
8
|
* mostly key encoding — the tag-prefixed byte scheme in `keys.ts` stays in this
|
|
@@ -17,7 +17,9 @@ import { type LevelDBLike } from './leveldb-like.js';
|
|
|
17
17
|
*/
|
|
18
18
|
export declare class LevelDBStoreDriver implements RawStoreDriver {
|
|
19
19
|
private readonly db;
|
|
20
|
+
private readonly identity;
|
|
20
21
|
constructor(db: LevelDBLike);
|
|
22
|
+
storeIdentity(): StoreIdentity;
|
|
21
23
|
getMetadata(blockId: BlockId): Promise<Uint8Array | undefined>;
|
|
22
24
|
putMetadata(blockId: BlockId, value: Uint8Array): Promise<void>;
|
|
23
25
|
getRevision(blockId: BlockId, rev: number): Promise<Uint8Array | undefined>;
|
|
@@ -29,6 +31,8 @@ export declare class LevelDBStoreDriver implements RawStoreDriver {
|
|
|
29
31
|
listPendingActionIds(blockId: BlockId): AsyncIterable<ActionId>;
|
|
30
32
|
getTransaction(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
|
|
31
33
|
putTransaction(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
|
|
34
|
+
getProof(blockId: BlockId, rev: number): Promise<Uint8Array | undefined>;
|
|
35
|
+
putProof(blockId: BlockId, rev: number, value: Uint8Array): Promise<void>;
|
|
32
36
|
getMaterialized(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined>;
|
|
33
37
|
putMaterialized(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void>;
|
|
34
38
|
deleteMaterialized(blockId: BlockId, actionId: ActionId): Promise<void>;
|
|
@@ -51,6 +55,7 @@ export declare class LevelDBStoreDriver implements RawStoreDriver {
|
|
|
51
55
|
export declare class LevelDBRawStorage extends KvRawStorage {
|
|
52
56
|
listBlockIds: () => AsyncIterable<BlockId>;
|
|
53
57
|
getApproximateBytesUsed: () => Promise<number>;
|
|
58
|
+
getStoreIdentity: () => StoreIdentity;
|
|
54
59
|
constructor(db: LevelDBLike);
|
|
55
60
|
}
|
|
56
61
|
//# sourceMappingURL=leveldb-storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leveldb-storage.d.ts","sourceRoot":"","sources":["../../src/leveldb-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"leveldb-storage.d.ts","sourceRoot":"","sources":["../../src/leveldb-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { KvRawStorage } from '@optimystic/db-p2p';
|
|
1
|
+
import { KvRawStorage, identityForHandle } from '@optimystic/db-p2p';
|
|
2
2
|
import { drain } from './leveldb-like.js';
|
|
3
|
-
import { TAG_PENDING, actionIdFromKey, blockEnvelopeRange, blockIdFromMetadataKey, materializedKey, metadataKey, metadataRange, pendingKey, revisionFromKey, revisionKey, transactionKey, } from './keys.js';
|
|
3
|
+
import { TAG_PENDING, actionIdFromKey, blockEnvelopeRange, blockIdFromMetadataKey, materializedKey, metadataKey, metadataRange, pendingKey, proofKey, revisionFromKey, revisionKey, transactionKey, } from './keys.js';
|
|
4
4
|
import { createLogger } from './logger.js';
|
|
5
5
|
const log = createLogger('storage:leveldb');
|
|
6
6
|
/**
|
|
7
|
-
* LevelDB {@link RawStoreDriver}: the
|
|
7
|
+
* LevelDB {@link RawStoreDriver}: the six logical block-storage stores mapped
|
|
8
8
|
* into a single ordered byte keyspace, partitioned by a leading tag byte (see
|
|
9
9
|
* `./keys.ts`). LevelDB is already one ordered byte-keyspace, so this driver is
|
|
10
10
|
* mostly key encoding — the tag-prefixed byte scheme in `keys.ts` stays in this
|
|
@@ -19,8 +19,17 @@ const log = createLogger('storage:leveldb');
|
|
|
19
19
|
*/
|
|
20
20
|
export class LevelDBStoreDriver {
|
|
21
21
|
db;
|
|
22
|
+
// NOTE: identity is the HANDLE object, so two handles opened over the same LevelDB PATH read
|
|
23
|
+
// as two identities. Resolving that would mean naming the underlying on-disk path, which
|
|
24
|
+
// `LevelDBLike` does not expose. The package opener (`rn-opener.ts`) hands out one handle per
|
|
25
|
+
// path in practice, so this is the reachable case, not the complete one.
|
|
26
|
+
identity;
|
|
22
27
|
constructor(db) {
|
|
23
28
|
this.db = db;
|
|
29
|
+
this.identity = identityForHandle('leveldb-handle', db);
|
|
30
|
+
}
|
|
31
|
+
storeIdentity() {
|
|
32
|
+
return this.identity;
|
|
24
33
|
}
|
|
25
34
|
// --- metadata ---
|
|
26
35
|
async getMetadata(blockId) {
|
|
@@ -74,6 +83,13 @@ export class LevelDBStoreDriver {
|
|
|
74
83
|
async putTransaction(blockId, actionId, value) {
|
|
75
84
|
await this.db.put(transactionKey(blockId, actionId), value);
|
|
76
85
|
}
|
|
86
|
+
// --- proofs (own tag byte; no delete — see RawStoreDriver.getProof) ---
|
|
87
|
+
async getProof(blockId, rev) {
|
|
88
|
+
return this.db.get(proofKey(blockId, rev));
|
|
89
|
+
}
|
|
90
|
+
async putProof(blockId, rev, value) {
|
|
91
|
+
await this.db.put(proofKey(blockId, rev), value);
|
|
92
|
+
}
|
|
77
93
|
// --- materialized ---
|
|
78
94
|
async getMaterialized(blockId, actionId) {
|
|
79
95
|
return this.db.get(materializedKey(blockId, actionId));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leveldb-storage.js","sourceRoot":"","sources":["../../src/leveldb-storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"leveldb-storage.js","sourceRoot":"","sources":["../../src/leveldb-storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAA2C,MAAM,oBAAoB,CAAC;AAC9G,OAAO,EAAE,KAAK,EAAoB,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACN,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,EACf,WAAW,EACX,aAAa,EACb,UAAU,EACV,QAAQ,EACR,eAAe,EACf,WAAW,EACX,cAAc,GACd,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,GAAG,GAAG,YAAY,CAAC,iBAAiB,CAAC,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,kBAAkB;IAOD;IAN7B,6FAA6F;IAC7F,yFAAyF;IACzF,8FAA8F;IAC9F,yEAAyE;IACxD,QAAQ,CAAgB;IAEzC,YAA6B,EAAe;QAAf,OAAE,GAAF,EAAE,CAAa;QAC3C,IAAI,CAAC,QAAQ,GAAG,iBAAiB,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,aAAa;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED,mBAAmB;IAEnB,KAAK,CAAC,WAAW,CAAC,OAAgB;QACjC,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAgB,EAAE,KAAiB;QACpD,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IAED,oBAAoB;IAEpB,KAAK,CAAC,WAAW,CAAC,OAAgB,EAAE,GAAW;QAC9C,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAgB,EAAE,GAAW,EAAE,KAAiB;QACjE,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,CAAC,cAAc,CAAC,OAAgB,EAAE,EAAU,EAAE,EAAU,EAAE,OAAgB;QAC/E,+EAA+E;QAC/E,6EAA6E;QAC7E,gFAAgF;QAChF,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;QACxC,8EAA8E;QAC9E,oEAAoE;QACpE,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QACpE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;YACpC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IAED,kBAAkB;IAElB,KAAK,CAAC,UAAU,CAAC,OAAgB,EAAE,QAAkB;QACpD,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAgB,EAAE,QAAkB,EAAE,KAAiB;QACvE,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAgB,EAAE,QAAkB;QACvD,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,CAAC,oBAAoB,CAAC,OAAgB;QAC3C,MAAM,KAAK,GAAG,kBAAkB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACvD,2DAA2D;QAC3D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC5F,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,eAAe,CAAC,GAAG,EAAE,OAAO,CAAa,CAAC;QACjD,CAAC;IACF,CAAC;IAED,uBAAuB;IAEvB,KAAK,CAAC,cAAc,CAAC,OAAgB,EAAE,QAAkB;QACxD,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAAgB,EAAE,QAAkB,EAAE,KAAiB;QAC3E,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,yEAAyE;IAEzE,KAAK,CAAC,QAAQ,CAAC,OAAgB,EAAE,GAAW;QAC3C,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAgB,EAAE,GAAW,EAAE,KAAiB;QAC9D,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IAED,uBAAuB;IAEvB,KAAK,CAAC,eAAe,CAAC,OAAgB,EAAE,QAAkB;QACzD,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,OAAgB,EAAE,QAAkB,EAAE,KAAiB;QAC5E,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAC9D,CAAC;IAED,8EAA8E;IAC9E,0CAA0C;IAC1C,KAAK,CAAC,kBAAkB,CAAC,OAAgB,EAAE,QAAkB;QAC5D,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,iDAAiD;IAEjD,KAAK,CAAC,OAAO,CAAC,OAAgB,EAAE,QAAkB;QACjD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,wBAAwB,OAAO,EAAE,CAAC,CAAC;QAC9E,CAAC;QACD,wEAAwE;QACxE,sDAAsD;QACtD,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,IAAI,CAAC,EAAE;aACX,KAAK,EAAE;aACP,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC;aAChB,MAAM,CAAC,IAAI,CAAC;aACZ,KAAK,EAAE,CAAC;IACX,CAAC;IAED,gCAAgC;IAEhC,KAAK,CAAC,CAAC,YAAY;QAClB,0EAA0E;QAC1E,0EAA0E;QAC1E,yEAAyE;QACzE,sDAAsD;QACtD,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC5F,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,sBAAsB,CAAC,GAAG,CAAY,CAAC;QAC9C,CAAC;IACF,CAAC;IAED,0EAA0E;IAC1E,6EAA6E;IAC7E,0EAA0E;IAC1E,2DAA2D;IAC3D,KAAK,CAAC,oBAAoB;QACzB,IAAI,CAAC;YACJ,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;YAChC,IAAI,CAAC;gBACJ,OAAO,IAAI,EAAE,CAAC;oBACb,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;oBAChC,IAAI,CAAC,KAAK;wBAAE,MAAM;oBAClB,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;gBACpD,CAAC;YACF,CAAC;oBAAS,CAAC;gBACV,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YACpB,CAAC;YACD,OAAO,KAAK,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,0CAA0C,EAAE,GAAG,CAAC,CAAC;YACrD,OAAO,CAAC,CAAC;QACV,CAAC;IACF,CAAC;CAOD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,iBAAkB,SAAQ,YAAY;IAKlD,YAAY,EAAe;QAC1B,KAAK,CAAC,IAAI,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;CACD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optimystic/db-p2p-storage-rn",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "React Native LevelDB storage backend for @optimystic/db-p2p",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"typescript": "^5.9.3"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@optimystic/db-core": "^0.
|
|
58
|
-
"@optimystic/db-p2p": "^0.
|
|
57
|
+
"@optimystic/db-core": "^0.25.1",
|
|
58
|
+
"@optimystic/db-p2p": "^0.25.1",
|
|
59
59
|
"debug": "^4.4.3"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
package/src/keys.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - revisions: rev (8-byte big-endian unsigned via DataView.setBigUint64)
|
|
14
14
|
* - pending: actionId UTF-8 (terminal)
|
|
15
15
|
* - transactions: actionId UTF-8 (terminal)
|
|
16
|
+
* - proofs: rev (8-byte big-endian unsigned, same as revisions)
|
|
16
17
|
* - materialized: actionId UTF-8 (terminal)
|
|
17
18
|
*
|
|
18
19
|
* `kv` and `identity` keys are flat — no `blockId` envelope — under their
|
|
@@ -28,6 +29,7 @@ export const TAG_REVISIONS = 0x02;
|
|
|
28
29
|
export const TAG_PENDING = 0x03;
|
|
29
30
|
export const TAG_TRANSACTIONS = 0x04;
|
|
30
31
|
export const TAG_MATERIALIZED = 0x05;
|
|
32
|
+
export const TAG_PROOFS = 0x06;
|
|
31
33
|
export const TAG_KV = 0x10;
|
|
32
34
|
export const TAG_IDENTITY = 0x20;
|
|
33
35
|
|
|
@@ -78,14 +80,23 @@ export function blockIdFromMetadataKey(key: Uint8Array): string {
|
|
|
78
80
|
return textDecoder.decode(key.subarray(5, 5 + blockIdLen));
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
/**
|
|
84
|
+
* `tag || len(blockId) || blockId || rev (8 BE)`. The fixed-width big-endian suffix is
|
|
85
|
+
* what makes a rev-keyed store scan in numeric order; `revisionFromKey` decodes it back.
|
|
86
|
+
* Shared by every rev-keyed store so their encodings cannot drift apart.
|
|
87
|
+
*/
|
|
88
|
+
function revScopedKey(tag: number, blockId: string, rev: number): Uint8Array {
|
|
89
|
+
const envelope = encodeBlockEnvelope(tag, blockId);
|
|
83
90
|
const out = new Uint8Array(envelope.length + 8);
|
|
84
91
|
out.set(envelope, 0);
|
|
85
92
|
new DataView(out.buffer, out.byteOffset).setBigUint64(envelope.length, BigInt(rev), false);
|
|
86
93
|
return out;
|
|
87
94
|
}
|
|
88
95
|
|
|
96
|
+
export function revisionKey(blockId: string, rev: number): Uint8Array {
|
|
97
|
+
return revScopedKey(TAG_REVISIONS, blockId, rev);
|
|
98
|
+
}
|
|
99
|
+
|
|
89
100
|
/** Decode the trailing 8-byte big-endian rev from a `revisionKey`-encoded key. */
|
|
90
101
|
export function revisionFromKey(key: Uint8Array): number {
|
|
91
102
|
const view = new DataView(key.buffer, key.byteOffset, key.byteLength);
|
|
@@ -100,6 +111,15 @@ export function transactionKey(blockId: string, actionId: string): Uint8Array {
|
|
|
100
111
|
return concat(encodeBlockEnvelope(TAG_TRANSACTIONS, blockId), textEncoder.encode(actionId));
|
|
101
112
|
}
|
|
102
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Proofs are keyed by `(blockId, rev)` with the SAME 8-byte big-endian rev suffix as
|
|
116
|
+
* `revisionKey`, under their own tag — deliberately not the action keyspace, since an
|
|
117
|
+
* action id is chosen by whoever originates a write (see `RawStoreDriver.getProof`).
|
|
118
|
+
*/
|
|
119
|
+
export function proofKey(blockId: string, rev: number): Uint8Array {
|
|
120
|
+
return revScopedKey(TAG_PROOFS, blockId, rev);
|
|
121
|
+
}
|
|
122
|
+
|
|
103
123
|
export function materializedKey(blockId: string, actionId: string): Uint8Array {
|
|
104
124
|
return concat(encodeBlockEnvelope(TAG_MATERIALIZED, blockId), textEncoder.encode(actionId));
|
|
105
125
|
}
|
package/src/leveldb-storage.ts
CHANGED
|
@@ -1,203 +1,227 @@
|
|
|
1
|
-
import type { ActionId, BlockId } from '@optimystic/db-core';
|
|
2
|
-
import { KvRawStorage, type RawStoreDriver } from '@optimystic/db-p2p';
|
|
3
|
-
import { drain, type LevelDBLike } from './leveldb-like.js';
|
|
4
|
-
import {
|
|
5
|
-
TAG_PENDING,
|
|
6
|
-
actionIdFromKey,
|
|
7
|
-
blockEnvelopeRange,
|
|
8
|
-
blockIdFromMetadataKey,
|
|
9
|
-
materializedKey,
|
|
10
|
-
metadataKey,
|
|
11
|
-
metadataRange,
|
|
12
|
-
pendingKey,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* values
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
await this.db.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
await this.db.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
1
|
+
import type { ActionId, BlockId } from '@optimystic/db-core';
|
|
2
|
+
import { KvRawStorage, identityForHandle, type RawStoreDriver, type StoreIdentity } from '@optimystic/db-p2p';
|
|
3
|
+
import { drain, type LevelDBLike } from './leveldb-like.js';
|
|
4
|
+
import {
|
|
5
|
+
TAG_PENDING,
|
|
6
|
+
actionIdFromKey,
|
|
7
|
+
blockEnvelopeRange,
|
|
8
|
+
blockIdFromMetadataKey,
|
|
9
|
+
materializedKey,
|
|
10
|
+
metadataKey,
|
|
11
|
+
metadataRange,
|
|
12
|
+
pendingKey,
|
|
13
|
+
proofKey,
|
|
14
|
+
revisionFromKey,
|
|
15
|
+
revisionKey,
|
|
16
|
+
transactionKey,
|
|
17
|
+
} from './keys.js';
|
|
18
|
+
import { createLogger } from './logger.js';
|
|
19
|
+
|
|
20
|
+
const log = createLogger('storage:leveldb');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* LevelDB {@link RawStoreDriver}: the six logical block-storage stores mapped
|
|
24
|
+
* into a single ordered byte keyspace, partitioned by a leading tag byte (see
|
|
25
|
+
* `./keys.ts`). LevelDB is already one ordered byte-keyspace, so this driver is
|
|
26
|
+
* mostly key encoding — the tag-prefixed byte scheme in `keys.ts` stays in this
|
|
27
|
+
* package; the kernel deals in logical keys.
|
|
28
|
+
*
|
|
29
|
+
* `KvRawStorage` now owns all JSON/UTF-8 serialization, so this driver only ever
|
|
30
|
+
* reads/writes raw `Uint8Array` values — no `TextEncoder`/`TextDecoder` for
|
|
31
|
+
* values, and no `JSON.parse`/`stringify`. A value round-trips as the exact bytes
|
|
32
|
+
* the kernel wrote. Everything LevelDB-specific stays here: the tag-range scans
|
|
33
|
+
* (drained snapshot-first before yielding, so a native iterator never straddles a
|
|
34
|
+
* consumer's `await`), and the single `WriteBatch` that makes `promote` atomic.
|
|
35
|
+
*/
|
|
36
|
+
export class LevelDBStoreDriver implements RawStoreDriver {
|
|
37
|
+
// NOTE: identity is the HANDLE object, so two handles opened over the same LevelDB PATH read
|
|
38
|
+
// as two identities. Resolving that would mean naming the underlying on-disk path, which
|
|
39
|
+
// `LevelDBLike` does not expose. The package opener (`rn-opener.ts`) hands out one handle per
|
|
40
|
+
// path in practice, so this is the reachable case, not the complete one.
|
|
41
|
+
private readonly identity: StoreIdentity;
|
|
42
|
+
|
|
43
|
+
constructor(private readonly db: LevelDBLike) {
|
|
44
|
+
this.identity = identityForHandle('leveldb-handle', db);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
storeIdentity(): StoreIdentity {
|
|
48
|
+
return this.identity;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// --- metadata ---
|
|
52
|
+
|
|
53
|
+
async getMetadata(blockId: BlockId): Promise<Uint8Array | undefined> {
|
|
54
|
+
return this.db.get(metadataKey(blockId));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async putMetadata(blockId: BlockId, value: Uint8Array): Promise<void> {
|
|
58
|
+
await this.db.put(metadataKey(blockId), value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// --- revisions ---
|
|
62
|
+
|
|
63
|
+
async getRevision(blockId: BlockId, rev: number): Promise<Uint8Array | undefined> {
|
|
64
|
+
return this.db.get(revisionKey(blockId, rev));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async putRevision(blockId: BlockId, rev: number, value: Uint8Array): Promise<void> {
|
|
68
|
+
await this.db.put(revisionKey(blockId, rev), value);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async *rangeRevisions(blockId: BlockId, lo: number, hi: number, reverse: boolean): AsyncIterable<[number, Uint8Array]> {
|
|
72
|
+
// Revs are encoded 8-byte big-endian (`revisionKey`), so byte order == numeric
|
|
73
|
+
// order and `revisionKey(blockId, hi)` is exactly the inclusive upper bound;
|
|
74
|
+
// LevelDB's upper bound is exclusive (`lt`), so use `lt = revisionKey(hi + 1)`.
|
|
75
|
+
const gte = revisionKey(blockId, lo);
|
|
76
|
+
const lt = revisionKey(blockId, hi + 1);
|
|
77
|
+
// Drain before yielding — a native LevelDB iterator must not stay open across
|
|
78
|
+
// the consumer's awaits (the kernel's drain-before-yield contract).
|
|
79
|
+
const entries = await drain(this.db.iterator({ gte, lt, reverse }));
|
|
80
|
+
for (const [key, value] of entries) {
|
|
81
|
+
yield [revisionFromKey(key), value];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// --- pending ---
|
|
86
|
+
|
|
87
|
+
async getPending(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined> {
|
|
88
|
+
return this.db.get(pendingKey(blockId, actionId));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async putPending(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void> {
|
|
92
|
+
await this.db.put(pendingKey(blockId, actionId), value);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async deletePending(blockId: BlockId, actionId: ActionId): Promise<void> {
|
|
96
|
+
await this.db.delete(pendingKey(blockId, actionId));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async *listPendingActionIds(blockId: BlockId): AsyncIterable<ActionId> {
|
|
100
|
+
const range = blockEnvelopeRange(TAG_PENDING, blockId);
|
|
101
|
+
// Drain before yielding, same rationale as rangeRevisions.
|
|
102
|
+
const entries = await drain(this.db.iterator({ gte: range.gte, lt: range.lt, keys: true }));
|
|
103
|
+
for (const [key] of entries) {
|
|
104
|
+
yield actionIdFromKey(key, blockId) as ActionId;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// --- transactions ---
|
|
109
|
+
|
|
110
|
+
async getTransaction(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined> {
|
|
111
|
+
return this.db.get(transactionKey(blockId, actionId));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async putTransaction(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void> {
|
|
115
|
+
await this.db.put(transactionKey(blockId, actionId), value);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// --- proofs (own tag byte; no delete — see RawStoreDriver.getProof) ---
|
|
119
|
+
|
|
120
|
+
async getProof(blockId: BlockId, rev: number): Promise<Uint8Array | undefined> {
|
|
121
|
+
return this.db.get(proofKey(blockId, rev));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async putProof(blockId: BlockId, rev: number, value: Uint8Array): Promise<void> {
|
|
125
|
+
await this.db.put(proofKey(blockId, rev), value);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// --- materialized ---
|
|
129
|
+
|
|
130
|
+
async getMaterialized(blockId: BlockId, actionId: ActionId): Promise<Uint8Array | undefined> {
|
|
131
|
+
return this.db.get(materializedKey(blockId, actionId));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async putMaterialized(blockId: BlockId, actionId: ActionId, value: Uint8Array): Promise<void> {
|
|
135
|
+
await this.db.put(materializedKey(blockId, actionId), value);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// The kernel owns the put-or-delete branch of `saveMaterializedBlock`, so the
|
|
139
|
+
// driver exposes delete as a separate op.
|
|
140
|
+
async deleteMaterialized(blockId: BlockId, actionId: ActionId): Promise<void> {
|
|
141
|
+
await this.db.delete(materializedKey(blockId, actionId));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// --- promote (the only cross-key atomic op) ---
|
|
145
|
+
|
|
146
|
+
async promote(blockId: BlockId, actionId: ActionId): Promise<void> {
|
|
147
|
+
const pKey = pendingKey(blockId, actionId);
|
|
148
|
+
const value = await this.db.get(pKey);
|
|
149
|
+
if (!value) {
|
|
150
|
+
throw new Error(`Pending action ${actionId} not found for block ${blockId}`);
|
|
151
|
+
}
|
|
152
|
+
// The single `WriteBatch` IS the atomic move: a crash leaves either the
|
|
153
|
+
// pending or the committed entry, never both/neither.
|
|
154
|
+
const tKey = transactionKey(blockId, actionId);
|
|
155
|
+
await this.db
|
|
156
|
+
.batch()
|
|
157
|
+
.put(tKey, value)
|
|
158
|
+
.delete(pKey)
|
|
159
|
+
.write();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// --- optional passthroughs ---
|
|
163
|
+
|
|
164
|
+
async *listBlockIds(): AsyncIterable<BlockId> {
|
|
165
|
+
// Scan the whole TAG_METADATA keyspace; each metadata key is one distinct
|
|
166
|
+
// block id (empty suffix). keys:true skips values — we only need the ids.
|
|
167
|
+
// Drained before yielding (same discipline as the range scans): a native
|
|
168
|
+
// iterator must not stay open across consumer awaits.
|
|
169
|
+
const range = metadataRange();
|
|
170
|
+
const entries = await drain(this.db.iterator({ gte: range.gte, lt: range.lt, keys: true }));
|
|
171
|
+
for (const [key] of entries) {
|
|
172
|
+
yield blockIdFromMetadataKey(key) as BlockId;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// NOTE: full-scan byte sum — O(total bytes) per call. Fine as an advisory
|
|
177
|
+
// StorageMonitor input at current sizes; if a StorageMonitor ever polls this
|
|
178
|
+
// on a large db, replace with the kernel's incremental write-path counter
|
|
179
|
+
// (see the seam NOTE in kv-raw-storage.ts's saveMetadata).
|
|
180
|
+
async approximateBytesUsed(): Promise<number> {
|
|
181
|
+
try {
|
|
182
|
+
let total = 0;
|
|
183
|
+
const iter = this.db.iterator();
|
|
184
|
+
try {
|
|
185
|
+
while (true) {
|
|
186
|
+
const entry = await iter.next();
|
|
187
|
+
if (!entry) break;
|
|
188
|
+
total += entry[0].byteLength + entry[1].byteLength;
|
|
189
|
+
}
|
|
190
|
+
} finally {
|
|
191
|
+
await iter.close();
|
|
192
|
+
}
|
|
193
|
+
return total;
|
|
194
|
+
} catch (err) {
|
|
195
|
+
log('approximateBytesUsed iterator failed: %o', err);
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// NOTE: intentionally NO close(). The `LevelDBLike` handle is shared with
|
|
201
|
+
// `LevelDBKVStore` and `loadOrCreateRNPeerKey` (one db per RN peer — see the
|
|
202
|
+
// README usage), so the driver must not own its lifecycle; closing it here
|
|
203
|
+
// would break the other two. Same rationale as the IndexedDB driver. The
|
|
204
|
+
// kernel never wires the optional close() regardless.
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* LevelDB-backed {@link IRawStorage} for React Native peers, now a thin shell
|
|
209
|
+
* over the shared {@link KvRawStorage} kernel driven by a {@link LevelDBStoreDriver}.
|
|
210
|
+
* The public name/constructor (`new LevelDBRawStorage(db)`) is unchanged so
|
|
211
|
+
* existing imports keep resolving; the kernel supplies the `IRawStorage` surface
|
|
212
|
+
* and the driver supplies LevelDB behavior.
|
|
213
|
+
*
|
|
214
|
+
* `listBlockIds`/`getApproximateBytesUsed` are re-declared here as always-present
|
|
215
|
+
* (the LevelDB driver always implements them, so the kernel constructor always
|
|
216
|
+
* wires them) — the base declares them optional, but every RN consumer relies on
|
|
217
|
+
* them.
|
|
218
|
+
*/
|
|
219
|
+
export class LevelDBRawStorage extends KvRawStorage {
|
|
220
|
+
declare listBlockIds: () => AsyncIterable<BlockId>;
|
|
221
|
+
declare getApproximateBytesUsed: () => Promise<number>;
|
|
222
|
+
declare getStoreIdentity: () => StoreIdentity;
|
|
223
|
+
|
|
224
|
+
constructor(db: LevelDBLike) {
|
|
225
|
+
super(new LevelDBStoreDriver(db));
|
|
226
|
+
}
|
|
227
|
+
}
|