@ceramicnetwork/core
Version:
Typescript implementation of the Ceramic protocol
191 lines • 8.49 kB
JavaScript
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _InMemoryCAS_anchorOnRequest, _InMemoryCAS_queue, _InMemoryCAS_events, _InMemoryCAS_anchors, _InMemoryCAS_chainId, _InMemoryCAS_transactionCache;
import { AnchorRequestStatusName } from '@ceramicnetwork/common';
import { randomCID } from '@ceramicnetwork/streamid';
import { CARFactory } from 'cartonne';
import * as DAG_JOSE from 'dag-jose';
import { Subject } from 'rxjs';
class Candidate {
constructor(streamId, cid, key) {
this.streamId = streamId;
this.cid = cid;
this.key = key;
}
}
const V1_PROOF_TYPE = 'f(bytes32)';
const carFactory = new CARFactory();
carFactory.codecs.add(DAG_JOSE);
function groupCandidatesByStreamId(candidates) {
const result = {};
for (const req of candidates) {
const key = req.key;
const items = result[key] || [];
if (items.find((c) => c.cid.equals(req.cid))) {
continue;
}
items.push(req);
result[key] = items;
}
return result;
}
export class InMemoryCAS {
constructor(chainId, transactionCache, anchorOnRequest) {
_InMemoryCAS_anchorOnRequest.set(this, void 0);
_InMemoryCAS_queue.set(this, void 0);
_InMemoryCAS_events.set(this, void 0);
_InMemoryCAS_anchors.set(this, new Map());
_InMemoryCAS_chainId.set(this, void 0);
_InMemoryCAS_transactionCache.set(this, void 0);
__classPrivateFieldSet(this, _InMemoryCAS_chainId, chainId, "f");
__classPrivateFieldSet(this, _InMemoryCAS_transactionCache, transactionCache, "f");
__classPrivateFieldSet(this, _InMemoryCAS_anchorOnRequest, anchorOnRequest, "f");
__classPrivateFieldSet(this, _InMemoryCAS_queue, [], "f");
__classPrivateFieldSet(this, _InMemoryCAS_events, new Subject(), "f");
__classPrivateFieldGet(this, _InMemoryCAS_events, "f").subscribe((event) => {
__classPrivateFieldGet(this, _InMemoryCAS_anchors, "f").set(event.cid.toString(), event);
});
}
assertCASAccessible() {
}
async supportedChains() {
return [__classPrivateFieldGet(this, _InMemoryCAS_chainId, "f")];
}
anchor() {
const candidates = this.findCandidates();
for (const candidate of candidates) {
const event = this.process(candidate);
__classPrivateFieldGet(this, _InMemoryCAS_events, "f").next(event);
}
__classPrivateFieldSet(this, _InMemoryCAS_queue, [], "f");
}
async createRequest(streamId, tip, timestamp) {
const candidate = new Candidate(streamId, tip, streamId.toString());
let event;
if (__classPrivateFieldGet(this, _InMemoryCAS_anchorOnRequest, "f")) {
try {
event = this.process(candidate);
}
catch (e) {
event = {
status: AnchorRequestStatusName.FAILED,
streamId: streamId,
cid: tip,
message: e.message,
};
}
}
else {
const found = __classPrivateFieldGet(this, _InMemoryCAS_anchors, "f").get(tip.toString());
if (found) {
return found;
}
__classPrivateFieldGet(this, _InMemoryCAS_queue, "f").push(candidate);
event = {
status: AnchorRequestStatusName.PENDING,
streamId: streamId,
cid: tip,
message: 'Sending anchoring request',
};
}
__classPrivateFieldGet(this, _InMemoryCAS_events, "f").next(event);
return event;
}
async getStatusForRequest(streamId, tip) {
const found = __classPrivateFieldGet(this, _InMemoryCAS_anchors, "f").get(tip.toString());
if (found) {
return found;
}
else {
throw new Error(`Not found`);
}
}
findCandidates() {
const groupedCandidates = groupCandidatesByStreamId(__classPrivateFieldGet(this, _InMemoryCAS_queue, "f"));
return Object.values(groupedCandidates).map((candidates) => {
const init = candidates.slice(0, candidates.length - 1);
const last = candidates[candidates.length - 1];
for (const replaced of init) {
__classPrivateFieldGet(this, _InMemoryCAS_events, "f").next({
status: AnchorRequestStatusName.REPLACED,
streamId: replaced.streamId,
cid: replaced.cid,
message: 'replaced',
});
}
return last;
});
}
process(candidate) {
__classPrivateFieldGet(this, _InMemoryCAS_events, "f").next({
status: AnchorRequestStatusName.PROCESSING,
streamId: candidate.streamId,
cid: candidate.cid,
message: `Processing request to anchor CID ${candidate.cid.toString()} for stream ${candidate.streamId.toString()}`,
});
const timestamp = Math.floor(Date.now() / 1000);
const txHashCid = randomCID();
const proofData = {
chainId: __classPrivateFieldGet(this, _InMemoryCAS_chainId, "f"),
txHash: txHashCid,
root: candidate.cid,
txType: V1_PROOF_TYPE,
};
__classPrivateFieldGet(this, _InMemoryCAS_transactionCache, "f").set(txHashCid.toString(), timestamp);
const witnessCar = carFactory.build();
const proofCid = witnessCar.put(proofData);
const commit = {
proof: proofCid,
path: '',
prev: candidate.cid,
id: candidate.streamId.cid,
};
witnessCar.put(commit, { isRoot: true });
return {
status: AnchorRequestStatusName.COMPLETED,
streamId: candidate.streamId,
cid: candidate.cid,
message: 'CID successfully anchored',
witnessCar: witnessCar,
};
}
moveAnchors(from, to, reset) {
const candidates = __classPrivateFieldGet(this, _InMemoryCAS_queue, "f");
for (const candidate of candidates) {
const current = __classPrivateFieldGet(this, _InMemoryCAS_anchors, "f").get(candidate.cid.toString());
if (current && from === current.status) {
__classPrivateFieldGet(this, _InMemoryCAS_events, "f").next({
status: to,
streamId: candidate.streamId,
cid: candidate.cid,
message: `Moved anchor to ${to}`,
});
}
else if (!current) {
__classPrivateFieldGet(this, _InMemoryCAS_events, "f").next({
status: to,
streamId: candidate.streamId,
cid: candidate.cid,
message: `Set anchor to ${to}`,
});
}
}
if (reset) {
__classPrivateFieldSet(this, _InMemoryCAS_queue, [], "f");
}
}
async close() {
__classPrivateFieldGet(this, _InMemoryCAS_events, "f").complete();
}
}
_InMemoryCAS_anchorOnRequest = new WeakMap(), _InMemoryCAS_queue = new WeakMap(), _InMemoryCAS_events = new WeakMap(), _InMemoryCAS_anchors = new WeakMap(), _InMemoryCAS_chainId = new WeakMap(), _InMemoryCAS_transactionCache = new WeakMap();
//# sourceMappingURL=in-memory-cas.js.map