@enbox/dwn-sdk-js 0.0.6 → 0.0.8
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/dist/browser.mjs +8 -8
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/generated/precompiled-validators.js +762 -911
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/core/abstract-message.js +4 -0
- package/dist/esm/src/core/abstract-message.js.map +1 -1
- package/dist/esm/src/core/auth.js +22 -33
- package/dist/esm/src/core/auth.js.map +1 -1
- package/dist/esm/src/core/constants.js +11 -0
- package/dist/esm/src/core/constants.js.map +1 -0
- package/dist/esm/src/core/core-protocol.js +44 -0
- package/dist/esm/src/core/core-protocol.js.map +1 -0
- package/dist/esm/src/core/dwn-constant.js +7 -7
- package/dist/esm/src/core/dwn-constant.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +10 -12
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/grant-authorization.js +50 -52
- package/dist/esm/src/core/grant-authorization.js.map +1 -1
- package/dist/esm/src/core/message.js +85 -116
- package/dist/esm/src/core/message.js.map +1 -1
- package/dist/esm/src/core/messages-grant-authorization.js +63 -78
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-action.js +266 -0
- package/dist/esm/src/core/protocol-authorization-action.js.map +1 -0
- package/dist/esm/src/core/protocol-authorization-validation.js +321 -0
- package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -0
- package/dist/esm/src/core/protocol-authorization.js +144 -741
- package/dist/esm/src/core/protocol-authorization.js.map +1 -1
- package/dist/esm/src/core/protocols-grant-authorization.js +24 -38
- package/dist/esm/src/core/protocols-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/record-chain.js +64 -0
- package/dist/esm/src/core/record-chain.js.map +1 -0
- package/dist/esm/src/core/records-grant-authorization.js +53 -72
- package/dist/esm/src/core/records-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/resumable-task-manager.js +50 -65
- package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
- package/dist/esm/src/core/tenant-gate.js +2 -13
- package/dist/esm/src/core/tenant-gate.js.map +1 -1
- package/dist/esm/src/dwn.js +108 -101
- package/dist/esm/src/dwn.js.map +1 -1
- package/dist/esm/src/event-stream/event-emitter-event-log.js +204 -0
- package/dist/esm/src/event-stream/event-emitter-event-log.js.map +1 -0
- package/dist/esm/src/handlers/messages-read.js +67 -81
- package/dist/esm/src/handlers/messages-read.js.map +1 -1
- package/dist/esm/src/handlers/messages-subscribe.js +51 -63
- package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/messages-sync.js +75 -89
- package/dist/esm/src/handlers/messages-sync.js.map +1 -1
- package/dist/esm/src/handlers/protocols-configure.js +153 -163
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
- package/dist/esm/src/handlers/protocols-query.js +52 -55
- package/dist/esm/src/handlers/protocols-query.js.map +1 -1
- package/dist/esm/src/handlers/records-count.js +97 -85
- package/dist/esm/src/handlers/records-count.js.map +1 -1
- package/dist/esm/src/handlers/records-delete.js +75 -93
- package/dist/esm/src/handlers/records-delete.js.map +1 -1
- package/dist/esm/src/handlers/records-query.js +116 -105
- package/dist/esm/src/handlers/records-query.js.map +1 -1
- package/dist/esm/src/handlers/records-read.js +130 -132
- package/dist/esm/src/handlers/records-read.js.map +1 -1
- package/dist/esm/src/handlers/records-subscribe.js +164 -104
- package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +213 -280
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/index.js +5 -2
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/messages-read.js +24 -32
- package/dist/esm/src/interfaces/messages-read.js.map +1 -1
- package/dist/esm/src/interfaces/messages-subscribe.js +28 -41
- package/dist/esm/src/interfaces/messages-subscribe.js.map +1 -1
- package/dist/esm/src/interfaces/messages-sync.js +26 -40
- package/dist/esm/src/interfaces/messages-sync.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-configure.js +87 -65
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-query.js +55 -68
- package/dist/esm/src/interfaces/protocols-query.js.map +1 -1
- package/dist/esm/src/interfaces/records-count.js +50 -66
- package/dist/esm/src/interfaces/records-count.js.map +1 -1
- package/dist/esm/src/interfaces/records-delete.js +45 -55
- package/dist/esm/src/interfaces/records-delete.js.map +1 -1
- package/dist/esm/src/interfaces/records-query.js +60 -76
- package/dist/esm/src/interfaces/records-query.js.map +1 -1
- package/dist/esm/src/interfaces/records-read.js +51 -67
- package/dist/esm/src/interfaces/records-read.js.map +1 -1
- package/dist/esm/src/interfaces/records-subscribe.js +53 -68
- package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
- package/dist/esm/src/interfaces/records-write-query.js +102 -0
- package/dist/esm/src/interfaces/records-write-query.js.map +1 -0
- package/dist/esm/src/interfaces/records-write-signing.js +81 -0
- package/dist/esm/src/interfaces/records-write-signing.js.map +1 -0
- package/dist/esm/src/interfaces/records-write.js +396 -610
- package/dist/esm/src/interfaces/records-write.js.map +1 -1
- package/dist/esm/src/jose/algorithms/signing/ed25519.js +10 -19
- package/dist/esm/src/jose/algorithms/signing/ed25519.js.map +1 -1
- package/dist/esm/src/jose/jws/general/builder.js +23 -35
- package/dist/esm/src/jose/jws/general/builder.js.map +1 -1
- package/dist/esm/src/jose/jws/general/verifier.js +56 -69
- package/dist/esm/src/jose/jws/general/verifier.js.map +1 -1
- package/dist/esm/src/protocols/permission-grant.js +43 -14
- package/dist/esm/src/protocols/permission-grant.js.map +1 -1
- package/dist/esm/src/protocols/permission-request.js +28 -14
- package/dist/esm/src/protocols/permission-request.js.map +1 -1
- package/dist/esm/src/protocols/permissions.js +325 -227
- package/dist/esm/src/protocols/permissions.js.map +1 -1
- package/dist/esm/src/smt/smt-store-level.js +42 -64
- package/dist/esm/src/smt/smt-store-level.js.map +1 -1
- package/dist/esm/src/smt/smt-store-memory.js +19 -45
- package/dist/esm/src/smt/smt-store-memory.js.map +1 -1
- package/dist/esm/src/smt/smt-utils.js +28 -45
- package/dist/esm/src/smt/smt-utils.js.map +1 -1
- package/dist/esm/src/smt/sparse-merkle-tree.js +426 -471
- package/dist/esm/src/smt/sparse-merkle-tree.js.map +1 -1
- package/dist/esm/src/state-index/state-index-level.js +113 -150
- package/dist/esm/src/state-index/state-index-level.js.map +1 -1
- package/dist/esm/src/store/blockstore-level.js +54 -156
- package/dist/esm/src/store/blockstore-level.js.map +1 -1
- package/dist/esm/src/store/blockstore-mock.js +48 -153
- package/dist/esm/src/store/blockstore-mock.js.map +1 -1
- package/dist/esm/src/store/data-store-level.js +137 -100
- package/dist/esm/src/store/data-store-level.js.map +1 -1
- package/dist/esm/src/store/index-level-compound.js +246 -0
- package/dist/esm/src/store/index-level-compound.js.map +1 -0
- package/dist/esm/src/store/index-level.js +307 -715
- package/dist/esm/src/store/index-level.js.map +1 -1
- package/dist/esm/src/store/level-wrapper.js +143 -244
- package/dist/esm/src/store/level-wrapper.js.map +1 -1
- package/dist/esm/src/store/message-store-level.js +71 -94
- package/dist/esm/src/store/message-store-level.js.map +1 -1
- package/dist/esm/src/store/resumable-task-store-level.js +62 -101
- package/dist/esm/src/store/resumable-task-store-level.js.map +1 -1
- package/dist/esm/src/store/storage-controller.js +131 -146
- package/dist/esm/src/store/storage-controller.js.map +1 -1
- package/dist/esm/src/types/permission-types.js.map +1 -1
- package/dist/esm/src/types/protocols-types.js +10 -0
- package/dist/esm/src/types/protocols-types.js.map +1 -1
- package/dist/esm/src/types/records-types.js.map +1 -1
- package/dist/esm/src/utils/abort.js +8 -19
- package/dist/esm/src/utils/abort.js.map +1 -1
- package/dist/esm/src/utils/array.js +15 -49
- package/dist/esm/src/utils/array.js.map +1 -1
- package/dist/esm/src/utils/cid.js +29 -77
- package/dist/esm/src/utils/cid.js.map +1 -1
- package/dist/esm/src/utils/data-stream.js +37 -65
- package/dist/esm/src/utils/data-stream.js.map +1 -1
- package/dist/esm/src/utils/encryption.js +136 -162
- package/dist/esm/src/utils/encryption.js.map +1 -1
- package/dist/esm/src/utils/filter.js +1 -12
- package/dist/esm/src/utils/filter.js.map +1 -1
- package/dist/esm/src/utils/hd-key.js +45 -71
- package/dist/esm/src/utils/hd-key.js.map +1 -1
- package/dist/esm/src/utils/jws.js +9 -20
- package/dist/esm/src/utils/jws.js.map +1 -1
- package/dist/esm/src/utils/memory-cache.js +12 -23
- package/dist/esm/src/utils/memory-cache.js.map +1 -1
- package/dist/esm/src/utils/messages.js +21 -33
- package/dist/esm/src/utils/messages.js.map +1 -1
- package/dist/esm/src/utils/private-key-signer.js +9 -17
- package/dist/esm/src/utils/private-key-signer.js.map +1 -1
- package/dist/esm/src/utils/protocols.js +62 -70
- package/dist/esm/src/utils/protocols.js.map +1 -1
- package/dist/esm/src/utils/records.js +103 -166
- package/dist/esm/src/utils/records.js.map +1 -1
- package/dist/esm/src/utils/secp256k1.js +60 -96
- package/dist/esm/src/utils/secp256k1.js.map +1 -1
- package/dist/esm/src/utils/secp256r1.js +54 -71
- package/dist/esm/src/utils/secp256r1.js.map +1 -1
- package/dist/esm/src/utils/time.js +5 -18
- package/dist/esm/src/utils/time.js.map +1 -1
- package/dist/esm/src/utils/url.js +3 -3
- package/dist/esm/src/utils/url.js.map +1 -1
- package/dist/esm/tests/core/auth.spec.js +3 -12
- package/dist/esm/tests/core/auth.spec.js.map +1 -1
- package/dist/esm/tests/core/message.spec.js +50 -59
- package/dist/esm/tests/core/message.spec.js.map +1 -1
- package/dist/esm/tests/core/protocol-authorization.spec.js +10 -18
- package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
- package/dist/esm/tests/dwn.spec.js +65 -89
- package/dist/esm/tests/dwn.spec.js.map +1 -1
- package/dist/esm/tests/event-emitter-event-log.spec.js +305 -0
- package/dist/esm/tests/event-emitter-event-log.spec.js.map +1 -0
- package/dist/esm/tests/features/author-delegated-grant.spec.js +337 -347
- package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -1
- package/dist/esm/tests/features/owner-delegated-grant.spec.js +160 -172
- package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -1
- package/dist/esm/tests/features/owner-signature.spec.js +78 -82
- package/dist/esm/tests/features/owner-signature.spec.js.map +1 -1
- package/dist/esm/tests/features/permissions.spec.js +449 -184
- package/dist/esm/tests/features/permissions.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-composition.spec.js +981 -360
- package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-create-action.spec.js +45 -54
- package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-delete-action.spec.js +99 -108
- package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-update-action.spec.js +108 -117
- package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -1
- package/dist/esm/tests/features/records-immutable.spec.js +315 -0
- package/dist/esm/tests/features/records-immutable.spec.js.map +1 -0
- package/dist/esm/tests/features/records-prune.spec.js +178 -194
- package/dist/esm/tests/features/records-prune.spec.js.map +1 -1
- package/dist/esm/tests/features/records-record-limit.spec.js +542 -0
- package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -0
- package/dist/esm/tests/features/records-tags.spec.js +456 -463
- package/dist/esm/tests/features/records-tags.spec.js.map +1 -1
- package/dist/esm/tests/features/resumable-tasks.spec.js +88 -98
- package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-read.spec.js +215 -210
- package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-subscribe.spec.js +309 -171
- package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-sync.spec.js +272 -199
- package/dist/esm/tests/handlers/messages-sync.spec.js.map +1 -1
- package/dist/esm/tests/handlers/protocols-configure.spec.js +247 -241
- package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/handlers/protocols-query.spec.js +159 -172
- package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-count.spec.js +101 -105
- package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-delete.spec.js +266 -279
- package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-query.spec.js +984 -996
- package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-read.spec.js +542 -671
- package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-subscribe.spec.js +433 -302
- package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-write.spec.js +1216 -1140
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/messages-get.spec.js +39 -48
- package/dist/esm/tests/interfaces/messages-get.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/messages-subscribe.spec.js +4 -13
- package/dist/esm/tests/interfaces/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-configure.spec.js +212 -88
- package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-query.spec.js +8 -17
- package/dist/esm/tests/interfaces/protocols-query.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-delete.spec.js +8 -17
- package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-query.spec.js +20 -29
- package/dist/esm/tests/interfaces/records-query.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-read.spec.js +42 -51
- package/dist/esm/tests/interfaces/records-read.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-subscribe.spec.js +16 -25
- package/dist/esm/tests/interfaces/records-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-write.spec.js +190 -219
- package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
- package/dist/esm/tests/jose/jws/general.spec.js +36 -45
- package/dist/esm/tests/jose/jws/general.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permission-grant.spec.js +44 -50
- package/dist/esm/tests/protocols/permission-grant.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permission-request.spec.js +23 -32
- package/dist/esm/tests/protocols/permission-request.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permissions.spec.js +49 -55
- package/dist/esm/tests/protocols/permissions.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/aggregator.spec.js +127 -138
- package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/deleted-record.spec.js +372 -36
- package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +55 -64
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/nested-roles.spec.js +66 -76
- package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/subscriptions.spec.js +451 -354
- package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -1
- package/dist/esm/tests/smt/smt-store-level.spec.js +76 -87
- package/dist/esm/tests/smt/smt-store-level.spec.js.map +1 -1
- package/dist/esm/tests/smt/sparse-merkle-tree.spec.js +344 -353
- package/dist/esm/tests/smt/sparse-merkle-tree.spec.js.map +1 -1
- package/dist/esm/tests/state-index/state-index-level.spec.js +117 -126
- package/dist/esm/tests/state-index/state-index-level.spec.js.map +1 -1
- package/dist/esm/tests/store/blockstore-level.spec.js +44 -99
- package/dist/esm/tests/store/blockstore-level.spec.js.map +1 -1
- package/dist/esm/tests/store/blockstore-mock.spec.js +40 -120
- package/dist/esm/tests/store/blockstore-mock.spec.js.map +1 -1
- package/dist/esm/tests/store/data-store-level.spec.js +160 -108
- package/dist/esm/tests/store/data-store-level.spec.js.map +1 -1
- package/dist/esm/tests/store/index-level.spec.js +404 -414
- package/dist/esm/tests/store/index-level.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store-level.spec.js +13 -22
- package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store.spec.js +229 -238
- package/dist/esm/tests/store/message-store.spec.js.map +1 -1
- package/dist/esm/tests/test-event-stream.js +12 -13
- package/dist/esm/tests/test-event-stream.js.map +1 -1
- package/dist/esm/tests/test-stores.js +16 -13
- package/dist/esm/tests/test-stores.js.map +1 -1
- package/dist/esm/tests/test-suite.js +8 -15
- package/dist/esm/tests/test-suite.js.map +1 -1
- package/dist/esm/tests/utils/cid.spec.js +24 -33
- package/dist/esm/tests/utils/cid.spec.js.map +1 -1
- package/dist/esm/tests/utils/data-stream.spec.js +48 -57
- package/dist/esm/tests/utils/data-stream.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption-callbacks.spec.js +45 -54
- package/dist/esm/tests/utils/encryption-callbacks.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption.spec.js +229 -82
- package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
- package/dist/esm/tests/utils/filters.spec.js +46 -55
- package/dist/esm/tests/utils/filters.spec.js.map +1 -1
- package/dist/esm/tests/utils/hd-key.spec.js +10 -19
- package/dist/esm/tests/utils/hd-key.spec.js.map +1 -1
- package/dist/esm/tests/utils/jws.spec.js +3 -12
- package/dist/esm/tests/utils/jws.spec.js.map +1 -1
- package/dist/esm/tests/utils/memory-cache.spec.js +9 -18
- package/dist/esm/tests/utils/memory-cache.spec.js.map +1 -1
- package/dist/esm/tests/utils/messages.spec.js +18 -20
- package/dist/esm/tests/utils/messages.spec.js.map +1 -1
- package/dist/esm/tests/utils/poller.js +22 -33
- package/dist/esm/tests/utils/poller.js.map +1 -1
- package/dist/esm/tests/utils/private-key-signer.spec.js +15 -24
- package/dist/esm/tests/utils/private-key-signer.spec.js.map +1 -1
- package/dist/esm/tests/utils/records.spec.js +14 -27
- package/dist/esm/tests/utils/records.spec.js.map +1 -1
- package/dist/esm/tests/utils/secp256k1.spec.js +16 -25
- package/dist/esm/tests/utils/secp256k1.spec.js.map +1 -1
- package/dist/esm/tests/utils/secp256r1.spec.js +18 -27
- package/dist/esm/tests/utils/secp256r1.spec.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js +446 -467
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/definitions.spec.js +2 -11
- package/dist/esm/tests/validation/json-schemas/definitions.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js +4 -13
- package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js +8 -17
- package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js +3 -12
- package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js +4 -13
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js +2 -11
- package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-read.spec.js +2 -11
- package/dist/esm/tests/validation/json-schemas/records/records-read.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +44 -24
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -1
- package/dist/types/generated/precompiled-validators.d.ts +49 -40
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/constants.d.ts +11 -0
- package/dist/types/src/core/constants.d.ts.map +1 -0
- package/dist/types/src/core/core-protocol.d.ts +89 -0
- package/dist/types/src/core/core-protocol.d.ts.map +1 -0
- package/dist/types/src/core/dwn-error.d.ts +9 -12
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/grant-authorization.d.ts +6 -2
- package/dist/types/src/core/grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-action.d.ts +42 -0
- package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -0
- package/dist/types/src/core/protocol-authorization-validation.d.ts +81 -0
- package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -0
- package/dist/types/src/core/protocol-authorization.d.ts +24 -106
- package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
- package/dist/types/src/core/record-chain.d.ts +24 -0
- package/dist/types/src/core/record-chain.d.ts.map +1 -0
- package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/dwn.d.ts +19 -7
- package/dist/types/src/dwn.d.ts.map +1 -1
- package/dist/types/src/event-stream/event-emitter-event-log.d.ts +50 -0
- package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +1 -0
- package/dist/types/src/handlers/messages-read.d.ts +3 -8
- package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-subscribe.d.ts +6 -10
- package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-sync.d.ts +3 -8
- package/dist/types/src/handlers/messages-sync.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-configure.d.ts +3 -10
- package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-query.d.ts +3 -8
- package/dist/types/src/handlers/protocols-query.d.ts.map +1 -1
- package/dist/types/src/handlers/records-count.d.ts +3 -6
- package/dist/types/src/handlers/records-count.d.ts.map +1 -1
- package/dist/types/src/handlers/records-delete.d.ts +3 -8
- package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
- package/dist/types/src/handlers/records-query.d.ts +3 -8
- package/dist/types/src/handlers/records-query.d.ts.map +1 -1
- package/dist/types/src/handlers/records-read.d.ts +3 -8
- package/dist/types/src/handlers/records-read.d.ts.map +1 -1
- package/dist/types/src/handlers/records-subscribe.d.ts +8 -10
- package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/records-write.d.ts +4 -24
- package/dist/types/src/handlers/records-write.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +8 -4
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/messages-subscribe.d.ts +5 -0
- package/dist/types/src/interfaces/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-subscribe.d.ts +5 -0
- package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write-query.d.ts +33 -0
- package/dist/types/src/interfaces/records-write-query.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-write-signing.d.ts +34 -0
- package/dist/types/src/interfaces/records-write-signing.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-write.d.ts +13 -53
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
- package/dist/types/src/protocols/permission-grant.d.ts +1 -1
- package/dist/types/src/protocols/permission-grant.d.ts.map +1 -1
- package/dist/types/src/protocols/permission-request.d.ts +1 -1
- package/dist/types/src/protocols/permission-request.d.ts.map +1 -1
- package/dist/types/src/protocols/permissions.d.ts +40 -3
- package/dist/types/src/protocols/permissions.d.ts.map +1 -1
- package/dist/types/src/state-index/state-index-level.d.ts.map +1 -1
- package/dist/types/src/store/data-store-level.d.ts +20 -4
- package/dist/types/src/store/data-store-level.d.ts.map +1 -1
- package/dist/types/src/store/index-level-compound.d.ts +70 -0
- package/dist/types/src/store/index-level-compound.d.ts.map +1 -0
- package/dist/types/src/store/index-level.d.ts +4 -58
- package/dist/types/src/store/index-level.d.ts.map +1 -1
- package/dist/types/src/store/storage-controller.d.ts +4 -4
- package/dist/types/src/store/storage-controller.d.ts.map +1 -1
- package/dist/types/src/types/message-types.d.ts +3 -3
- package/dist/types/src/types/message-types.d.ts.map +1 -1
- package/dist/types/src/types/messages-types.d.ts +12 -3
- package/dist/types/src/types/messages-types.d.ts.map +1 -1
- package/dist/types/src/types/method-handler.d.ts +24 -3
- package/dist/types/src/types/method-handler.d.ts.map +1 -1
- package/dist/types/src/types/permission-types.d.ts +7 -0
- package/dist/types/src/types/permission-types.d.ts.map +1 -1
- package/dist/types/src/types/protocols-types.d.ts +41 -1
- package/dist/types/src/types/protocols-types.d.ts.map +1 -1
- package/dist/types/src/types/records-types.d.ts +16 -6
- package/dist/types/src/types/records-types.d.ts.map +1 -1
- package/dist/types/src/types/subscriptions.d.ts +151 -13
- package/dist/types/src/types/subscriptions.d.ts.map +1 -1
- package/dist/types/src/utils/hd-key.d.ts +1 -9
- package/dist/types/src/utils/hd-key.d.ts.map +1 -1
- package/dist/types/src/utils/messages.d.ts +7 -5
- package/dist/types/src/utils/messages.d.ts.map +1 -1
- package/dist/types/src/utils/protocols.d.ts +5 -0
- package/dist/types/src/utils/protocols.d.ts.map +1 -1
- package/dist/types/src/utils/records.d.ts +1 -11
- package/dist/types/src/utils/records.d.ts.map +1 -1
- package/dist/types/tests/dwn.spec.d.ts.map +1 -1
- package/dist/types/tests/event-emitter-event-log.spec.d.ts +2 -0
- package/dist/types/tests/event-emitter-event-log.spec.d.ts.map +1 -0
- package/dist/types/tests/features/author-delegated-grant.spec.d.ts.map +1 -1
- package/dist/types/tests/features/owner-delegated-grant.spec.d.ts.map +1 -1
- package/dist/types/tests/features/owner-signature.spec.d.ts.map +1 -1
- package/dist/types/tests/features/permissions.spec.d.ts.map +1 -1
- package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
- package/dist/types/tests/features/records-immutable.spec.d.ts +2 -0
- package/dist/types/tests/features/records-immutable.spec.d.ts.map +1 -0
- package/dist/types/tests/features/records-record-limit.spec.d.ts +2 -0
- package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -0
- package/dist/types/tests/features/records-tags.spec.d.ts.map +1 -1
- package/dist/types/tests/features/resumable-tasks.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
- package/dist/types/tests/scenarios/deleted-record.spec.d.ts.map +1 -1
- package/dist/types/tests/scenarios/subscriptions.spec.d.ts.map +1 -1
- package/dist/types/tests/test-event-stream.d.ts +11 -12
- package/dist/types/tests/test-event-stream.d.ts.map +1 -1
- package/dist/types/tests/test-suite.d.ts +2 -2
- package/dist/types/tests/test-suite.d.ts.map +1 -1
- package/dist/types/tests/utils/test-data-generator.d.ts +18 -0
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/core/constants.ts +11 -0
- package/src/core/core-protocol.ts +129 -0
- package/src/core/dwn-error.ts +15 -12
- package/src/core/grant-authorization.ts +20 -3
- package/src/core/protocol-authorization-action.ts +377 -0
- package/src/core/protocol-authorization-validation.ts +487 -0
- package/src/core/protocol-authorization.ts +111 -856
- package/src/core/record-chain.ts +99 -0
- package/src/core/records-grant-authorization.ts +6 -8
- package/src/dwn.ts +58 -73
- package/src/event-stream/event-emitter-event-log.ts +283 -0
- package/src/handlers/messages-read.ts +8 -9
- package/src/handlers/messages-subscribe.ts +24 -28
- package/src/handlers/messages-sync.ts +10 -16
- package/src/handlers/protocols-configure.ts +47 -32
- package/src/handlers/protocols-query.ts +6 -9
- package/src/handlers/records-count.ts +11 -10
- package/src/handlers/records-delete.ts +12 -21
- package/src/handlers/records-query.ts +12 -12
- package/src/handlers/records-read.ts +34 -22
- package/src/handlers/records-subscribe.ts +47 -26
- package/src/handlers/records-write.ts +47 -104
- package/src/index.ts +9 -5
- package/src/interfaces/messages-subscribe.ts +7 -1
- package/src/interfaces/protocols-configure.ts +73 -8
- package/src/interfaces/records-count.ts +1 -1
- package/src/interfaces/records-delete.ts +1 -1
- package/src/interfaces/records-query.ts +1 -1
- package/src/interfaces/records-read.ts +1 -1
- package/src/interfaces/records-subscribe.ts +8 -1
- package/src/interfaces/records-write-query.ts +139 -0
- package/src/interfaces/records-write-signing.ts +123 -0
- package/src/interfaces/records-write.ts +66 -261
- package/src/protocols/permission-grant.ts +1 -1
- package/src/protocols/permission-request.ts +1 -1
- package/src/protocols/permissions.ts +148 -6
- package/src/state-index/state-index-level.ts +5 -7
- package/src/store/data-store-level.ts +124 -34
- package/src/store/index-level-compound.ts +324 -0
- package/src/store/index-level.ts +68 -341
- package/src/store/storage-controller.ts +11 -11
- package/src/types/message-types.ts +3 -3
- package/src/types/messages-types.ts +12 -3
- package/src/types/method-handler.ts +26 -4
- package/src/types/mitt.d.ts +28 -0
- package/src/types/permission-types.ts +7 -0
- package/src/types/protocols-types.ts +46 -0
- package/src/types/records-types.ts +16 -6
- package/src/types/subscriptions.ts +178 -14
- package/src/utils/hd-key.ts +0 -9
- package/src/utils/messages.ts +17 -37
- package/src/utils/protocols.ts +8 -0
- package/src/utils/records.ts +8 -59
- package/dist/esm/src/event-stream/event-emitter-stream.js +0 -60
- package/dist/esm/src/event-stream/event-emitter-stream.js.map +0 -1
- package/dist/esm/tests/event-stream/event-emitter-stream.spec.js +0 -77
- package/dist/esm/tests/event-stream/event-emitter-stream.spec.js.map +0 -1
- package/dist/esm/tests/event-stream/event-stream.spec.js +0 -123
- package/dist/esm/tests/event-stream/event-stream.spec.js.map +0 -1
- package/dist/types/src/event-stream/event-emitter-stream.d.ts +0 -23
- package/dist/types/src/event-stream/event-emitter-stream.d.ts.map +0 -1
- package/dist/types/tests/event-stream/event-emitter-stream.spec.d.ts +0 -2
- package/dist/types/tests/event-stream/event-emitter-stream.spec.d.ts.map +0 -1
- package/dist/types/tests/event-stream/event-stream.spec.d.ts +0 -2
- package/dist/types/tests/event-stream/event-stream.spec.d.ts.map +0 -1
- package/src/event-stream/event-emitter-stream.ts +0 -69
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
|
|
11
2
|
import { SMTStoreMemory } from '../../src/smt/smt-store-memory.js';
|
|
12
3
|
import { SparseMerkleTree } from '../../src/smt/sparse-merkle-tree.js';
|
|
@@ -14,22 +5,22 @@ import { getBit, getDefaultHashes, hashEquals, hashKey, hashLeaf, initDefaultHas
|
|
|
14
5
|
describe('SparseMerkleTree', () => {
|
|
15
6
|
let store;
|
|
16
7
|
let smt;
|
|
17
|
-
beforeEach(() =>
|
|
8
|
+
beforeEach(async () => {
|
|
18
9
|
store = new SMTStoreMemory();
|
|
19
10
|
smt = new SparseMerkleTree(store);
|
|
20
|
-
|
|
21
|
-
})
|
|
22
|
-
afterEach(() =>
|
|
23
|
-
|
|
24
|
-
})
|
|
11
|
+
await smt.initialize();
|
|
12
|
+
});
|
|
13
|
+
afterEach(async () => {
|
|
14
|
+
await smt.close();
|
|
15
|
+
});
|
|
25
16
|
describe('initialization', () => {
|
|
26
|
-
it('should return the default empty root for a new tree', () =>
|
|
27
|
-
const root =
|
|
28
|
-
const defaultHashes =
|
|
17
|
+
it('should return the default empty root for a new tree', async () => {
|
|
18
|
+
const root = await smt.getRoot();
|
|
19
|
+
const defaultHashes = await initDefaultHashes();
|
|
29
20
|
expect(hashEquals(root, defaultHashes[0])).toBe(true);
|
|
30
|
-
})
|
|
31
|
-
it('should precompute default hashes for all 256 levels + leaf level', () =>
|
|
32
|
-
const defaultHashes =
|
|
21
|
+
});
|
|
22
|
+
it('should precompute default hashes for all 256 levels + leaf level', async () => {
|
|
23
|
+
const defaultHashes = await initDefaultHashes();
|
|
33
24
|
expect(defaultHashes.length).toBe(SMT_DEPTH + 1);
|
|
34
25
|
// Leaf level should be zero hash
|
|
35
26
|
expect(hashEquals(defaultHashes[SMT_DEPTH], ZERO_HASH)).toBe(true);
|
|
@@ -37,223 +28,223 @@ describe('SparseMerkleTree', () => {
|
|
|
37
28
|
for (let i = 0; i < SMT_DEPTH; i++) {
|
|
38
29
|
expect(hashEquals(defaultHashes[i], defaultHashes[i + 1])).toBe(false);
|
|
39
30
|
}
|
|
40
|
-
})
|
|
31
|
+
});
|
|
41
32
|
});
|
|
42
33
|
describe('insert', () => {
|
|
43
|
-
it('should change the root hash after inserting a single element', () =>
|
|
44
|
-
const emptyRoot =
|
|
45
|
-
|
|
46
|
-
const newRoot =
|
|
34
|
+
it('should change the root hash after inserting a single element', async () => {
|
|
35
|
+
const emptyRoot = await smt.getRoot();
|
|
36
|
+
await smt.insert('bafyreigtest1');
|
|
37
|
+
const newRoot = await smt.getRoot();
|
|
47
38
|
expect(hashEquals(emptyRoot, newRoot)).toBe(false);
|
|
48
|
-
})
|
|
49
|
-
it('should produce different roots for different values', () =>
|
|
39
|
+
});
|
|
40
|
+
it('should produce different roots for different values', async () => {
|
|
50
41
|
const storeA = new SMTStoreMemory();
|
|
51
42
|
const smtA = new SparseMerkleTree(storeA);
|
|
52
|
-
|
|
43
|
+
await smtA.initialize();
|
|
53
44
|
const storeB = new SMTStoreMemory();
|
|
54
45
|
const smtB = new SparseMerkleTree(storeB);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const rootA =
|
|
59
|
-
const rootB =
|
|
46
|
+
await smtB.initialize();
|
|
47
|
+
await smtA.insert('bafyreigaaa');
|
|
48
|
+
await smtB.insert('bafyreigbbb');
|
|
49
|
+
const rootA = await smtA.getRoot();
|
|
50
|
+
const rootB = await smtB.getRoot();
|
|
60
51
|
expect(hashEquals(rootA, rootB)).toBe(false);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
})
|
|
64
|
-
it('should produce the same root regardless of insertion order', () =>
|
|
52
|
+
await smtA.close();
|
|
53
|
+
await smtB.close();
|
|
54
|
+
});
|
|
55
|
+
it('should produce the same root regardless of insertion order', async () => {
|
|
65
56
|
const cids = ['bafyreiA', 'bafyreiB', 'bafyreiC', 'bafyreiD', 'bafyreiE'];
|
|
66
57
|
// Insert in forward order
|
|
67
58
|
const storeA = new SMTStoreMemory();
|
|
68
59
|
const smtA = new SparseMerkleTree(storeA);
|
|
69
|
-
|
|
60
|
+
await smtA.initialize();
|
|
70
61
|
for (const cid of cids) {
|
|
71
|
-
|
|
62
|
+
await smtA.insert(cid);
|
|
72
63
|
}
|
|
73
64
|
// Insert in reverse order
|
|
74
65
|
const storeB = new SMTStoreMemory();
|
|
75
66
|
const smtB = new SparseMerkleTree(storeB);
|
|
76
|
-
|
|
67
|
+
await smtB.initialize();
|
|
77
68
|
for (const cid of [...cids].reverse()) {
|
|
78
|
-
|
|
69
|
+
await smtB.insert(cid);
|
|
79
70
|
}
|
|
80
|
-
const rootA =
|
|
81
|
-
const rootB =
|
|
71
|
+
const rootA = await smtA.getRoot();
|
|
72
|
+
const rootB = await smtB.getRoot();
|
|
82
73
|
expect(hashEquals(rootA, rootB)).toBe(true);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
})
|
|
86
|
-
it('should handle inserting many elements', () =>
|
|
74
|
+
await smtA.close();
|
|
75
|
+
await smtB.close();
|
|
76
|
+
});
|
|
77
|
+
it('should handle inserting many elements', async () => {
|
|
87
78
|
const cids = [];
|
|
88
79
|
for (let i = 0; i < 100; i++) {
|
|
89
80
|
cids.push(`bafyreig-test-${i.toString().padStart(4, '0')}`);
|
|
90
81
|
}
|
|
91
82
|
for (const cid of cids) {
|
|
92
|
-
|
|
83
|
+
await smt.insert(cid);
|
|
93
84
|
}
|
|
94
85
|
// Verify all exist
|
|
95
86
|
for (const cid of cids) {
|
|
96
|
-
expect(
|
|
87
|
+
expect(await smt.has(cid)).toBe(true);
|
|
97
88
|
}
|
|
98
|
-
})
|
|
99
|
-
it('should handle re-inserting the same value (idempotent for same key)', () =>
|
|
100
|
-
|
|
101
|
-
const rootAfterFirst =
|
|
102
|
-
|
|
103
|
-
const rootAfterSecond =
|
|
89
|
+
});
|
|
90
|
+
it('should handle re-inserting the same value (idempotent for same key)', async () => {
|
|
91
|
+
await smt.insert('bafyreigtest1');
|
|
92
|
+
const rootAfterFirst = await smt.getRoot();
|
|
93
|
+
await smt.insert('bafyreigtest1');
|
|
94
|
+
const rootAfterSecond = await smt.getRoot();
|
|
104
95
|
expect(hashEquals(rootAfterFirst, rootAfterSecond)).toBe(true);
|
|
105
|
-
})
|
|
96
|
+
});
|
|
106
97
|
});
|
|
107
98
|
describe('has', () => {
|
|
108
|
-
it('should return false for an empty tree', () =>
|
|
109
|
-
expect(
|
|
110
|
-
})
|
|
111
|
-
it('should return true for an inserted element', () =>
|
|
112
|
-
|
|
113
|
-
expect(
|
|
114
|
-
})
|
|
115
|
-
it('should return false for an element not in the tree', () =>
|
|
116
|
-
|
|
117
|
-
expect(
|
|
118
|
-
})
|
|
119
|
-
it('should return false after deletion', () =>
|
|
120
|
-
|
|
121
|
-
expect(
|
|
122
|
-
|
|
123
|
-
expect(
|
|
124
|
-
})
|
|
99
|
+
it('should return false for an empty tree', async () => {
|
|
100
|
+
expect(await smt.has('bafyreigtest1')).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
it('should return true for an inserted element', async () => {
|
|
103
|
+
await smt.insert('bafyreigtest1');
|
|
104
|
+
expect(await smt.has('bafyreigtest1')).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
it('should return false for an element not in the tree', async () => {
|
|
107
|
+
await smt.insert('bafyreigtest1');
|
|
108
|
+
expect(await smt.has('bafyreigtest2')).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
it('should return false after deletion', async () => {
|
|
111
|
+
await smt.insert('bafyreigtest1');
|
|
112
|
+
expect(await smt.has('bafyreigtest1')).toBe(true);
|
|
113
|
+
await smt.delete('bafyreigtest1');
|
|
114
|
+
expect(await smt.has('bafyreigtest1')).toBe(false);
|
|
115
|
+
});
|
|
125
116
|
});
|
|
126
117
|
describe('delete', () => {
|
|
127
|
-
it('should return to empty root after inserting and deleting a single element', () =>
|
|
128
|
-
const emptyRoot =
|
|
129
|
-
|
|
130
|
-
const nonEmptyRoot =
|
|
118
|
+
it('should return to empty root after inserting and deleting a single element', async () => {
|
|
119
|
+
const emptyRoot = await smt.getRoot();
|
|
120
|
+
await smt.insert('bafyreigtest1');
|
|
121
|
+
const nonEmptyRoot = await smt.getRoot();
|
|
131
122
|
expect(hashEquals(emptyRoot, nonEmptyRoot)).toBe(false);
|
|
132
|
-
|
|
133
|
-
const rootAfterDelete =
|
|
123
|
+
await smt.delete('bafyreigtest1');
|
|
124
|
+
const rootAfterDelete = await smt.getRoot();
|
|
134
125
|
expect(hashEquals(emptyRoot, rootAfterDelete)).toBe(true);
|
|
135
|
-
})
|
|
136
|
-
it('should not change the root when deleting a non-existent element', () =>
|
|
137
|
-
|
|
138
|
-
const rootBefore =
|
|
139
|
-
|
|
140
|
-
const rootAfter =
|
|
126
|
+
});
|
|
127
|
+
it('should not change the root when deleting a non-existent element', async () => {
|
|
128
|
+
await smt.insert('bafyreigtest1');
|
|
129
|
+
const rootBefore = await smt.getRoot();
|
|
130
|
+
await smt.delete('bafyreigtest2');
|
|
131
|
+
const rootAfter = await smt.getRoot();
|
|
141
132
|
expect(hashEquals(rootBefore, rootAfter)).toBe(true);
|
|
142
|
-
})
|
|
143
|
-
it('should produce the same root regardless of insert-delete order', () =>
|
|
133
|
+
});
|
|
134
|
+
it('should produce the same root regardless of insert-delete order', async () => {
|
|
144
135
|
// Insert A, B, C then delete B
|
|
145
136
|
const storeA = new SMTStoreMemory();
|
|
146
137
|
const smtA = new SparseMerkleTree(storeA);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
138
|
+
await smtA.initialize();
|
|
139
|
+
await smtA.insert('bafyreiA');
|
|
140
|
+
await smtA.insert('bafyreiB');
|
|
141
|
+
await smtA.insert('bafyreiC');
|
|
142
|
+
await smtA.delete('bafyreiB');
|
|
152
143
|
// Insert A, C only (never insert B)
|
|
153
144
|
const storeB = new SMTStoreMemory();
|
|
154
145
|
const smtB = new SparseMerkleTree(storeB);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const rootA =
|
|
159
|
-
const rootB =
|
|
146
|
+
await smtB.initialize();
|
|
147
|
+
await smtB.insert('bafyreiA');
|
|
148
|
+
await smtB.insert('bafyreiC');
|
|
149
|
+
const rootA = await smtA.getRoot();
|
|
150
|
+
const rootB = await smtB.getRoot();
|
|
160
151
|
expect(hashEquals(rootA, rootB)).toBe(true);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
})
|
|
164
|
-
it('should handle deleting all elements to return to empty state', () =>
|
|
165
|
-
const emptyRoot =
|
|
152
|
+
await smtA.close();
|
|
153
|
+
await smtB.close();
|
|
154
|
+
});
|
|
155
|
+
it('should handle deleting all elements to return to empty state', async () => {
|
|
156
|
+
const emptyRoot = await smt.getRoot();
|
|
166
157
|
const cids = ['bafyreiA', 'bafyreiB', 'bafyreiC'];
|
|
167
158
|
for (const cid of cids) {
|
|
168
|
-
|
|
159
|
+
await smt.insert(cid);
|
|
169
160
|
}
|
|
170
161
|
for (const cid of cids) {
|
|
171
|
-
|
|
162
|
+
await smt.delete(cid);
|
|
172
163
|
}
|
|
173
|
-
const rootAfter =
|
|
164
|
+
const rootAfter = await smt.getRoot();
|
|
174
165
|
expect(hashEquals(emptyRoot, rootAfter)).toBe(true);
|
|
175
|
-
})
|
|
176
|
-
it('should handle interleaved inserts and deletes', () =>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
166
|
+
});
|
|
167
|
+
it('should handle interleaved inserts and deletes', async () => {
|
|
168
|
+
await smt.insert('bafyreiA');
|
|
169
|
+
await smt.insert('bafyreiB');
|
|
170
|
+
await smt.delete('bafyreiA');
|
|
171
|
+
await smt.insert('bafyreiC');
|
|
172
|
+
await smt.delete('bafyreiB');
|
|
173
|
+
await smt.insert('bafyreiD');
|
|
183
174
|
// Should have C and D
|
|
184
|
-
expect(
|
|
185
|
-
expect(
|
|
186
|
-
expect(
|
|
187
|
-
expect(
|
|
188
|
-
})
|
|
175
|
+
expect(await smt.has('bafyreiA')).toBe(false);
|
|
176
|
+
expect(await smt.has('bafyreiB')).toBe(false);
|
|
177
|
+
expect(await smt.has('bafyreiC')).toBe(true);
|
|
178
|
+
expect(await smt.has('bafyreiD')).toBe(true);
|
|
179
|
+
});
|
|
189
180
|
});
|
|
190
181
|
describe('proof', () => {
|
|
191
|
-
it('should generate a proof for an existing element (inclusion)', () =>
|
|
192
|
-
|
|
193
|
-
const proof =
|
|
182
|
+
it('should generate a proof for an existing element (inclusion)', async () => {
|
|
183
|
+
await smt.insert('bafyreigtest1');
|
|
184
|
+
const proof = await smt.getProof('bafyreigtest1');
|
|
194
185
|
expect(proof.leafNode).toBeDefined();
|
|
195
186
|
expect(proof.leafNode.valueCid).toBe('bafyreigtest1');
|
|
196
187
|
expect(proof.leafNode.type).toBe('leaf');
|
|
197
|
-
})
|
|
198
|
-
it('should generate a proof for a non-existent element (non-inclusion)', () =>
|
|
199
|
-
|
|
200
|
-
const proof =
|
|
188
|
+
});
|
|
189
|
+
it('should generate a proof for a non-existent element (non-inclusion)', async () => {
|
|
190
|
+
await smt.insert('bafyreigtest1');
|
|
191
|
+
const proof = await smt.getProof('bafyreigtest2');
|
|
201
192
|
// Either the leaf is undefined (empty slot) or it's a different key
|
|
202
193
|
if (proof.leafNode !== undefined) {
|
|
203
194
|
// The proof terminates at a leaf with a different key
|
|
204
|
-
const expectedKeyHash =
|
|
195
|
+
const expectedKeyHash = await hashKey('bafyreigtest2');
|
|
205
196
|
expect(hashEquals(proof.leafNode.keyHash, expectedKeyHash)).toBe(false);
|
|
206
197
|
}
|
|
207
|
-
})
|
|
208
|
-
it('should generate an empty proof for an empty tree', () =>
|
|
209
|
-
const proof =
|
|
198
|
+
});
|
|
199
|
+
it('should generate an empty proof for an empty tree', async () => {
|
|
200
|
+
const proof = await smt.getProof('bafyreigtest1');
|
|
210
201
|
expect(proof.leafNode).toBeUndefined();
|
|
211
202
|
expect(proof.siblings.length).toBe(0);
|
|
212
|
-
})
|
|
203
|
+
});
|
|
213
204
|
});
|
|
214
205
|
describe('getSubtreeHash', () => {
|
|
215
|
-
it('should return default hash for empty subtree', () =>
|
|
216
|
-
const defaultHashes =
|
|
217
|
-
const subtreeHash =
|
|
206
|
+
it('should return default hash for empty subtree', async () => {
|
|
207
|
+
const defaultHashes = await initDefaultHashes();
|
|
208
|
+
const subtreeHash = await smt.getSubtreeHash([false]); // left child of root
|
|
218
209
|
expect(hashEquals(subtreeHash, defaultHashes[1])).toBe(true);
|
|
219
|
-
})
|
|
220
|
-
it('should return different hashes for subtrees with different contents', () =>
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const leftHash =
|
|
224
|
-
const rightHash =
|
|
210
|
+
});
|
|
211
|
+
it('should return different hashes for subtrees with different contents', async () => {
|
|
212
|
+
await smt.insert('bafyreigtest1');
|
|
213
|
+
await smt.insert('bafyreigtest2');
|
|
214
|
+
const leftHash = await smt.getSubtreeHash([false]);
|
|
215
|
+
const rightHash = await smt.getSubtreeHash([true]);
|
|
225
216
|
// At least one should be non-default (elements distributed by hash)
|
|
226
|
-
const defaultHashes =
|
|
217
|
+
const defaultHashes = await initDefaultHashes();
|
|
227
218
|
const leftIsDefault = hashEquals(leftHash, defaultHashes[1]);
|
|
228
219
|
const rightIsDefault = hashEquals(rightHash, defaultHashes[1]);
|
|
229
220
|
expect(leftIsDefault && rightIsDefault).toBe(false);
|
|
230
|
-
})
|
|
221
|
+
});
|
|
231
222
|
});
|
|
232
223
|
describe('getLeaves', () => {
|
|
233
|
-
it('should return empty array for empty tree', () =>
|
|
234
|
-
const leaves =
|
|
224
|
+
it('should return empty array for empty tree', async () => {
|
|
225
|
+
const leaves = await smt.getLeaves([]);
|
|
235
226
|
expect(leaves).toEqual([]);
|
|
236
|
-
})
|
|
237
|
-
it('should return all leaves for empty prefix', () =>
|
|
227
|
+
});
|
|
228
|
+
it('should return all leaves for empty prefix', async () => {
|
|
238
229
|
const cids = ['bafyreiA', 'bafyreiB', 'bafyreiC'];
|
|
239
230
|
for (const cid of cids) {
|
|
240
|
-
|
|
231
|
+
await smt.insert(cid);
|
|
241
232
|
}
|
|
242
|
-
const leaves =
|
|
233
|
+
const leaves = await smt.getLeaves([]);
|
|
243
234
|
expect(leaves.sort()).toEqual([...cids].sort());
|
|
244
|
-
})
|
|
245
|
-
it('should return only leaves under the specified prefix', () =>
|
|
235
|
+
});
|
|
236
|
+
it('should return only leaves under the specified prefix', async () => {
|
|
246
237
|
// Insert multiple elements and verify prefix filtering works
|
|
247
238
|
const cids = [];
|
|
248
239
|
for (let i = 0; i < 20; i++) {
|
|
249
240
|
cids.push(`bafyreig-prefix-test-${i}`);
|
|
250
241
|
}
|
|
251
242
|
for (const cid of cids) {
|
|
252
|
-
|
|
243
|
+
await smt.insert(cid);
|
|
253
244
|
}
|
|
254
245
|
// Get leaves under left and right subtrees
|
|
255
|
-
const leftLeaves =
|
|
256
|
-
const rightLeaves =
|
|
246
|
+
const leftLeaves = await smt.getLeaves([false]);
|
|
247
|
+
const rightLeaves = await smt.getLeaves([true]);
|
|
257
248
|
// Together they should contain all CIDs
|
|
258
249
|
const allLeaves = [...leftLeaves, ...rightLeaves].sort();
|
|
259
250
|
expect(allLeaves).toEqual([...cids].sort());
|
|
@@ -261,214 +252,214 @@ describe('SparseMerkleTree', () => {
|
|
|
261
252
|
// (This is probabilistic but 20 elements should reliably split)
|
|
262
253
|
expect(leftLeaves.length).toBeGreaterThan(0);
|
|
263
254
|
expect(rightLeaves.length).toBeGreaterThan(0);
|
|
264
|
-
})
|
|
255
|
+
});
|
|
265
256
|
});
|
|
266
257
|
describe('diff', () => {
|
|
267
|
-
it('should return empty diff for identical trees', () =>
|
|
258
|
+
it('should return empty diff for identical trees', async () => {
|
|
268
259
|
const storeB = new SMTStoreMemory();
|
|
269
260
|
const smtB = new SparseMerkleTree(storeB);
|
|
270
|
-
|
|
261
|
+
await smtB.initialize();
|
|
271
262
|
const cids = ['bafyreiA', 'bafyreiB', 'bafyreiC'];
|
|
272
263
|
for (const cid of cids) {
|
|
273
|
-
|
|
274
|
-
|
|
264
|
+
await smt.insert(cid);
|
|
265
|
+
await smtB.insert(cid);
|
|
275
266
|
}
|
|
276
|
-
const diff =
|
|
267
|
+
const diff = await smt.diff(smtB);
|
|
277
268
|
expect(diff.onlyLocal).toEqual([]);
|
|
278
269
|
expect(diff.onlyRemote).toEqual([]);
|
|
279
|
-
|
|
280
|
-
})
|
|
281
|
-
it('should return empty diff for two empty trees', () =>
|
|
270
|
+
await smtB.close();
|
|
271
|
+
});
|
|
272
|
+
it('should return empty diff for two empty trees', async () => {
|
|
282
273
|
const storeB = new SMTStoreMemory();
|
|
283
274
|
const smtB = new SparseMerkleTree(storeB);
|
|
284
|
-
|
|
285
|
-
const diff =
|
|
275
|
+
await smtB.initialize();
|
|
276
|
+
const diff = await smt.diff(smtB);
|
|
286
277
|
expect(diff.onlyLocal).toEqual([]);
|
|
287
278
|
expect(diff.onlyRemote).toEqual([]);
|
|
288
|
-
|
|
289
|
-
})
|
|
290
|
-
it('should detect elements only in the local tree', () =>
|
|
279
|
+
await smtB.close();
|
|
280
|
+
});
|
|
281
|
+
it('should detect elements only in the local tree', async () => {
|
|
291
282
|
const storeB = new SMTStoreMemory();
|
|
292
283
|
const smtB = new SparseMerkleTree(storeB);
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const diff =
|
|
284
|
+
await smtB.initialize();
|
|
285
|
+
await smt.insert('bafyreiA');
|
|
286
|
+
await smt.insert('bafyreiB');
|
|
287
|
+
await smtB.insert('bafyreiA');
|
|
288
|
+
const diff = await smt.diff(smtB);
|
|
298
289
|
expect(diff.onlyLocal.sort()).toEqual(['bafyreiB']);
|
|
299
290
|
expect(diff.onlyRemote).toEqual([]);
|
|
300
|
-
|
|
301
|
-
})
|
|
302
|
-
it('should detect elements only in the remote tree', () =>
|
|
291
|
+
await smtB.close();
|
|
292
|
+
});
|
|
293
|
+
it('should detect elements only in the remote tree', async () => {
|
|
303
294
|
const storeB = new SMTStoreMemory();
|
|
304
295
|
const smtB = new SparseMerkleTree(storeB);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const diff =
|
|
296
|
+
await smtB.initialize();
|
|
297
|
+
await smt.insert('bafyreiA');
|
|
298
|
+
await smtB.insert('bafyreiA');
|
|
299
|
+
await smtB.insert('bafyreiB');
|
|
300
|
+
const diff = await smt.diff(smtB);
|
|
310
301
|
expect(diff.onlyLocal).toEqual([]);
|
|
311
302
|
expect(diff.onlyRemote.sort()).toEqual(['bafyreiB']);
|
|
312
|
-
|
|
313
|
-
})
|
|
314
|
-
it('should detect elements unique to each tree', () =>
|
|
303
|
+
await smtB.close();
|
|
304
|
+
});
|
|
305
|
+
it('should detect elements unique to each tree', async () => {
|
|
315
306
|
const storeB = new SMTStoreMemory();
|
|
316
307
|
const smtB = new SparseMerkleTree(storeB);
|
|
317
|
-
|
|
308
|
+
await smtB.initialize();
|
|
318
309
|
// Shared
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
310
|
+
await smt.insert('bafyreiShared1');
|
|
311
|
+
await smtB.insert('bafyreiShared1');
|
|
312
|
+
await smt.insert('bafyreiShared2');
|
|
313
|
+
await smtB.insert('bafyreiShared2');
|
|
323
314
|
// Only local
|
|
324
|
-
|
|
325
|
-
|
|
315
|
+
await smt.insert('bafyreiLocalOnly1');
|
|
316
|
+
await smt.insert('bafyreiLocalOnly2');
|
|
326
317
|
// Only remote
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const diff =
|
|
318
|
+
await smtB.insert('bafyreiRemoteOnly1');
|
|
319
|
+
await smtB.insert('bafyreiRemoteOnly2');
|
|
320
|
+
await smtB.insert('bafyreiRemoteOnly3');
|
|
321
|
+
const diff = await smt.diff(smtB);
|
|
331
322
|
expect(diff.onlyLocal.sort()).toEqual(['bafyreiLocalOnly1', 'bafyreiLocalOnly2'].sort());
|
|
332
323
|
expect(diff.onlyRemote.sort()).toEqual(['bafyreiRemoteOnly1', 'bafyreiRemoteOnly2', 'bafyreiRemoteOnly3'].sort());
|
|
333
|
-
|
|
334
|
-
})
|
|
335
|
-
it('should detect all differences when trees are completely disjoint', () =>
|
|
324
|
+
await smtB.close();
|
|
325
|
+
});
|
|
326
|
+
it('should detect all differences when trees are completely disjoint', async () => {
|
|
336
327
|
const storeB = new SMTStoreMemory();
|
|
337
328
|
const smtB = new SparseMerkleTree(storeB);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const diff =
|
|
329
|
+
await smtB.initialize();
|
|
330
|
+
await smt.insert('bafyreiA');
|
|
331
|
+
await smt.insert('bafyreiB');
|
|
332
|
+
await smtB.insert('bafyreiC');
|
|
333
|
+
await smtB.insert('bafyreiD');
|
|
334
|
+
const diff = await smt.diff(smtB);
|
|
344
335
|
expect(diff.onlyLocal.sort()).toEqual(['bafyreiA', 'bafyreiB'].sort());
|
|
345
336
|
expect(diff.onlyRemote.sort()).toEqual(['bafyreiC', 'bafyreiD'].sort());
|
|
346
|
-
|
|
347
|
-
})
|
|
348
|
-
it('should detect differences in larger trees efficiently', () =>
|
|
337
|
+
await smtB.close();
|
|
338
|
+
});
|
|
339
|
+
it('should detect differences in larger trees efficiently', async () => {
|
|
349
340
|
const storeB = new SMTStoreMemory();
|
|
350
341
|
const smtB = new SparseMerkleTree(storeB);
|
|
351
|
-
|
|
342
|
+
await smtB.initialize();
|
|
352
343
|
// Both trees share 50 elements
|
|
353
344
|
for (let i = 0; i < 50; i++) {
|
|
354
345
|
const cid = `bafyreig-shared-${i.toString().padStart(3, '0')}`;
|
|
355
|
-
|
|
356
|
-
|
|
346
|
+
await smt.insert(cid);
|
|
347
|
+
await smtB.insert(cid);
|
|
357
348
|
}
|
|
358
349
|
// Local has 5 unique elements
|
|
359
350
|
const localOnly = [];
|
|
360
351
|
for (let i = 0; i < 5; i++) {
|
|
361
352
|
const cid = `bafyreig-local-${i}`;
|
|
362
|
-
|
|
353
|
+
await smt.insert(cid);
|
|
363
354
|
localOnly.push(cid);
|
|
364
355
|
}
|
|
365
356
|
// Remote has 3 unique elements
|
|
366
357
|
const remoteOnly = [];
|
|
367
358
|
for (let i = 0; i < 3; i++) {
|
|
368
359
|
const cid = `bafyreig-remote-${i}`;
|
|
369
|
-
|
|
360
|
+
await smtB.insert(cid);
|
|
370
361
|
remoteOnly.push(cid);
|
|
371
362
|
}
|
|
372
|
-
const diff =
|
|
363
|
+
const diff = await smt.diff(smtB);
|
|
373
364
|
expect(diff.onlyLocal.sort()).toEqual(localOnly.sort());
|
|
374
365
|
expect(diff.onlyRemote.sort()).toEqual(remoteOnly.sort());
|
|
375
|
-
|
|
376
|
-
})
|
|
377
|
-
it('should handle diff where local tree is empty', () =>
|
|
366
|
+
await smtB.close();
|
|
367
|
+
});
|
|
368
|
+
it('should handle diff where local tree is empty', async () => {
|
|
378
369
|
const storeB = new SMTStoreMemory();
|
|
379
370
|
const smtB = new SparseMerkleTree(storeB);
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
const diff =
|
|
371
|
+
await smtB.initialize();
|
|
372
|
+
await smtB.insert('bafyreiA');
|
|
373
|
+
await smtB.insert('bafyreiB');
|
|
374
|
+
const diff = await smt.diff(smtB);
|
|
384
375
|
expect(diff.onlyLocal).toEqual([]);
|
|
385
376
|
expect(diff.onlyRemote.sort()).toEqual(['bafyreiA', 'bafyreiB'].sort());
|
|
386
|
-
|
|
387
|
-
})
|
|
388
|
-
it('should handle diff where remote tree is empty', () =>
|
|
377
|
+
await smtB.close();
|
|
378
|
+
});
|
|
379
|
+
it('should handle diff where remote tree is empty', async () => {
|
|
389
380
|
const storeB = new SMTStoreMemory();
|
|
390
381
|
const smtB = new SparseMerkleTree(storeB);
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const diff =
|
|
382
|
+
await smtB.initialize();
|
|
383
|
+
await smt.insert('bafyreiA');
|
|
384
|
+
await smt.insert('bafyreiB');
|
|
385
|
+
const diff = await smt.diff(smtB);
|
|
395
386
|
expect(diff.onlyLocal.sort()).toEqual(['bafyreiA', 'bafyreiB'].sort());
|
|
396
387
|
expect(diff.onlyRemote).toEqual([]);
|
|
397
|
-
|
|
398
|
-
})
|
|
388
|
+
await smtB.close();
|
|
389
|
+
});
|
|
399
390
|
});
|
|
400
391
|
describe('clear', () => {
|
|
401
|
-
it('should reset the tree to empty state', () =>
|
|
402
|
-
const emptyRoot =
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
const rootAfterClear =
|
|
392
|
+
it('should reset the tree to empty state', async () => {
|
|
393
|
+
const emptyRoot = await smt.getRoot();
|
|
394
|
+
await smt.insert('bafyreiA');
|
|
395
|
+
await smt.insert('bafyreiB');
|
|
396
|
+
await smt.clear();
|
|
397
|
+
const rootAfterClear = await smt.getRoot();
|
|
407
398
|
expect(hashEquals(emptyRoot, rootAfterClear)).toBe(true);
|
|
408
|
-
expect(
|
|
409
|
-
expect(
|
|
410
|
-
})
|
|
399
|
+
expect(await smt.has('bafyreiA')).toBe(false);
|
|
400
|
+
expect(await smt.has('bafyreiB')).toBe(false);
|
|
401
|
+
});
|
|
411
402
|
});
|
|
412
403
|
describe('getSubtreeHash with leaf at shallow depth', () => {
|
|
413
|
-
it('should return leaf hash when leaf matches the prefix', () =>
|
|
404
|
+
it('should return leaf hash when leaf matches the prefix', async () => {
|
|
414
405
|
// Insert a single element — the tree stores it as a leaf near the root
|
|
415
|
-
|
|
416
|
-
const keyHash =
|
|
406
|
+
await smt.insert('bafyreiA');
|
|
407
|
+
const keyHash = await hashKey('bafyreiA');
|
|
417
408
|
// Build a deep prefix that follows the leaf's keyHash bits
|
|
418
409
|
const matchingPrefix = [];
|
|
419
410
|
for (let i = 0; i < 8; i++) {
|
|
420
411
|
matchingPrefix.push(getBit(keyHash, i));
|
|
421
412
|
}
|
|
422
|
-
const subtreeHash =
|
|
413
|
+
const subtreeHash = await smt.getSubtreeHash(matchingPrefix);
|
|
423
414
|
// Should be the leaf hash (non-default) since the leaf is under this prefix
|
|
424
|
-
const expectedLeafHash =
|
|
415
|
+
const expectedLeafHash = await hashLeaf(keyHash, 'bafyreiA');
|
|
425
416
|
expect(hashEquals(subtreeHash, expectedLeafHash)).toBe(true);
|
|
426
|
-
})
|
|
427
|
-
it('should return default hash when leaf does not match the prefix', () =>
|
|
428
|
-
|
|
429
|
-
const keyHash =
|
|
430
|
-
const defaultHashes =
|
|
417
|
+
});
|
|
418
|
+
it('should return default hash when leaf does not match the prefix', async () => {
|
|
419
|
+
await smt.insert('bafyreiA');
|
|
420
|
+
const keyHash = await hashKey('bafyreiA');
|
|
421
|
+
const defaultHashes = await initDefaultHashes();
|
|
431
422
|
// Build a prefix that diverges from the leaf's keyHash at bit 0
|
|
432
423
|
const firstBit = getBit(keyHash, 0);
|
|
433
424
|
const nonMatchingPrefix = [!firstBit]; // opposite of the first bit
|
|
434
|
-
const subtreeHash =
|
|
425
|
+
const subtreeHash = await smt.getSubtreeHash(nonMatchingPrefix);
|
|
435
426
|
expect(hashEquals(subtreeHash, defaultHashes[1])).toBe(true);
|
|
436
|
-
})
|
|
427
|
+
});
|
|
437
428
|
});
|
|
438
429
|
describe('getLeaves with leaf at shallow depth', () => {
|
|
439
|
-
it('should return the leaf CID when leaf matches the prefix', () =>
|
|
440
|
-
|
|
441
|
-
const keyHash =
|
|
430
|
+
it('should return the leaf CID when leaf matches the prefix', async () => {
|
|
431
|
+
await smt.insert('bafyreiA');
|
|
432
|
+
const keyHash = await hashKey('bafyreiA');
|
|
442
433
|
// Build a prefix that matches the leaf's keyHash bits
|
|
443
434
|
const matchingPrefix = [];
|
|
444
435
|
for (let i = 0; i < 4; i++) {
|
|
445
436
|
matchingPrefix.push(getBit(keyHash, i));
|
|
446
437
|
}
|
|
447
|
-
const leaves =
|
|
438
|
+
const leaves = await smt.getLeaves(matchingPrefix);
|
|
448
439
|
expect(leaves).toEqual(['bafyreiA']);
|
|
449
|
-
})
|
|
450
|
-
it('should return empty when leaf does not match the prefix', () =>
|
|
451
|
-
|
|
452
|
-
const keyHash =
|
|
440
|
+
});
|
|
441
|
+
it('should return empty when leaf does not match the prefix', async () => {
|
|
442
|
+
await smt.insert('bafyreiA');
|
|
443
|
+
const keyHash = await hashKey('bafyreiA');
|
|
453
444
|
// Build a prefix that diverges from the leaf's keyHash
|
|
454
445
|
const firstBit = getBit(keyHash, 0);
|
|
455
446
|
const nonMatchingPrefix = [!firstBit];
|
|
456
|
-
const leaves =
|
|
447
|
+
const leaves = await smt.getLeaves(nonMatchingPrefix);
|
|
457
448
|
expect(leaves).toEqual([]);
|
|
458
|
-
})
|
|
449
|
+
});
|
|
459
450
|
});
|
|
460
451
|
describe('proof', () => {
|
|
461
|
-
it('should generate a multi-level proof with sibling hashes', () =>
|
|
452
|
+
it('should generate a multi-level proof with sibling hashes', async () => {
|
|
462
453
|
// Insert two elements so the tree has internal nodes
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const proof =
|
|
454
|
+
await smt.insert('bafyreiA');
|
|
455
|
+
await smt.insert('bafyreiB');
|
|
456
|
+
const proof = await smt.getProof('bafyreiA');
|
|
466
457
|
expect(proof.leafNode).toBeDefined();
|
|
467
458
|
expect(proof.leafNode.valueCid).toBe('bafyreiA');
|
|
468
459
|
// With two elements, there should be at least one sibling hash
|
|
469
460
|
expect(proof.siblings.length).toBeGreaterThan(0);
|
|
470
|
-
})
|
|
471
|
-
it('should return empty proof when store node is missing (corrupted store)', () =>
|
|
461
|
+
});
|
|
462
|
+
it('should return empty proof when store node is missing (corrupted store)', async () => {
|
|
472
463
|
// Test lines 503-505 of sparse-merkle-tree.ts: getNode returns undefined
|
|
473
464
|
const realStore = new SMTStoreMemory();
|
|
474
465
|
let corruptDuringProof = false;
|
|
@@ -480,28 +471,28 @@ describe('SparseMerkleTree', () => {
|
|
|
480
471
|
setRoot: (hash) => realStore.setRoot(hash),
|
|
481
472
|
putNode: (hash, node) => realStore.putNode(hash, node),
|
|
482
473
|
deleteNode: (hash) => realStore.deleteNode(hash),
|
|
483
|
-
getNode: (hash) =>
|
|
474
|
+
getNode: async (hash) => {
|
|
484
475
|
if (corruptDuringProof) {
|
|
485
476
|
return undefined;
|
|
486
477
|
}
|
|
487
478
|
return realStore.getNode(hash);
|
|
488
|
-
}
|
|
479
|
+
},
|
|
489
480
|
};
|
|
490
481
|
const corruptSmt = new SparseMerkleTree(corruptStore);
|
|
491
|
-
|
|
492
|
-
|
|
482
|
+
await corruptSmt.initialize();
|
|
483
|
+
await corruptSmt.insert('bafyreiProofCorrupt');
|
|
493
484
|
// Now corrupt the store so getNode returns undefined during proof generation
|
|
494
485
|
corruptDuringProof = true;
|
|
495
|
-
const proof =
|
|
486
|
+
const proof = await corruptSmt.getProof('bafyreiProofCorrupt');
|
|
496
487
|
// Should return a proof without a leaf node since the node is missing
|
|
497
488
|
expect(proof.leafNode).toBeUndefined();
|
|
498
489
|
expect(proof.siblings).toHaveLength(0);
|
|
499
490
|
corruptDuringProof = false;
|
|
500
|
-
|
|
501
|
-
})
|
|
491
|
+
await corruptSmt.close();
|
|
492
|
+
});
|
|
502
493
|
});
|
|
503
494
|
describe('diff edge cases', () => {
|
|
504
|
-
it('should detect local leaf not present in remote subtree', () =>
|
|
495
|
+
it('should detect local leaf not present in remote subtree', async () => {
|
|
505
496
|
// We need a scenario where local has a single leaf at a node while remote
|
|
506
497
|
// has an internal subtree at the same position, and the local leaf is NOT
|
|
507
498
|
// in the remote set. This happens when:
|
|
@@ -509,68 +500,68 @@ describe('SparseMerkleTree', () => {
|
|
|
509
500
|
// - Local has 1 element with the same prefix but a different CID
|
|
510
501
|
const storeB = new SMTStoreMemory();
|
|
511
502
|
const smtB = new SparseMerkleTree(storeB);
|
|
512
|
-
|
|
503
|
+
await smtB.initialize();
|
|
513
504
|
// Insert many elements into both trees so they develop deep structure
|
|
514
505
|
const sharedCids = [];
|
|
515
506
|
for (let i = 0; i < 30; i++) {
|
|
516
507
|
const cid = `bafyreig-shared-${i}`;
|
|
517
508
|
sharedCids.push(cid);
|
|
518
|
-
|
|
519
|
-
|
|
509
|
+
await smt.insert(cid);
|
|
510
|
+
await smtB.insert(cid);
|
|
520
511
|
}
|
|
521
512
|
// Add unique elements to each side
|
|
522
513
|
const localOnly = 'bafyreig-local-unique-42';
|
|
523
|
-
|
|
514
|
+
await smt.insert(localOnly);
|
|
524
515
|
const remoteOnly = 'bafyreig-remote-unique-99';
|
|
525
|
-
|
|
526
|
-
const diff =
|
|
516
|
+
await smtB.insert(remoteOnly);
|
|
517
|
+
const diff = await smt.diff(smtB);
|
|
527
518
|
expect(diff.onlyLocal).toContain(localOnly);
|
|
528
519
|
expect(diff.onlyRemote).toContain(remoteOnly);
|
|
529
|
-
|
|
530
|
-
})
|
|
531
|
-
it('should detect both-are-leaves diff when each tree has one unique element', () =>
|
|
520
|
+
await smtB.close();
|
|
521
|
+
});
|
|
522
|
+
it('should detect both-are-leaves diff when each tree has one unique element', async () => {
|
|
532
523
|
// When each tree has exactly one element, the root IS a leaf hash.
|
|
533
524
|
// diffAtNode at depth 0 encounters two leaf nodes → hits lines 632-643.
|
|
534
525
|
const storeB = new SMTStoreMemory();
|
|
535
526
|
const smtB = new SparseMerkleTree(storeB);
|
|
536
|
-
|
|
527
|
+
await smtB.initialize();
|
|
537
528
|
// Each tree has exactly one unique element (different keys → line 633-636)
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
const diff =
|
|
529
|
+
await smt.insert('bafyreiOnlyInLocal');
|
|
530
|
+
await smtB.insert('bafyreiOnlyInRemote');
|
|
531
|
+
const diff = await smt.diff(smtB);
|
|
541
532
|
expect(diff.onlyLocal).toEqual(['bafyreiOnlyInLocal']);
|
|
542
533
|
expect(diff.onlyRemote).toEqual(['bafyreiOnlyInRemote']);
|
|
543
|
-
|
|
544
|
-
})
|
|
545
|
-
it('should detect both-are-leaves diff with same key but different value', () =>
|
|
534
|
+
await smtB.close();
|
|
535
|
+
});
|
|
536
|
+
it('should detect both-are-leaves diff with same key but different value', async () => {
|
|
546
537
|
// Test lines 637-640: same keyHash, different valueCid.
|
|
547
538
|
// Since keyHash = hash(valueCid), this can't happen organically.
|
|
548
539
|
// We simulate it by directly placing leaf nodes in the store.
|
|
549
540
|
const storeA = new SMTStoreMemory();
|
|
550
541
|
const smtA = new SparseMerkleTree(storeA);
|
|
551
|
-
|
|
542
|
+
await smtA.initialize();
|
|
552
543
|
const storeB = new SMTStoreMemory();
|
|
553
544
|
const smtB = new SparseMerkleTree(storeB);
|
|
554
|
-
|
|
545
|
+
await smtB.initialize();
|
|
555
546
|
// Insert the same CID into both, then manually alter one tree's leaf to have a different valueCid
|
|
556
547
|
// but the same keyHash, by manipulating the store directly.
|
|
557
|
-
const sharedKeyHash =
|
|
558
|
-
const leafHashA =
|
|
548
|
+
const sharedKeyHash = await hashKey('bafyreiSharedKey');
|
|
549
|
+
const leafHashA = await hashLeaf(sharedKeyHash, 'valueCidA');
|
|
559
550
|
const leafNodeA = { type: 'leaf', keyHash: sharedKeyHash, valueCid: 'valueCidA' };
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const leafHashB =
|
|
551
|
+
await storeA.putNode(leafHashA, leafNodeA);
|
|
552
|
+
await storeA.setRoot(leafHashA);
|
|
553
|
+
const leafHashB = await hashLeaf(sharedKeyHash, 'valueCidB');
|
|
563
554
|
const leafNodeB = { type: 'leaf', keyHash: sharedKeyHash, valueCid: 'valueCidB' };
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const diff =
|
|
555
|
+
await storeB.putNode(leafHashB, leafNodeB);
|
|
556
|
+
await storeB.setRoot(leafHashB);
|
|
557
|
+
const diff = await smtA.diff(smtB);
|
|
567
558
|
// Same key, different value → both appear as unique
|
|
568
559
|
expect(diff.onlyLocal).toEqual(['valueCidA']);
|
|
569
560
|
expect(diff.onlyRemote).toEqual(['valueCidB']);
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
})
|
|
573
|
-
it('should handle diff with selectively corrupted nodes via fallback', () =>
|
|
561
|
+
await smtA.close();
|
|
562
|
+
await smtB.close();
|
|
563
|
+
});
|
|
564
|
+
it('should handle diff with selectively corrupted nodes via fallback', async () => {
|
|
574
565
|
// To hit lines 687-696, we need both trees to have internal root nodes
|
|
575
566
|
// (so the recursion goes through line 682-684 into children), and then
|
|
576
567
|
// at the child level, one node is missing (getNode returns undefined).
|
|
@@ -585,7 +576,7 @@ describe('SparseMerkleTree', () => {
|
|
|
585
576
|
setRoot: (hash) => realStore.setRoot(hash),
|
|
586
577
|
putNode: (hash, node) => realStore.putNode(hash, node),
|
|
587
578
|
deleteNode: (hash) => realStore.deleteNode(hash),
|
|
588
|
-
getNode: (hash) =>
|
|
579
|
+
getNode: async (hash) => {
|
|
589
580
|
if (corruptDuringDiff) {
|
|
590
581
|
lookupCount++;
|
|
591
582
|
// Return the root node (first lookup) but corrupt child nodes
|
|
@@ -594,33 +585,33 @@ describe('SparseMerkleTree', () => {
|
|
|
594
585
|
}
|
|
595
586
|
}
|
|
596
587
|
return realStore.getNode(hash);
|
|
597
|
-
}
|
|
588
|
+
},
|
|
598
589
|
};
|
|
599
590
|
// Build the corrupt tree with multiple elements (so root = internal node)
|
|
600
591
|
const corruptSmt = new SparseMerkleTree(corruptStore);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
592
|
+
await corruptSmt.initialize();
|
|
593
|
+
await corruptSmt.insert('bafyreiCorrupt1');
|
|
594
|
+
await corruptSmt.insert('bafyreiCorrupt2');
|
|
595
|
+
await corruptSmt.insert('bafyreiCorrupt3');
|
|
605
596
|
// Build normal tree with multiple elements (so root = internal node too)
|
|
606
597
|
const normalStore = new SMTStoreMemory();
|
|
607
598
|
const normalSmt = new SparseMerkleTree(normalStore);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
599
|
+
await normalSmt.initialize();
|
|
600
|
+
await normalSmt.insert('bafyreiNormal1');
|
|
601
|
+
await normalSmt.insert('bafyreiNormal2');
|
|
602
|
+
await normalSmt.insert('bafyreiNormal3');
|
|
612
603
|
// Corrupt the store so child nodes are missing during diff
|
|
613
604
|
corruptDuringDiff = true;
|
|
614
605
|
lookupCount = 0;
|
|
615
|
-
const diff =
|
|
606
|
+
const diff = await normalSmt.diff(corruptSmt);
|
|
616
607
|
// The diff should still complete — fallback collects leaves from the other side
|
|
617
608
|
// Normal tree's elements should be in onlyLocal
|
|
618
609
|
expect(diff.onlyLocal.sort()).toEqual(['bafyreiNormal1', 'bafyreiNormal2', 'bafyreiNormal3'].sort());
|
|
619
610
|
corruptDuringDiff = false;
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
})
|
|
623
|
-
it('should handle diff where local node is missing but remote exists', () =>
|
|
611
|
+
await corruptSmt.close();
|
|
612
|
+
await normalSmt.close();
|
|
613
|
+
});
|
|
614
|
+
it('should handle diff where local node is missing but remote exists', async () => {
|
|
624
615
|
// Test lines 689-692: localNode is undefined while remoteNode exists.
|
|
625
616
|
// Both trees need non-default hashes at the SAME child position so the
|
|
626
617
|
// recursion reaches line 628 (both load nodes). We achieve this by sharing
|
|
@@ -636,7 +627,7 @@ describe('SparseMerkleTree', () => {
|
|
|
636
627
|
setRoot: (hash) => realStore.setRoot(hash),
|
|
637
628
|
putNode: (hash, node) => realStore.putNode(hash, node),
|
|
638
629
|
deleteNode: (hash) => realStore.deleteNode(hash),
|
|
639
|
-
getNode: (hash) =>
|
|
630
|
+
getNode: async (hash) => {
|
|
640
631
|
if (corruptDuringDiff) {
|
|
641
632
|
lookupCount++;
|
|
642
633
|
// Return the root internal node (first lookup) but corrupt children
|
|
@@ -645,24 +636,24 @@ describe('SparseMerkleTree', () => {
|
|
|
645
636
|
}
|
|
646
637
|
}
|
|
647
638
|
return realStore.getNode(hash);
|
|
648
|
-
}
|
|
639
|
+
},
|
|
649
640
|
};
|
|
650
641
|
// Build corrupt tree (local) with shared + unique elements
|
|
651
642
|
const corruptSmt = new SparseMerkleTree(corruptStore);
|
|
652
|
-
|
|
643
|
+
await corruptSmt.initialize();
|
|
653
644
|
// Add many shared elements so both subtrees (left/right) are populated
|
|
654
645
|
for (let i = 0; i < 20; i++) {
|
|
655
|
-
|
|
646
|
+
await corruptSmt.insert(`bafyreiShared-${i}`);
|
|
656
647
|
}
|
|
657
|
-
|
|
648
|
+
await corruptSmt.insert('bafyreiCorruptOnly');
|
|
658
649
|
// Build normal tree (remote) with the same shared elements + different unique
|
|
659
650
|
const normalStore = new SMTStoreMemory();
|
|
660
651
|
const normalSmt = new SparseMerkleTree(normalStore);
|
|
661
|
-
|
|
652
|
+
await normalSmt.initialize();
|
|
662
653
|
for (let i = 0; i < 20; i++) {
|
|
663
|
-
|
|
654
|
+
await normalSmt.insert(`bafyreiShared-${i}`);
|
|
664
655
|
}
|
|
665
|
-
|
|
656
|
+
await normalSmt.insert('bafyreiNormalOnly');
|
|
666
657
|
// corruptSmt is local, normalSmt is remote
|
|
667
658
|
// The roots differ (different unique elements), both are internal nodes,
|
|
668
659
|
// and both have non-default children at the same positions (shared elements).
|
|
@@ -670,37 +661,37 @@ describe('SparseMerkleTree', () => {
|
|
|
670
661
|
// while remoteNode will be a real internal/leaf node → hits lines 689-692.
|
|
671
662
|
corruptDuringDiff = true;
|
|
672
663
|
lookupCount = 0;
|
|
673
|
-
const diff =
|
|
664
|
+
const diff = await corruptSmt.diff(normalSmt);
|
|
674
665
|
// The diff should complete. Remote leaves should appear in onlyRemote
|
|
675
666
|
// since the corrupt local can't prove they exist locally.
|
|
676
667
|
expect(diff.onlyRemote.length).toBeGreaterThan(0);
|
|
677
668
|
corruptDuringDiff = false;
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
})
|
|
669
|
+
await corruptSmt.close();
|
|
670
|
+
await normalSmt.close();
|
|
671
|
+
});
|
|
681
672
|
});
|
|
682
673
|
describe('node storage efficiency', () => {
|
|
683
|
-
it('should clean up internal nodes after deletion collapses the tree', () =>
|
|
684
|
-
|
|
685
|
-
|
|
674
|
+
it('should clean up internal nodes after deletion collapses the tree', async () => {
|
|
675
|
+
await smt.insert('bafyreiA');
|
|
676
|
+
await smt.insert('bafyreiB');
|
|
686
677
|
const sizeAfterInserts = store.size;
|
|
687
|
-
|
|
688
|
-
|
|
678
|
+
await smt.delete('bafyreiA');
|
|
679
|
+
await smt.delete('bafyreiB');
|
|
689
680
|
const sizeAfterDeletes = store.size;
|
|
690
681
|
// After deleting everything, the store should have fewer nodes than after inserts
|
|
691
682
|
expect(sizeAfterDeletes).toBeLessThan(sizeAfterInserts);
|
|
692
|
-
})
|
|
683
|
+
});
|
|
693
684
|
});
|
|
694
685
|
});
|
|
695
686
|
describe('SMT Utility Functions', () => {
|
|
696
687
|
describe('getDefaultHashes', () => {
|
|
697
|
-
it('should return default hashes after initialization', () =>
|
|
698
|
-
|
|
688
|
+
it('should return default hashes after initialization', async () => {
|
|
689
|
+
await initDefaultHashes();
|
|
699
690
|
const hashes = getDefaultHashes();
|
|
700
691
|
expect(hashes).toHaveLength(SMT_DEPTH + 1);
|
|
701
692
|
expect(hashEquals(hashes[SMT_DEPTH], ZERO_HASH)).toBe(true);
|
|
702
|
-
})
|
|
703
|
-
it('should throw when called before initDefaultHashes()', () =>
|
|
693
|
+
});
|
|
694
|
+
it('should throw when called before initDefaultHashes()', async () => {
|
|
704
695
|
// Reset the module-level cache
|
|
705
696
|
resetDefaultHashesForTesting();
|
|
706
697
|
try {
|
|
@@ -711,8 +702,8 @@ describe('SMT Utility Functions', () => {
|
|
|
711
702
|
expect(e.message).toContain('Default hashes not initialized');
|
|
712
703
|
}
|
|
713
704
|
// Re-initialize so subsequent tests aren't affected
|
|
714
|
-
|
|
715
|
-
})
|
|
705
|
+
await initDefaultHashes();
|
|
706
|
+
});
|
|
716
707
|
});
|
|
717
708
|
describe('hashEquals', () => {
|
|
718
709
|
it('should return false for hashes of different lengths', () => {
|
|
@@ -722,20 +713,20 @@ describe('SMT Utility Functions', () => {
|
|
|
722
713
|
});
|
|
723
714
|
});
|
|
724
715
|
describe('hashKey', () => {
|
|
725
|
-
it('should produce consistent hashes for the same input', () =>
|
|
726
|
-
const hash1 =
|
|
727
|
-
const hash2 =
|
|
716
|
+
it('should produce consistent hashes for the same input', async () => {
|
|
717
|
+
const hash1 = await hashKey('bafyreigtest');
|
|
718
|
+
const hash2 = await hashKey('bafyreigtest');
|
|
728
719
|
expect(hashEquals(hash1, hash2)).toBe(true);
|
|
729
|
-
})
|
|
730
|
-
it('should produce different hashes for different inputs', () =>
|
|
731
|
-
const hash1 =
|
|
732
|
-
const hash2 =
|
|
720
|
+
});
|
|
721
|
+
it('should produce different hashes for different inputs', async () => {
|
|
722
|
+
const hash1 = await hashKey('bafyreigtest1');
|
|
723
|
+
const hash2 = await hashKey('bafyreigtest2');
|
|
733
724
|
expect(hashEquals(hash1, hash2)).toBe(false);
|
|
734
|
-
})
|
|
735
|
-
it('should produce 32-byte hashes', () =>
|
|
736
|
-
const hash =
|
|
725
|
+
});
|
|
726
|
+
it('should produce 32-byte hashes', async () => {
|
|
727
|
+
const hash = await hashKey('bafyreigtest');
|
|
737
728
|
expect(hash.length).toBe(32);
|
|
738
|
-
})
|
|
729
|
+
});
|
|
739
730
|
});
|
|
740
731
|
});
|
|
741
732
|
//# sourceMappingURL=sparse-merkle-tree.spec.js.map
|