@polkadot-api/forklift 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +394 -0
- package/bin/cli.js +388 -0
- package/bin/cli.js.map +1 -0
- package/dist/.papi/descriptors/dist/descriptors-CVixQzDI.js +27 -0
- package/dist/.papi/descriptors/dist/descriptors-CVixQzDI.js.map +1 -0
- package/dist/.papi/descriptors/dist/index.js +40 -0
- package/dist/.papi/descriptors/dist/index.js.map +1 -0
- package/dist/.papi/descriptors/dist/metadataTypes-OmVFeQs5.js +4 -0
- package/dist/.papi/descriptors/dist/metadataTypes-OmVFeQs5.js.map +1 -0
- package/dist/.papi/descriptors/dist/parachain_metadata-CQQZadL1.js +4 -0
- package/dist/.papi/descriptors/dist/parachain_metadata-CQQZadL1.js.map +1 -0
- package/dist/.papi/descriptors/dist/relay_metadata-BAI7pjXf.js +4 -0
- package/dist/.papi/descriptors/dist/relay_metadata-BAI7pjXf.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/src/block-builder/create-block.js +232 -0
- package/dist/src/block-builder/create-block.js.map +1 -0
- package/dist/src/block-builder/para-enter.js +21 -0
- package/dist/src/block-builder/para-enter.js.map +1 -0
- package/dist/src/block-builder/set-validation-data.js +284 -0
- package/dist/src/block-builder/set-validation-data.js.map +1 -0
- package/dist/src/block-builder/slot-utils.js +68 -0
- package/dist/src/block-builder/slot-utils.js.map +1 -0
- package/dist/src/block-builder/timestamp.js +20 -0
- package/dist/src/block-builder/timestamp.js.map +1 -0
- package/dist/src/chain.js +334 -0
- package/dist/src/chain.js.map +1 -0
- package/dist/src/codecs.js +103 -0
- package/dist/src/codecs.js.map +1 -0
- package/dist/src/executor.js +87 -0
- package/dist/src/executor.js.map +1 -0
- package/dist/src/forklift.js +177 -0
- package/dist/src/forklift.js.map +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/logger.js +11 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/prequeries.js +19 -0
- package/dist/src/prequeries.js.map +1 -0
- package/dist/src/rpc/archive_v1.js +223 -0
- package/dist/src/rpc/archive_v1.js.map +1 -0
- package/dist/src/rpc/chainHead_v1.js +383 -0
- package/dist/src/rpc/chainHead_v1.js.map +1 -0
- package/dist/src/rpc/chainSpec_v1.js +14 -0
- package/dist/src/rpc/chainSpec_v1.js.map +1 -0
- package/dist/src/rpc/dev.js +32 -0
- package/dist/src/rpc/dev.js.map +1 -0
- package/dist/src/rpc/forklift_xcm.js +99 -0
- package/dist/src/rpc/forklift_xcm.js.map +1 -0
- package/dist/src/rpc/rpc_utils.js +20 -0
- package/dist/src/rpc/rpc_utils.js.map +1 -0
- package/dist/src/rpc/transaction_v1.js +13 -0
- package/dist/src/rpc/transaction_v1.js.map +1 -0
- package/dist/src/serve.js +88 -0
- package/dist/src/serve.js.map +1 -0
- package/dist/src/source.js +125 -0
- package/dist/src/source.js.map +1 -0
- package/dist/src/storage.js +223 -0
- package/dist/src/storage.js.map +1 -0
- package/dist/src/txPool.js +177 -0
- package/dist/src/txPool.js.map +1 -0
- package/dist/src/xcm.js +292 -0
- package/dist/src/xcm.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { Binary, Enum } from 'polkadot-api';
|
|
2
|
+
import { Subject, Subscription, from, switchMap, withLatestFrom, firstValueFrom, combineLatest } from 'rxjs';
|
|
3
|
+
import { finalizedAndPruned$ } from './chain.js';
|
|
4
|
+
import { getCallCodec } from './codecs.js';
|
|
5
|
+
import { runRuntimeCall } from './executor.js';
|
|
6
|
+
import { logger } from './logger.js';
|
|
7
|
+
|
|
8
|
+
const log = logger.child({ module: "txPool" });
|
|
9
|
+
const createTxPool = (chainP) => {
|
|
10
|
+
const blocksTxPool = {};
|
|
11
|
+
const txAdded$ = new Subject();
|
|
12
|
+
const validateTx = async (block, tx) => {
|
|
13
|
+
const codec = await getCallCodec(
|
|
14
|
+
block,
|
|
15
|
+
"TaggedTransactionQueue",
|
|
16
|
+
"validate_transaction"
|
|
17
|
+
);
|
|
18
|
+
if (!codec)
|
|
19
|
+
throw new Error("TaggedTransactionQueue_validate_transaction required");
|
|
20
|
+
const result = await runRuntimeCall({
|
|
21
|
+
chain: await chainP,
|
|
22
|
+
hash: block.hash,
|
|
23
|
+
call: "TaggedTransactionQueue_validate_transaction",
|
|
24
|
+
params: Binary.toHex(
|
|
25
|
+
codec.args.enc([
|
|
26
|
+
Enum("External", void 0),
|
|
27
|
+
Binary.fromOpaque(tx),
|
|
28
|
+
block.hash
|
|
29
|
+
])
|
|
30
|
+
)
|
|
31
|
+
});
|
|
32
|
+
return codec.value.dec(result.result);
|
|
33
|
+
};
|
|
34
|
+
const getAliveBlocks = async () => {
|
|
35
|
+
const chain = await chainP;
|
|
36
|
+
const [finalized, blocks] = await firstValueFrom(
|
|
37
|
+
combineLatest([chain.finalized$, chain.blocks$])
|
|
38
|
+
);
|
|
39
|
+
const heads = [];
|
|
40
|
+
const include = (hash) => {
|
|
41
|
+
const block = blocks[hash];
|
|
42
|
+
heads.push(block);
|
|
43
|
+
block.children.forEach(include);
|
|
44
|
+
};
|
|
45
|
+
include(finalized);
|
|
46
|
+
return heads;
|
|
47
|
+
};
|
|
48
|
+
const subscription = new Subscription();
|
|
49
|
+
subscription.add(
|
|
50
|
+
from(Promise.resolve(chainP)).pipe(
|
|
51
|
+
switchMap(
|
|
52
|
+
(chain) => chain.newBlocks$.pipe(withLatestFrom(chain.blocks$))
|
|
53
|
+
)
|
|
54
|
+
).subscribe(([blockHash, blocks]) => {
|
|
55
|
+
const block = blocks[blockHash];
|
|
56
|
+
const parentTxPool = blocksTxPool[block.parent] ?? /* @__PURE__ */ new Map();
|
|
57
|
+
const txPool = blocksTxPool[block.hash] = /* @__PURE__ */ new Map();
|
|
58
|
+
parentTxPool.forEach((validation, tx) => {
|
|
59
|
+
if (block.body.includes(tx)) return;
|
|
60
|
+
txPool.set(tx, validation);
|
|
61
|
+
});
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
subscription.add(
|
|
65
|
+
from(Promise.resolve(chainP)).pipe(switchMap((chain) => finalizedAndPruned$(chain))).subscribe(
|
|
66
|
+
({ pruned }) => pruned.forEach((hash) => {
|
|
67
|
+
const txPool = blocksTxPool[hash];
|
|
68
|
+
if (!txPool) return;
|
|
69
|
+
txPool.clear();
|
|
70
|
+
delete blocksTxPool[hash];
|
|
71
|
+
})
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
return {
|
|
75
|
+
async addTx(tx) {
|
|
76
|
+
const blocks = await getAliveBlocks();
|
|
77
|
+
blocks.forEach((block) => {
|
|
78
|
+
var _a;
|
|
79
|
+
const txPool = blocksTxPool[_a = block.hash] ?? (blocksTxPool[_a] = /* @__PURE__ */ new Map());
|
|
80
|
+
if (txPool.has(tx)) return;
|
|
81
|
+
txPool.set(
|
|
82
|
+
tx,
|
|
83
|
+
validateTx(block, tx).then((res) => {
|
|
84
|
+
if (!res.success) {
|
|
85
|
+
log.error(
|
|
86
|
+
{ blockHash: block.hash, reason: res.value },
|
|
87
|
+
"invalid transaction"
|
|
88
|
+
);
|
|
89
|
+
throw res.value;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
priority: res.value.priority,
|
|
93
|
+
provides: new Set(res.value.provides.map(Binary.toHex)),
|
|
94
|
+
requires: new Set(res.value.requires.map(Binary.toHex))
|
|
95
|
+
};
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
txAdded$.next();
|
|
100
|
+
},
|
|
101
|
+
getTxsForBlock: async (block) => {
|
|
102
|
+
const blockTxPool = blocksTxPool[block.hash];
|
|
103
|
+
if (!blockTxPool) return [];
|
|
104
|
+
const awaitedTxs = await Promise.all(
|
|
105
|
+
blockTxPool.entries().map(async ([tx, validateP]) => {
|
|
106
|
+
try {
|
|
107
|
+
return { tx, validation: await validateP };
|
|
108
|
+
} catch {
|
|
109
|
+
return { tx, validation: null };
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
awaitedTxs.forEach((tx) => {
|
|
114
|
+
if (tx.validation == null) {
|
|
115
|
+
blockTxPool.delete(tx.tx);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const validTxs = awaitedTxs.filter((v) => v.validation != null);
|
|
119
|
+
return sortValidatedTxs(validTxs);
|
|
120
|
+
},
|
|
121
|
+
destroy() {
|
|
122
|
+
subscription.unsubscribe();
|
|
123
|
+
for (const hash in blocksTxPool) {
|
|
124
|
+
blocksTxPool[hash].clear();
|
|
125
|
+
delete blocksTxPool[hash];
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
txAdded$: txAdded$.asObservable()
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
const sortValidatedTxs = (txs) => {
|
|
132
|
+
const result = txs.filter((tx) => tx.validation.requires.size === 0);
|
|
133
|
+
let pending = txs.filter((tx) => tx.validation.requires.size > 0);
|
|
134
|
+
const providedTags = {};
|
|
135
|
+
const includeTags = (tx) => tx.validation.provides.forEach((tag) => {
|
|
136
|
+
const p = tx.validation.priority;
|
|
137
|
+
const v = providedTags[tag];
|
|
138
|
+
providedTags[tag] = v == null ? p : v < p ? p : v;
|
|
139
|
+
});
|
|
140
|
+
result.forEach(includeTags);
|
|
141
|
+
let toPromote;
|
|
142
|
+
do {
|
|
143
|
+
const pendingPromotion = pending.map((original) => {
|
|
144
|
+
const maxPriority = [...original.validation.requires].map((req) => providedTags[req]).reduce(
|
|
145
|
+
(a, b) => a == null || b == null ? void 0 : a > b ? b : a,
|
|
146
|
+
BigInt(Number.MAX_SAFE_INTEGER)
|
|
147
|
+
);
|
|
148
|
+
if (maxPriority == null) {
|
|
149
|
+
return { type: "pending", tx: original };
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
type: "promote",
|
|
153
|
+
tx: {
|
|
154
|
+
...original,
|
|
155
|
+
validation: {
|
|
156
|
+
...original.validation,
|
|
157
|
+
// put it below the last tag provider
|
|
158
|
+
priority: maxPriority - 1n
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
toPromote = pendingPromotion.filter((pp) => pp.type === "promote").map((pp) => pp.tx);
|
|
164
|
+
pending = pendingPromotion.filter((pp) => pp.type === "pending").map((pp) => pp.tx);
|
|
165
|
+
toPromote.forEach((tx) => {
|
|
166
|
+
includeTags(tx);
|
|
167
|
+
result.push(tx);
|
|
168
|
+
});
|
|
169
|
+
} while (toPromote.length > 0);
|
|
170
|
+
const sorted = result.sort(
|
|
171
|
+
(a, b) => Number(b.validation.priority - a.validation.priority)
|
|
172
|
+
);
|
|
173
|
+
return sorted.map((v) => v.tx);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export { createTxPool };
|
|
177
|
+
//# sourceMappingURL=txPool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"txPool.js","sources":["../../src/txPool.ts"],"sourcesContent":["import { Binary, Enum, type HexString, type ResultPayload } from \"polkadot-api\";\nimport {\n combineLatest,\n firstValueFrom,\n from,\n Subject,\n Subscription,\n switchMap,\n withLatestFrom,\n type Observable,\n} from \"rxjs\";\nimport type { Block } from \"./block-builder/create-block\";\nimport { finalizedAndPruned$, type Chain } from \"./chain\";\nimport { getCallCodec } from \"./codecs\";\nimport { runRuntimeCall } from \"./executor\";\nimport { logger } from \"./logger\";\n\nconst log = logger.child({ module: \"txPool\" });\n\ntype Validation = {\n provides: Set<HexString>;\n requires: Set<HexString>;\n priority: bigint;\n};\ntype BlockTxPool = Map<Uint8Array, Promise<Validation>>;\n\n/**\n * This tx pool is simplified: There's just one set of transactions, that get\n * validated against the best block, but fallbacking to others.\n */\nexport interface TxPool {\n addTx: (tx: Uint8Array) => Promise<void>;\n getTxsForBlock: (block: Block) => Promise<Uint8Array[]>;\n destroy: () => void;\n\n txAdded$: Observable<void>;\n}\n\nexport const createTxPool = (chainP: Chain | Promise<Chain>): TxPool => {\n const blocksTxPool: Record<HexString, BlockTxPool> = {};\n const txAdded$ = new Subject<void>();\n\n const validateTx = async (\n block: Block,\n tx: Uint8Array\n ): Promise<\n ResultPayload<\n {\n priority: bigint;\n longevity: bigint;\n provides: Array<Uint8Array>;\n requires: Array<Uint8Array>;\n },\n {}\n >\n > => {\n const codec = await getCallCodec(\n block,\n \"TaggedTransactionQueue\",\n \"validate_transaction\"\n )!;\n if (!codec)\n throw new Error(\"TaggedTransactionQueue_validate_transaction required\");\n\n const result = await runRuntimeCall({\n chain: await chainP,\n hash: block.hash,\n call: \"TaggedTransactionQueue_validate_transaction\",\n params: Binary.toHex(\n codec.args.enc([\n Enum(\"External\", undefined),\n Binary.fromOpaque(tx),\n block.hash,\n ])\n ),\n });\n\n return codec.value.dec(result.result);\n };\n\n const getAliveBlocks = async () => {\n const chain = await chainP;\n const [finalized, blocks] = await firstValueFrom(\n combineLatest([chain.finalized$, chain.blocks$])\n );\n\n const heads: Block[] = [];\n const include = (hash: HexString) => {\n const block = blocks[hash]!;\n heads.push(block);\n block.children.forEach(include);\n };\n include(finalized);\n return heads;\n };\n\n const subscription = new Subscription();\n subscription.add(\n from(Promise.resolve(chainP))\n .pipe(\n switchMap((chain) =>\n chain.newBlocks$.pipe(withLatestFrom(chain.blocks$))\n )\n )\n .subscribe(([blockHash, blocks]) => {\n const block = blocks[blockHash]!;\n\n const parentTxPool: BlockTxPool =\n blocksTxPool[block.parent] ?? new Map();\n const txPool: BlockTxPool = (blocksTxPool[block.hash] = new Map());\n\n parentTxPool.forEach((validation, tx) => {\n if (block.body.includes(tx)) return;\n txPool.set(tx, validation);\n });\n })\n );\n subscription.add(\n from(Promise.resolve(chainP))\n .pipe(switchMap((chain) => finalizedAndPruned$(chain)))\n .subscribe(({ pruned }) =>\n pruned.forEach((hash) => {\n const txPool = blocksTxPool[hash];\n if (!txPool) return;\n txPool.clear();\n delete blocksTxPool[hash];\n })\n )\n );\n\n return {\n async addTx(tx) {\n const blocks = await getAliveBlocks();\n\n blocks.forEach((block) => {\n const txPool = (blocksTxPool[block.hash] ??= new Map());\n if (txPool.has(tx)) return;\n\n txPool.set(\n tx,\n validateTx(block, tx).then((res) => {\n if (!res.success) {\n log.error(\n { blockHash: block.hash, reason: res.value },\n \"invalid transaction\"\n );\n throw res.value;\n }\n return {\n priority: res.value.priority,\n provides: new Set(res.value.provides.map(Binary.toHex)),\n requires: new Set(res.value.requires.map(Binary.toHex)),\n };\n })\n );\n });\n\n txAdded$.next();\n },\n getTxsForBlock: async (block) => {\n const blockTxPool = blocksTxPool[block.hash];\n if (!blockTxPool) return [];\n\n const awaitedTxs = await Promise.all(\n blockTxPool.entries().map(async ([tx, validateP]) => {\n try {\n return { tx, validation: await validateP };\n } catch {\n return { tx, validation: null };\n }\n })\n );\n\n // prune invalid transactions from the block\n awaitedTxs.forEach((tx) => {\n if (tx.validation == null) {\n blockTxPool.delete(tx.tx);\n }\n });\n\n const validTxs = awaitedTxs.filter((v) => v.validation != null);\n\n return sortValidatedTxs(validTxs);\n },\n destroy() {\n subscription.unsubscribe();\n for (const hash in blocksTxPool) {\n blocksTxPool[hash]!.clear();\n delete blocksTxPool[hash];\n }\n },\n txAdded$: txAdded$.asObservable(),\n };\n};\n\nconst sortValidatedTxs = (\n txs: Array<{\n tx: Uint8Array<ArrayBufferLike>;\n validation: Validation;\n }>\n) => {\n const result = txs.filter((tx) => tx.validation.requires.size === 0);\n let pending = txs.filter((tx) => tx.validation.requires.size > 0);\n\n const providedTags: Record<HexString, bigint> = {};\n const includeTags = (tx: {\n tx: Uint8Array<ArrayBufferLike>;\n validation: Validation;\n }) =>\n tx.validation.provides.forEach((tag) => {\n const p = tx.validation.priority;\n const v = providedTags[tag];\n // Keep the highest priority, as we want to be less restrictive with other txs.\n providedTags[tag] = v == null ? p : v < p ? p : v;\n });\n result.forEach(includeTags);\n\n let toPromote: typeof result;\n do {\n const pendingPromotion = pending.map((original) => {\n const maxPriority = [...original.validation.requires]\n .map((req) => providedTags[req])\n .reduce(\n (a, b) => (a == null || b == null ? undefined : a > b ? b : a),\n BigInt(Number.MAX_SAFE_INTEGER)\n );\n if (maxPriority == null) {\n return { type: \"pending\", tx: original };\n }\n return {\n type: \"promote\",\n tx: {\n ...original,\n validation: {\n ...original.validation,\n // put it below the last tag provider\n priority: maxPriority - 1n,\n },\n },\n };\n });\n toPromote = pendingPromotion\n .filter((pp) => pp.type === \"promote\")\n .map((pp) => pp.tx);\n pending = pendingPromotion\n .filter((pp) => pp.type === \"pending\")\n .map((pp) => pp.tx);\n toPromote.forEach((tx) => {\n includeTags(tx);\n result.push(tx);\n });\n } while (toPromote.length > 0);\n\n const sorted = result.sort((a, b) =>\n Number(b.validation.priority - a.validation.priority)\n );\n // console.log(\"sorted transactions\", sorted);\n return sorted.map((v) => v.tx);\n};\n"],"names":[],"mappings":"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"}
|
package/dist/src/xcm.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { parachain as _allDescriptors, relay as _allDescriptors$1 } from '../.papi/descriptors/dist/index.js';
|
|
2
|
+
import { concatMapEager } from '@polkadot-api/observable-client';
|
|
3
|
+
import { Tuple, Struct, bool, u32, Bytes } from '@polkadot-api/substrate-bindings';
|
|
4
|
+
import { Enum, Binary, CompatibilityLevel } from 'polkadot-api';
|
|
5
|
+
import { firstValueFrom, from, catchError, map, filter } from 'rxjs';
|
|
6
|
+
import { getStorageCodecs, getConstant } from './codecs.js';
|
|
7
|
+
import { getNode, insertValue } from './storage.js';
|
|
8
|
+
import { logger } from './logger.js';
|
|
9
|
+
|
|
10
|
+
const log = logger.child({ module: "xcm" });
|
|
11
|
+
const attachRelay = async (relayClient, parachainClient, chain, xcm) => {
|
|
12
|
+
const paraId = await getConstant(
|
|
13
|
+
chain.getBlock(await firstValueFrom(chain.finalized$)),
|
|
14
|
+
"ParachainSystem",
|
|
15
|
+
"SelfParaId"
|
|
16
|
+
);
|
|
17
|
+
if (paraId == null) {
|
|
18
|
+
throw new Error("Could not get parachain ID");
|
|
19
|
+
}
|
|
20
|
+
const typedApi = relayClient.getTypedApi(_allDescriptors$1);
|
|
21
|
+
const staticApis = await typedApi.getStaticApis();
|
|
22
|
+
if (!staticApis.compat.query.Dmp.DownwardMessageQueues.isCompatible(
|
|
23
|
+
CompatibilityLevel.Partial
|
|
24
|
+
)) {
|
|
25
|
+
throw new Error("Dmp queue incompatible");
|
|
26
|
+
}
|
|
27
|
+
const parachainApi = parachainClient.getTypedApi(_allDescriptors);
|
|
28
|
+
if (!(await parachainApi.getStaticApis()).compat.query.ParachainSystem.UpwardMessages.isCompatible(
|
|
29
|
+
CompatibilityLevel.Partial
|
|
30
|
+
)) {
|
|
31
|
+
throw new Error("UpwardMessageQueue incompatible");
|
|
32
|
+
}
|
|
33
|
+
log.debug("watching dmp queue");
|
|
34
|
+
let lastSentAt = 0;
|
|
35
|
+
typedApi.query.Dmp.DownwardMessageQueues.watchValue(paraId).pipe(
|
|
36
|
+
map(({ block, value }) => ({
|
|
37
|
+
block,
|
|
38
|
+
messages: value.filter((v) => v.sent_at > lastSentAt)
|
|
39
|
+
})),
|
|
40
|
+
filter(({ messages }) => messages.length > 0)
|
|
41
|
+
).subscribe(({ block, messages }) => {
|
|
42
|
+
relayClient._request("forklift_xcm_consume_dmp", [block.hash, paraId]);
|
|
43
|
+
lastSentAt = messages.map((m) => m.sent_at).reduce((a, b) => Math.max(a, b));
|
|
44
|
+
xcm.pushDmp(messages);
|
|
45
|
+
});
|
|
46
|
+
log.debug("watching ump queue");
|
|
47
|
+
parachainClient.finalizedBlock$.pipe(
|
|
48
|
+
concatMapEager(
|
|
49
|
+
(block) => from(
|
|
50
|
+
parachainApi.query.ParachainSystem.UpwardMessages.getValue({
|
|
51
|
+
at: block.hash
|
|
52
|
+
})
|
|
53
|
+
).pipe(
|
|
54
|
+
catchError((ex) => {
|
|
55
|
+
log.error(ex, "error reading upward messages");
|
|
56
|
+
return [];
|
|
57
|
+
})
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
).subscribe((messages) => {
|
|
61
|
+
relayClient._request("forklift_xcm_push_ump", [
|
|
62
|
+
paraId,
|
|
63
|
+
messages.map(Binary.toHex)
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
const consumeDmp = async (chain, hash, paraId) => {
|
|
68
|
+
const blocks = await firstValueFrom(chain.blocks$);
|
|
69
|
+
const targetBlock = blocks[hash];
|
|
70
|
+
if (!targetBlock) {
|
|
71
|
+
throw new Error("Block not found");
|
|
72
|
+
}
|
|
73
|
+
const codecs = await getStorageCodecs(
|
|
74
|
+
targetBlock,
|
|
75
|
+
"Dmp",
|
|
76
|
+
"DownwardMessageQueues"
|
|
77
|
+
);
|
|
78
|
+
if (!codecs) {
|
|
79
|
+
throw new Error("Dmp.DownwardMessageQueues not found");
|
|
80
|
+
}
|
|
81
|
+
const dmqKey = codecs.keys.enc(paraId);
|
|
82
|
+
const dmqBinKey = Binary.fromHex(dmqKey);
|
|
83
|
+
const targetDmqNode = await chain.getStorage(hash, dmqKey);
|
|
84
|
+
const targetDmq = targetDmqNode.value ? codecs.value.dec(targetDmqNode.value) : [];
|
|
85
|
+
if (targetDmq.length === 0) return;
|
|
86
|
+
const getDmpMessageKey = (msg) => `${msg.sent_at}_${Binary.toHex(msg.msg)}`;
|
|
87
|
+
const targetDmqKeys = new Set(targetDmq.map(getDmpMessageKey));
|
|
88
|
+
let blocksToUpdate = [hash];
|
|
89
|
+
while (blocksToUpdate.length) {
|
|
90
|
+
const hash2 = blocksToUpdate.pop();
|
|
91
|
+
const block = blocks[hash2];
|
|
92
|
+
blocksToUpdate = [...block.children, ...blocksToUpdate];
|
|
93
|
+
const childDmqNode = getNode(
|
|
94
|
+
block.storageRoot,
|
|
95
|
+
dmqBinKey,
|
|
96
|
+
dmqBinKey.length * 2
|
|
97
|
+
);
|
|
98
|
+
const childDmq = childDmqNode?.value ? codecs.value.dec(childDmqNode.value) : [];
|
|
99
|
+
const newChildDmq = childDmq.filter(
|
|
100
|
+
(v) => !targetDmqKeys.has(getDmpMessageKey(v))
|
|
101
|
+
);
|
|
102
|
+
block.storageRoot = insertValue(
|
|
103
|
+
block.storageRoot,
|
|
104
|
+
dmqBinKey,
|
|
105
|
+
dmqBinKey.length * 2,
|
|
106
|
+
codecs.value.enc(newChildDmq)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
log.info({ paraId, count: targetDmq.length }, "cleared DMP messages");
|
|
110
|
+
};
|
|
111
|
+
const pushUmp = async (chain, paraId, messages) => {
|
|
112
|
+
if (messages.length === 0) return;
|
|
113
|
+
const finalizedHash = await firstValueFrom(chain.finalized$);
|
|
114
|
+
const blocks = await firstValueFrom(chain.blocks$);
|
|
115
|
+
const finalizedBlock = blocks[finalizedHash];
|
|
116
|
+
if (!finalizedBlock) throw new Error(" lock not found");
|
|
117
|
+
const [pageCodecs, bookCodecs, serviceHeadCodecs] = await Promise.all([
|
|
118
|
+
getStorageCodecs(finalizedBlock, "MessageQueue", "Pages"),
|
|
119
|
+
getStorageCodecs(finalizedBlock, "MessageQueue", "BookStateFor"),
|
|
120
|
+
getStorageCodecs(finalizedBlock, "MessageQueue", "ServiceHead")
|
|
121
|
+
]);
|
|
122
|
+
if (!(serviceHeadCodecs && bookCodecs && pageCodecs))
|
|
123
|
+
throw new Error("MessageQueue codecs not found");
|
|
124
|
+
const totalMsgSize = messages.reduce((acc, p) => acc + p.length, 0);
|
|
125
|
+
const lastOffset = messages.slice(0, -1).reduce((acc, msg) => acc + 5 + msg.length, 0);
|
|
126
|
+
const heap = heapEncoder(messages);
|
|
127
|
+
const origin = Enum("Ump", Enum("Para", paraId));
|
|
128
|
+
const bookBinKey = Binary.fromHex(bookCodecs.keys.enc(origin));
|
|
129
|
+
const serviceHeadBinKey = Binary.fromHex(serviceHeadCodecs.keys.enc());
|
|
130
|
+
let blocksToUpdate = [finalizedHash];
|
|
131
|
+
while (blocksToUpdate.length) {
|
|
132
|
+
const hash = blocksToUpdate.pop();
|
|
133
|
+
const block = blocks[hash];
|
|
134
|
+
blocksToUpdate = [...block.children, ...blocksToUpdate];
|
|
135
|
+
const existingBookNode = getNode(
|
|
136
|
+
block.storageRoot,
|
|
137
|
+
bookBinKey,
|
|
138
|
+
bookBinKey.length * 2
|
|
139
|
+
);
|
|
140
|
+
const existingBook = existingBookNode?.value ? bookCodecs.value.dec(existingBookNode.value) : null;
|
|
141
|
+
const wasEmpty = !existingBook || existingBook.begin === existingBook.end;
|
|
142
|
+
const pageIndex = existingBook ? existingBook.end : 0;
|
|
143
|
+
const pageBinKey = Binary.fromHex(pageCodecs.keys.enc(origin, pageIndex));
|
|
144
|
+
const newBook = {
|
|
145
|
+
begin: existingBook?.begin ?? 0,
|
|
146
|
+
end: pageIndex + 1,
|
|
147
|
+
count: (existingBook?.count ?? 0) + 1,
|
|
148
|
+
ready_neighbours: existingBook?.ready_neighbours ?? void 0,
|
|
149
|
+
message_count: (existingBook?.message_count ?? 0n) + BigInt(messages.length),
|
|
150
|
+
size: (existingBook?.size ?? 0n) + BigInt(totalMsgSize)
|
|
151
|
+
};
|
|
152
|
+
const page = {
|
|
153
|
+
remaining: messages.length,
|
|
154
|
+
remaining_size: totalMsgSize,
|
|
155
|
+
first_index: 0,
|
|
156
|
+
first: 0,
|
|
157
|
+
last: lastOffset,
|
|
158
|
+
heap
|
|
159
|
+
};
|
|
160
|
+
block.storageRoot = insertValue(
|
|
161
|
+
block.storageRoot,
|
|
162
|
+
pageBinKey,
|
|
163
|
+
pageBinKey.length * 2,
|
|
164
|
+
pageCodecs.value.enc(page)
|
|
165
|
+
);
|
|
166
|
+
if (wasEmpty) {
|
|
167
|
+
const serviceHeadNode = getNode(
|
|
168
|
+
block.storageRoot,
|
|
169
|
+
serviceHeadBinKey,
|
|
170
|
+
serviceHeadBinKey.length * 2
|
|
171
|
+
);
|
|
172
|
+
const existingServiceHead = serviceHeadNode?.value ? serviceHeadCodecs.value.dec(serviceHeadNode.value) : null;
|
|
173
|
+
if (existingServiceHead) {
|
|
174
|
+
newBook.ready_neighbours = { prev: origin, next: existingServiceHead };
|
|
175
|
+
const existingHeadBookBinKey = Binary.fromHex(
|
|
176
|
+
bookCodecs.keys.enc(existingServiceHead)
|
|
177
|
+
);
|
|
178
|
+
const existingHeadBookNode = getNode(
|
|
179
|
+
block.storageRoot,
|
|
180
|
+
existingHeadBookBinKey,
|
|
181
|
+
existingHeadBookBinKey.length * 2
|
|
182
|
+
);
|
|
183
|
+
const existingHeadBook = existingHeadBookNode?.value ? bookCodecs.value.dec(existingHeadBookNode.value) : null;
|
|
184
|
+
if (existingHeadBook?.ready_neighbours) {
|
|
185
|
+
existingHeadBook.ready_neighbours.prev = origin;
|
|
186
|
+
block.storageRoot = insertValue(
|
|
187
|
+
block.storageRoot,
|
|
188
|
+
existingHeadBookBinKey,
|
|
189
|
+
existingHeadBookBinKey.length * 2,
|
|
190
|
+
bookCodecs.value.enc(existingHeadBook)
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
newBook.ready_neighbours = { prev: origin, next: origin };
|
|
195
|
+
}
|
|
196
|
+
block.storageRoot = insertValue(
|
|
197
|
+
block.storageRoot,
|
|
198
|
+
serviceHeadBinKey,
|
|
199
|
+
serviceHeadBinKey.length * 2,
|
|
200
|
+
serviceHeadCodecs.value.enc(origin)
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
block.storageRoot = insertValue(
|
|
204
|
+
block.storageRoot,
|
|
205
|
+
bookBinKey,
|
|
206
|
+
bookBinKey.length * 2,
|
|
207
|
+
bookCodecs.value.enc(newBook)
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const attachSibling = async (siblingClient, selfClient, chain, xcm) => {
|
|
212
|
+
const selfParaId = await getConstant(
|
|
213
|
+
chain.getBlock(await firstValueFrom(chain.finalized$)),
|
|
214
|
+
"ParachainSystem",
|
|
215
|
+
"SelfParaId"
|
|
216
|
+
);
|
|
217
|
+
if (selfParaId == null) throw new Error("Could not get self parachain ID");
|
|
218
|
+
const siblingApi = siblingClient.getTypedApi(_allDescriptors);
|
|
219
|
+
const selfApi = selfClient.getTypedApi(_allDescriptors);
|
|
220
|
+
const staticApis = await siblingApi.getStaticApis();
|
|
221
|
+
if (!staticApis.compat.query.ParachainSystem.HrmpOutboundMessages.isCompatible(
|
|
222
|
+
CompatibilityLevel.Partial
|
|
223
|
+
)) {
|
|
224
|
+
throw new Error("HrmpOutboundMessages incompatible");
|
|
225
|
+
}
|
|
226
|
+
const siblingParaId = await siblingApi.constants.ParachainSystem.SelfParaId();
|
|
227
|
+
log.info({ selfParaId, siblingParaId }, "attaching HRMP channel");
|
|
228
|
+
chain.openHrmpChannel(siblingParaId);
|
|
229
|
+
siblingClient._request("forklift_xcm_open_hrmp_channel", [selfParaId]);
|
|
230
|
+
siblingClient.finalizedBlock$.pipe(
|
|
231
|
+
concatMapEager(
|
|
232
|
+
(block) => from(
|
|
233
|
+
siblingApi.query.ParachainSystem.HrmpOutboundMessages.getValue({
|
|
234
|
+
at: block.hash
|
|
235
|
+
})
|
|
236
|
+
).pipe(
|
|
237
|
+
catchError((ex) => {
|
|
238
|
+
log.error(ex, "error reading sibling HRMP outbound messages");
|
|
239
|
+
return [];
|
|
240
|
+
})
|
|
241
|
+
)
|
|
242
|
+
)
|
|
243
|
+
).subscribe((messages) => {
|
|
244
|
+
const forSelf = messages.filter((m) => m.recipient === selfParaId);
|
|
245
|
+
if (forSelf.length > 0) {
|
|
246
|
+
xcm.pushHrmp(
|
|
247
|
+
siblingParaId,
|
|
248
|
+
forSelf.map((m) => m.data)
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
selfClient.finalizedBlock$.pipe(
|
|
253
|
+
concatMapEager(
|
|
254
|
+
(block) => from(
|
|
255
|
+
selfApi.query.ParachainSystem.HrmpOutboundMessages.getValue({
|
|
256
|
+
at: block.hash
|
|
257
|
+
})
|
|
258
|
+
).pipe(
|
|
259
|
+
catchError((ex) => {
|
|
260
|
+
log.error(ex, "error reading self HRMP outbound messages");
|
|
261
|
+
return [];
|
|
262
|
+
})
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
).subscribe((messages) => {
|
|
266
|
+
const forSibling = messages.filter((m) => m.recipient === siblingParaId);
|
|
267
|
+
if (forSibling.length > 0) {
|
|
268
|
+
siblingClient._request("forklift_xcm_push_hrmp", [
|
|
269
|
+
selfParaId,
|
|
270
|
+
forSibling.map((m) => Binary.toHex(m.data))
|
|
271
|
+
]);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
};
|
|
275
|
+
const heapEncoder = (value) => Tuple(
|
|
276
|
+
...value.map(
|
|
277
|
+
(coded) => Struct({
|
|
278
|
+
length: u32,
|
|
279
|
+
is_processed: bool,
|
|
280
|
+
payload: Bytes(coded.length)
|
|
281
|
+
})
|
|
282
|
+
)
|
|
283
|
+
).enc(
|
|
284
|
+
value.map((payload) => ({
|
|
285
|
+
length: payload.length,
|
|
286
|
+
is_processed: false,
|
|
287
|
+
payload
|
|
288
|
+
}))
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
export { attachRelay, attachSibling, consumeDmp, pushUmp };
|
|
292
|
+
//# sourceMappingURL=xcm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xcm.js","sources":["../../src/xcm.ts"],"sourcesContent":["import { parachain, relay } from \"../.papi/descriptors/dist\";\nimport { concatMapEager } from \"@polkadot-api/observable-client\";\nimport {\n bool,\n Bytes,\n Struct,\n Tuple,\n u32,\n} from \"@polkadot-api/substrate-bindings\";\nimport {\n Binary,\n CompatibilityLevel,\n Enum,\n type HexString,\n type PolkadotClient,\n} from \"polkadot-api\";\nimport { catchError, filter, firstValueFrom, from, map } from \"rxjs\";\nimport type { DmpMessage } from \"./block-builder/create-block\";\nimport type { Chain } from \"./chain\";\nimport { getConstant, getStorageCodecs } from \"./codecs\";\nimport { getNode, insertValue } from \"./storage\";\nimport { logger } from \"./logger\";\n\nconst log = logger.child({ module: \"xcm\" });\n\n/**\n * Attaches the current forklift as a parachain to a forklift relay chain.\n */\nexport const attachRelay = async (\n relayClient: PolkadotClient,\n parachainClient: PolkadotClient,\n chain: Chain,\n xcm: {\n pushDmp: (messages: Array<DmpMessage>) => void;\n }\n) => {\n const paraId: number | null = await getConstant(\n chain.getBlock(await firstValueFrom(chain.finalized$))!,\n \"ParachainSystem\",\n \"SelfParaId\"\n );\n if (paraId == null) {\n throw new Error(\"Could not get parachain ID\");\n }\n\n const typedApi = relayClient.getTypedApi(relay);\n const staticApis = await typedApi.getStaticApis();\n if (\n !staticApis.compat.query.Dmp.DownwardMessageQueues.isCompatible(\n CompatibilityLevel.Partial\n )\n ) {\n throw new Error(\"Dmp queue incompatible\");\n }\n\n const parachainApi = parachainClient.getTypedApi(parachain);\n if (\n !(\n await parachainApi.getStaticApis()\n ).compat.query.ParachainSystem.UpwardMessages.isCompatible(\n CompatibilityLevel.Partial\n )\n ) {\n throw new Error(\"UpwardMessageQueue incompatible\");\n }\n\n log.debug(\"watching dmp queue\");\n let lastSentAt = 0;\n typedApi.query.Dmp.DownwardMessageQueues.watchValue(paraId)\n .pipe(\n map(({ block, value }) => ({\n block,\n messages: value.filter((v) => v.sent_at > lastSentAt),\n })),\n filter(({ messages }) => messages.length > 0)\n )\n .subscribe(({ block, messages }) => {\n relayClient._request(\"forklift_xcm_consume_dmp\", [block.hash, paraId]);\n lastSentAt = messages\n .map((m) => m.sent_at)\n .reduce((a, b) => Math.max(a, b));\n\n xcm.pushDmp(messages);\n });\n\n log.debug(\"watching ump queue\");\n parachainClient.finalizedBlock$\n .pipe(\n concatMapEager((block) =>\n from(\n parachainApi.query.ParachainSystem.UpwardMessages.getValue({\n at: block.hash,\n })\n ).pipe(\n catchError((ex) => {\n log.error(ex, \"error reading upward messages\");\n return [];\n })\n )\n )\n )\n .subscribe((messages) => {\n relayClient._request(\"forklift_xcm_push_ump\", [\n paraId,\n messages.map(Binary.toHex),\n ]);\n });\n};\n\n/**\n * Consume DMP messages for a specific parachain.\n *\n * As we don't have a real ParaInherent.enter inherent, we need to clear them manually.\n * Here we mutate the state of the target block and descendants to remove the messages.\n * Another option would be to keep the messages in a \"blacklist\" so that the queue is cleared out\n * when building a new block, but knowing when to clear the blacklist is not trivial.\n */\nexport const consumeDmp = async (\n chain: Chain,\n hash: HexString,\n paraId: number\n) => {\n const blocks = await firstValueFrom(chain.blocks$);\n const targetBlock = blocks[hash];\n if (!targetBlock) {\n throw new Error(\"Block not found\");\n }\n\n const codecs = await getStorageCodecs(\n targetBlock,\n \"Dmp\",\n \"DownwardMessageQueues\"\n );\n if (!codecs) {\n throw new Error(\"Dmp.DownwardMessageQueues not found\");\n }\n\n const dmqKey = codecs.keys.enc(paraId);\n const dmqBinKey = Binary.fromHex(dmqKey);\n const targetDmqNode = await chain.getStorage(hash, dmqKey);\n const targetDmq: Array<DmpMessage> = targetDmqNode.value\n ? codecs.value.dec(targetDmqNode.value)\n : [];\n\n if (targetDmq.length === 0) return;\n\n const getDmpMessageKey = (msg: DmpMessage) =>\n `${msg.sent_at}_${Binary.toHex(msg.msg)}`;\n const targetDmqKeys = new Set(targetDmq.map(getDmpMessageKey));\n\n let blocksToUpdate = [hash];\n while (blocksToUpdate.length) {\n const hash = blocksToUpdate.pop()!;\n const block = blocks[hash]!;\n blocksToUpdate = [...block.children, ...blocksToUpdate];\n\n // If it doesn't have a value in the local node, it means it had the same value as all of its parents.\n // And one of those parents is the target that we're removing all the dmq messages from,\n // which means will end up in `[]` anyway\n const childDmqNode = getNode(\n block.storageRoot,\n dmqBinKey,\n dmqBinKey.length * 2\n );\n\n const childDmq: Array<DmpMessage> = childDmqNode?.value\n ? codecs.value.dec(childDmqNode.value)\n : [];\n\n const newChildDmq = childDmq.filter(\n (v) => !targetDmqKeys.has(getDmpMessageKey(v))\n );\n\n block.storageRoot = insertValue(\n block.storageRoot,\n dmqBinKey,\n dmqBinKey.length * 2,\n codecs.value.enc(newChildDmq)\n );\n }\n\n log.info({ paraId, count: targetDmq.length }, \"cleared DMP messages\");\n};\n\nexport const pushUmp = async (\n chain: Chain,\n paraId: number,\n messages: Array<Uint8Array>\n) => {\n if (messages.length === 0) return;\n\n const finalizedHash = await firstValueFrom(chain.finalized$);\n const blocks = await firstValueFrom(chain.blocks$);\n const finalizedBlock = blocks[finalizedHash];\n if (!finalizedBlock) throw new Error(\" lock not found\");\n\n const [pageCodecs, bookCodecs, serviceHeadCodecs] = await Promise.all([\n getStorageCodecs(finalizedBlock, \"MessageQueue\", \"Pages\"),\n getStorageCodecs(finalizedBlock, \"MessageQueue\", \"BookStateFor\"),\n getStorageCodecs(finalizedBlock, \"MessageQueue\", \"ServiceHead\"),\n ]);\n if (!(serviceHeadCodecs && bookCodecs && pageCodecs))\n throw new Error(\"MessageQueue codecs not found\");\n\n const totalMsgSize = messages.reduce((acc, p) => acc + p.length, 0);\n const lastOffset = messages\n .slice(0, -1)\n .reduce((acc, msg) => acc + 5 + msg.length, 0);\n const heap = heapEncoder(messages);\n\n const origin = Enum(\"Ump\", Enum(\"Para\", paraId));\n const bookBinKey = Binary.fromHex(bookCodecs.keys.enc(origin));\n const serviceHeadBinKey = Binary.fromHex(serviceHeadCodecs.keys.enc());\n\n // Apply updates to finalized block and all its descendants.\n // For each block, read the local trie state (via getNode) so that we append to whatever\n // messages are already there rather than overwriting them.\n let blocksToUpdate = [finalizedHash];\n while (blocksToUpdate.length) {\n const hash = blocksToUpdate.pop()!;\n const block = blocks[hash]!;\n blocksToUpdate = [...block.children, ...blocksToUpdate];\n\n const existingBookNode = getNode(\n block.storageRoot,\n bookBinKey,\n bookBinKey.length * 2\n );\n const existingBook = existingBookNode?.value\n ? bookCodecs.value.dec(existingBookNode.value)\n : null;\n\n const wasEmpty = !existingBook || existingBook.begin === existingBook.end;\n const pageIndex: number = existingBook ? existingBook.end : 0;\n const pageBinKey = Binary.fromHex(pageCodecs.keys.enc(origin, pageIndex));\n\n const newBook = {\n begin: existingBook?.begin ?? 0,\n end: pageIndex + 1,\n count: (existingBook?.count ?? 0) + 1,\n ready_neighbours: existingBook?.ready_neighbours ?? undefined,\n message_count:\n (existingBook?.message_count ?? 0n) + BigInt(messages.length),\n size: (existingBook?.size ?? 0n) + BigInt(totalMsgSize),\n };\n\n const page = {\n remaining: messages.length,\n remaining_size: totalMsgSize,\n first_index: 0,\n first: 0,\n last: lastOffset,\n heap,\n };\n\n block.storageRoot = insertValue(\n block.storageRoot,\n pageBinKey,\n pageBinKey.length * 2,\n pageCodecs.value.enc(page)\n );\n\n // If the book was empty, jump the queue by making origin the new ServiceHead.\n if (wasEmpty) {\n const serviceHeadNode = getNode(\n block.storageRoot,\n serviceHeadBinKey,\n serviceHeadBinKey.length * 2\n );\n const existingServiceHead = serviceHeadNode?.value\n ? serviceHeadCodecs.value.dec(serviceHeadNode.value)\n : null;\n\n if (existingServiceHead) {\n // Point origin forward into the existing ring, and fix the old head's prev pointer\n newBook.ready_neighbours = { prev: origin, next: existingServiceHead };\n const existingHeadBookBinKey = Binary.fromHex(\n bookCodecs.keys.enc(existingServiceHead)\n );\n const existingHeadBookNode = getNode(\n block.storageRoot,\n existingHeadBookBinKey,\n existingHeadBookBinKey.length * 2\n );\n const existingHeadBook = existingHeadBookNode?.value\n ? bookCodecs.value.dec(existingHeadBookNode.value)\n : null;\n if (existingHeadBook?.ready_neighbours) {\n existingHeadBook.ready_neighbours.prev = origin;\n block.storageRoot = insertValue(\n block.storageRoot,\n existingHeadBookBinKey,\n existingHeadBookBinKey.length * 2,\n bookCodecs.value.enc(existingHeadBook)\n );\n }\n } else {\n newBook.ready_neighbours = { prev: origin, next: origin };\n }\n\n block.storageRoot = insertValue(\n block.storageRoot,\n serviceHeadBinKey,\n serviceHeadBinKey.length * 2,\n serviceHeadCodecs.value.enc(origin)\n );\n }\n\n block.storageRoot = insertValue(\n block.storageRoot,\n bookBinKey,\n bookBinKey.length * 2,\n bookCodecs.value.enc(newBook)\n );\n }\n};\n\n/**\n * Attaches two sibling parachains for bidirectional HRMP message passing.\n * Called on self (Para A) with the sibling's (Para B) URL.\n * Sets up:\n * - Sibling → Self: watch Para B's HrmpOutboundMessages, push to self via xcm.pushHrmp\n * - Self → Sibling: watch Para A's HrmpOutboundMessages, push to Para B via forklift_xcm_push_hrmp\n */\nexport const attachSibling = async (\n siblingClient: PolkadotClient,\n selfClient: PolkadotClient,\n chain: Chain,\n xcm: { pushHrmp: (senderId: number, messages: Uint8Array[]) => void }\n) => {\n const selfParaId: number | null = await getConstant(\n chain.getBlock(await firstValueFrom(chain.finalized$))!,\n \"ParachainSystem\",\n \"SelfParaId\"\n );\n if (selfParaId == null) throw new Error(\"Could not get self parachain ID\");\n\n const siblingApi = siblingClient.getTypedApi(parachain);\n const selfApi = selfClient.getTypedApi(parachain);\n\n const staticApis = await siblingApi.getStaticApis();\n if (\n !staticApis.compat.query.ParachainSystem.HrmpOutboundMessages.isCompatible(\n CompatibilityLevel.Partial\n )\n ) {\n throw new Error(\"HrmpOutboundMessages incompatible\");\n }\n\n const siblingParaId: number =\n await siblingApi.constants.ParachainSystem.SelfParaId();\n log.info({ selfParaId, siblingParaId }, \"attaching HRMP channel\");\n\n // Open egress channels on both sides so each chain's relay proof includes the channel.\n chain.openHrmpChannel(siblingParaId);\n siblingClient._request(\"forklift_xcm_open_hrmp_channel\", [selfParaId]);\n\n // Sibling → Self: watch Para B outbound, push messages destined for self\n siblingClient.finalizedBlock$\n .pipe(\n concatMapEager((block) =>\n from(\n siblingApi.query.ParachainSystem.HrmpOutboundMessages.getValue({\n at: block.hash,\n })\n ).pipe(\n catchError((ex) => {\n log.error(ex, \"error reading sibling HRMP outbound messages\");\n return [];\n })\n )\n )\n )\n .subscribe((messages) => {\n const forSelf = messages.filter((m) => m.recipient === selfParaId);\n if (forSelf.length > 0) {\n xcm.pushHrmp(\n siblingParaId,\n forSelf.map((m) => m.data)\n );\n }\n });\n\n // Self → Sibling: watch Para A outbound, push messages destined for sibling\n selfClient.finalizedBlock$\n .pipe(\n concatMapEager((block) =>\n from(\n selfApi.query.ParachainSystem.HrmpOutboundMessages.getValue({\n at: block.hash,\n })\n ).pipe(\n catchError((ex) => {\n log.error(ex, \"error reading self HRMP outbound messages\");\n return [];\n })\n )\n )\n )\n .subscribe((messages) => {\n const forSibling = messages.filter((m) => m.recipient === siblingParaId);\n if (forSibling.length > 0) {\n siblingClient._request(\"forklift_xcm_push_hrmp\", [\n selfParaId,\n forSibling.map((m) => Binary.toHex(m.data)),\n ]);\n }\n });\n};\n\nconst heapEncoder = (value: Uint8Array[]) =>\n Tuple(\n ...value.map((coded) =>\n Struct({\n length: u32,\n is_processed: bool,\n payload: Bytes(coded.length),\n })\n )\n ).enc(\n value.map((payload) => ({\n length: payload.length,\n is_processed: false,\n payload,\n }))\n );\n"],"names":["relay","parachain","hash"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@polkadot-api/forklift",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/polkadot-api/papi-sdks.git"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"module": "./dist/src/index.js",
|
|
13
|
+
"import": "./dist/src/index.js",
|
|
14
|
+
"default": "./dist/src/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"main": "./dist/src/index.js",
|
|
18
|
+
"module": "./dist/src/index.js",
|
|
19
|
+
"browser": "./dist/src/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"bin"
|
|
24
|
+
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"forklift": "./bin/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "papi generate && tsc --noEmit && rollup -c"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@polkadot-labs/hdkd": "^0.0.27",
|
|
33
|
+
"@polkadot-labs/hdkd-helpers": "^0.0.28",
|
|
34
|
+
"@types/bun": "^1.3.11",
|
|
35
|
+
"rollup-plugin-dts": "^6.4.1",
|
|
36
|
+
"rollup-plugin-esbuild": "^6.2.1"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"typescript": "^5"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@acala-network/chopsticks-executor": "^1.3.0",
|
|
43
|
+
"@polkadot-api/descriptors": "file:.papi/descriptors",
|
|
44
|
+
"@polkadot-api/metadata-builders": "^0.13.11",
|
|
45
|
+
"@polkadot-api/observable-client": "^0.18.3",
|
|
46
|
+
"@polkadot-api/substrate-bindings": "^0.19.0",
|
|
47
|
+
"@polkadot-api/substrate-client": "^0.7.0",
|
|
48
|
+
"@polkadot-api/tx-utils": "^0.2.5",
|
|
49
|
+
"@polkadot-api/ws-middleware": "^0.3.0",
|
|
50
|
+
"@polkadot-api/ws-provider": "^0.9.0",
|
|
51
|
+
"@react-rxjs/utils": "^0.9.7",
|
|
52
|
+
"@types/ws": "^8.18.1",
|
|
53
|
+
"commander": "^14.0.3",
|
|
54
|
+
"pino": "^10.3.1",
|
|
55
|
+
"pino-pretty": "^13.1.3",
|
|
56
|
+
"polkadot-api": "2.0.0",
|
|
57
|
+
"rxjs": "^7.8.2",
|
|
58
|
+
"ws": "^8.20.0",
|
|
59
|
+
"yaml": "^2.8.3"
|
|
60
|
+
}
|
|
61
|
+
}
|