@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 @@
|
|
|
1
|
+
{"version":3,"file":"set-validation-data.js","sources":["../../../src/block-builder/set-validation-data.ts"],"sourcesContent":["import { create_proof, decode_proof } from \"@acala-network/chopsticks-executor\";\nimport {\n Blake2256,\n Bytes,\n Option,\n Struct,\n Twox128,\n Twox64Concat,\n Vector,\n blockHeader,\n compact,\n u32,\n u64,\n} from \"@polkadot-api/substrate-bindings\";\nimport { Binary, type HexString } from \"polkadot-api\";\nimport { mergeUint8 } from \"polkadot-api/utils\";\nimport type { Chain } from \"../chain\";\nimport {\n getCallData,\n getConstant,\n getExtrinsicDecoder,\n getTxCodec,\n unsignedExtrinsic,\n} from \"../codecs\";\nimport type { Block, XcmMessages } from \"./create-block\";\nimport {\n getCurrentSlot,\n getSlotDuration,\n runtimeBlockHeader,\n type RuntimeBlockHeader,\n} from \"./slot-utils\";\n\nconst textEncoder = new TextEncoder();\nconst RELAY_CHAIN_SLOT_DURATION_MILLIS = 6_000n;\n\n// Compute a Substrate storage key: twox128(pallet) ++ twox128(storage)\nconst storagePrefix = (pallet: string, storage: string): HexString =>\n Binary.toHex(\n mergeUint8([\n Twox128(textEncoder.encode(pallet)),\n Twox128(textEncoder.encode(storage)),\n ])\n ) as HexString;\n\nconst DMP_QUEUE_HEADS_KEY = storagePrefix(\"Dmp\", \"DownwardMessageQueueHeads\");\nconst HRMP_INGRESS_INDEX_KEY = storagePrefix(\n \"Hrmp\",\n \"HrmpIngressChannelsIndex\"\n);\nconst HRMP_EGRESS_INDEX_KEY = storagePrefix(\"Hrmp\", \"HrmpEgressChannelsIndex\");\nconst HRMP_CHANNELS_KEY = storagePrefix(\"Hrmp\", \"HrmpChannels\");\n\nconst appendParaId = (key: HexString, paraId: number) =>\n Binary.toHex(\n mergeUint8([Binary.fromHex(key), Twox64Concat(u32.enc(paraId))])\n ) as HexString;\n\nconst hrmpIngressIndexKey = (receiverParaId: number): HexString =>\n appendParaId(HRMP_INGRESS_INDEX_KEY, receiverParaId);\n\nconst hrmpEgressIndexKey = (senderParaId: number): HexString =>\n appendParaId(HRMP_EGRESS_INDEX_KEY, senderParaId);\n\nconst hrmpChannelKey = (sender: number, receiver: number): HexString =>\n Binary.toHex(\n mergeUint8([\n Binary.fromHex(HRMP_CHANNELS_KEY),\n Twox64Concat(mergeUint8([u32.enc(sender), u32.enc(receiver)])),\n ])\n ) as HexString;\n\nconst DEFAULT_CHANNEL = {\n max_capacity: 1000,\n max_total_size: 102400,\n max_message_size: 102400,\n msg_count: 0,\n total_size: 0,\n mqc_head: undefined as Uint8Array | undefined,\n};\n\nconst BABE_CURRENT_SLOT_KEY = storagePrefix(\"Babe\", \"CurrentSlot\");\n\n// Well-known relay chain storage keys that must be preserved in the proof.\n// These are required for the parachain runtime to verify relay chain state.\n// Keys are computed from pallet/storage names per Substrate storage conventions.\nconst PRESERVE_PROOFS = [\n storagePrefix(\"Babe\", \"EpochIndex\"),\n storagePrefix(\"Babe\", \"CurrentBlockRandomness\"),\n storagePrefix(\"Babe\", \"Randomness\"),\n storagePrefix(\"Babe\", \"NextRandomness\"),\n BABE_CURRENT_SLOT_KEY,\n storagePrefix(\"Configuration\", \"ActiveConfig\"),\n storagePrefix(\"Babe\", \"Authorities\"),\n];\n\n// Storage key prefix for Paras::Heads(paraId) on the relay chain\nconst PARAS_HEADS_PREFIX = Binary.fromHex(storagePrefix(\"Paras\", \"Heads\"));\n\n// Compute the full storage key: prefix ++ twox64Concat(paraId)\nconst paraHeadKey = (paraId: number): Uint8Array => {\n const paraIdBytes = u32.enc(paraId);\n return mergeUint8([PARAS_HEADS_PREFIX, Twox64Concat(paraIdBytes)]);\n};\n\n// Encode HeadData (Vec<u8> wrapper around encoded header)\nconst encodeHeadData = (header: Uint8Array): Uint8Array => {\n return mergeUint8([compact.enc(header.length), header]);\n};\n\nexport const setValidationDataInherent = async (\n chain: Chain,\n parentBlock: Block,\n xcm: XcmMessages\n) => {\n if (\n !parentBlock.header.digests.some(\n (d) => d.type === \"preRuntime\" && d.value.engine === \"aura\"\n )\n )\n return null;\n\n const txCodec = getTxCodec(\n parentBlock,\n \"ParachainSystem\",\n \"set_validation_data\"\n );\n if (!txCodec) return null;\n\n const txDec = await getExtrinsicDecoder(parentBlock);\n const prevValidationDataRaw = parentBlock.body.find((raw) => {\n const ext = txDec(raw);\n return (\n ext.call.type === \"ParachainSystem\" &&\n ext.call.value.type === \"set_validation_data\"\n );\n });\n const prevValidationDataExt =\n prevValidationDataRaw && txDec(prevValidationDataRaw);\n const prevValidationData = prevValidationDataExt?.call.value.value.data;\n\n if (!prevValidationData) {\n throw new Error(\"TODO no prevValidationData in previous block\");\n }\n\n // Get parachain ID from runtime constant\n const paraId: number | null = await getConstant(\n parentBlock,\n \"ParachainSystem\",\n \"SelfParaId\"\n );\n if (paraId == null) {\n throw new Error(\"Could not get parachain ID\");\n }\n\n // Encode the parent block header as HeadData to inject into relay chain proof\n const encodedParentHeader = blockHeader.enc(parentBlock.header);\n const headData = encodeHeadData(encodedParentHeader);\n const storageKey = paraHeadKey(paraId);\n\n // Get the existing relay chain state proof\n const existingNodes = (\n prevValidationData.relay_chain_state as Uint8Array[]\n ).map((node) => Binary.toHex(node));\n const existingStateRoot =\n prevValidationData.validation_data.relay_parent_storage_root;\n\n // Decode the existing proof to extract current values\n // Returns array of [key, value] pairs\n const decodedProofArray = (await decode_proof(\n existingStateRoot,\n existingNodes\n )) as [HexString, HexString | null][];\n\n // Convert to a Map for easy lookup\n const decodedProof = new Map(decodedProofArray);\n\n const slotDuration = await getSlotDuration(chain, parentBlock);\n const relaySlotIncreaseRaw = slotDuration / RELAY_CHAIN_SLOT_DURATION_MILLIS;\n const relaySlotIncrease =\n relaySlotIncreaseRaw > 0n ? relaySlotIncreaseRaw : 1n;\n\n const relayCurrentSlot = await (async () => {\n const currentSlotHex = decodedProof.get(BABE_CURRENT_SLOT_KEY);\n if (typeof currentSlotHex === \"string\") {\n return u64.dec(Binary.fromHex(currentSlotHex));\n }\n\n const currentSlot = await getCurrentSlot(chain, parentBlock);\n return currentSlot * relaySlotIncrease;\n })();\n\n const nextRelayChainSlot = Binary.toHex(\n u64.enc(relayCurrentSlot + relaySlotIncrease)\n ) as HexString;\n\n // Build new entries: preserve all PRESERVE_PROOFS + add paraHead\n const newEntries: [HexString, HexString | null][] = [];\n\n // Preserve all well-known relay chain storage entries (including AUTHORITIES)\n for (const key of PRESERVE_PROOFS) {\n if (decodedProof.has(key)) {\n const value =\n key === BABE_CURRENT_SLOT_KEY && nextRelayChainSlot\n ? nextRelayChainSlot\n : decodedProof.get(key) ?? null;\n newEntries.push([key as HexString, value]);\n }\n }\n\n // Add the parachain head entry (this signals inclusion of parent block)\n newEntries.push([\n Binary.toHex(storageKey) as HexString,\n Binary.toHex(headData) as HexString,\n ]);\n\n const dmpHashKey = appendParaId(DMP_QUEUE_HEADS_KEY, paraId);\n let dmpHash = Binary.fromHex(\n decodedProof.get(dmpHashKey) ??\n \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n );\n for (const { msg, sent_at } of xcm.dmp) {\n dmpHash = Blake2256(\n mqcChain.enc({\n hash: dmpHash,\n sent_at,\n msg_hash: Blake2256(Binary.toOpaque(msg)),\n })\n );\n }\n newEntries.push([dmpHashKey, Binary.toHex(dmpHash)]);\n\n // Preserve existing HRMP egress channel entries from the original proof, and inject\n // any manually registered channels. The runtime checks these to know which outbound\n // channels are open before queuing messages.\n const egressIndexHex = decodedProof.get(hrmpEgressIndexKey(paraId));\n const existingEgressRecipients = egressIndexHex\n ? vecU32.dec(Binary.fromHex(egressIndexHex))\n : [];\n const allEgressRecipients = [\n ...new Set([...existingEgressRecipients, ...chain.hrmpChannels]),\n ].sort((a, b) => a - b);\n\n if (allEgressRecipients.length > 0) {\n newEntries.push([\n hrmpEgressIndexKey(paraId),\n Binary.toHex(vecU32.enc(allEgressRecipients)),\n ]);\n\n for (const recipientId of allEgressRecipients) {\n const chKey = hrmpChannelKey(paraId, recipientId);\n\n const existingHex = decodedProof.get(chKey);\n if (existingHex) {\n newEntries.push([chKey, existingHex]);\n } else {\n newEntries.push([\n chKey,\n Binary.toHex(AbridgedHrmpChannelCodec.enc(DEFAULT_CHANNEL)),\n ]);\n }\n }\n }\n\n const nextRelayNumber =\n Number(prevValidationData.validation_data.relay_parent_number) +\n Number(relaySlotIncrease);\n\n const ingressIndexHex = decodedProof.get(hrmpIngressIndexKey(paraId));\n const existingIngressRecipients = ingressIndexHex\n ? vecU32.dec(Binary.fromHex(ingressIndexHex))\n : [];\n const allIngressSenders = [\n ...new Set([...existingIngressRecipients, ...chain.hrmpChannels]),\n ].sort((a, b) => a - b);\n\n if (allIngressSenders.length > 0)\n newEntries.push([\n hrmpIngressIndexKey(paraId),\n Binary.toHex(vecU32.enc(allIngressSenders)),\n ]);\n\n // Update HrmpChannels for each sender: compute new MQC head\n for (const senderId of allIngressSenders) {\n const chKey = hrmpChannelKey(senderId, paraId);\n const existingHex = decodedProof.get(chKey);\n const ch = existingHex\n ? AbridgedHrmpChannelCodec.dec(existingHex)\n : { ...DEFAULT_CHANNEL };\n\n const hrmpMessages = xcm.hrmp[senderId];\n\n if (hrmpMessages) {\n let mqcHead = ch.mqc_head ?? new Uint8Array(32);\n let totalSize = ch.total_size;\n for (const data of hrmpMessages) {\n mqcHead = Blake2256(\n mqcChain.enc({\n hash: mqcHead,\n sent_at: nextRelayNumber,\n msg_hash: Blake2256(Binary.toOpaque(data)),\n })\n );\n totalSize += data.length;\n }\n newEntries.push([\n chKey,\n Binary.toHex(\n AbridgedHrmpChannelCodec.enc({\n ...ch,\n msg_count: ch.msg_count + hrmpMessages.length,\n total_size: totalSize,\n mqc_head: mqcHead,\n })\n ),\n ]);\n } else {\n newEntries.push([chKey, Binary.toHex(AbridgedHrmpChannelCodec.enc(ch))]);\n }\n }\n\n // Create updated proof with all entries\n const [newStateRoot, newNodes]: [HexString, HexString[]] = await create_proof(\n existingNodes,\n newEntries\n );\n\n // Keep relay_parent_descendants aligned with the new relay parent number.\n const originalDescendants: Array<RuntimeBlockHeader> =\n prevValidationData.relay_parent_descendants ?? [];\n\n // Update relay_parent_descendants:\n // 1. First descendant's state_root must match our new relay_parent_storage_root\n // 2. Each subsequent descendant's parentHash must be the hash of the previous header\n const updatedDescendants: Array<RuntimeBlockHeader> = [];\n let lastHeaderHash: HexString | undefined;\n let nextDescNumber =\n Number(prevValidationData.validation_data.relay_parent_number) +\n Number(relaySlotIncrease);\n\n for (let i = 0; i < originalDescendants.length; i++) {\n const desc = originalDescendants[i]!;\n\n // Build updated header\n const updatedDesc = {\n ...desc,\n // Update state_root for the first descendant\n state_root: i === 0 ? newStateRoot : desc.state_root,\n // Update parentHash to point to the modified previous header\n parent_hash: lastHeaderHash ?? desc.parent_hash,\n // Align descendant numbers with the new relay_parent_number\n number: nextDescNumber,\n };\n\n updatedDescendants.push(updatedDesc);\n nextDescNumber += 1;\n\n const encoded = runtimeBlockHeader.enc(updatedDesc);\n lastHeaderHash = Binary.toHex(Blake2256(encoded));\n }\n\n const data = {\n ...prevValidationData,\n validation_data: {\n ...prevValidationData.validation_data,\n relay_parent_number: nextRelayNumber,\n relay_parent_storage_root: newStateRoot,\n },\n relay_chain_state: newNodes.map((node) => Binary.fromHex(node)),\n relay_parent_descendants: updatedDescendants,\n };\n\n const inbound_messages_data = {\n downward_messages: {\n full_messages: xcm.dmp,\n hashed_messages: [],\n },\n horizontal_messages: {\n full_messages: allIngressSenders.flatMap((senderId) =>\n (xcm.hrmp[senderId] ?? []).map((data) => [\n senderId,\n {\n sent_at: nextRelayNumber,\n data,\n },\n ])\n ),\n hashed_messages: [],\n },\n };\n\n const callData = await getCallData(\n parentBlock,\n \"ParachainSystem\",\n \"set_validation_data\",\n {\n data,\n inbound_messages_data,\n }\n );\n return unsignedExtrinsic(callData!);\n};\n\nconst mqcChain = Struct({\n hash: Bytes(32),\n sent_at: u32,\n msg_hash: Bytes(32),\n});\n\nconst vecU32 = Vector(u32);\nconst AbridgedHrmpChannelCodec = Struct({\n max_capacity: u32,\n max_total_size: u32,\n max_message_size: u32,\n msg_count: u32,\n total_size: u32,\n mqc_head: Option(Bytes(32)),\n});\n"],"names":["data"],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Tuple, Hex, Bytes, Variant, _void, Struct, compactNumber, Vector, u64 } from '@polkadot-api/substrate-bindings';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
import { getConstant, getStorageCodecs } from '../codecs.js';
|
|
4
|
+
import { runRuntimeCall } from '../executor.js';
|
|
5
|
+
|
|
6
|
+
const log = logger.child({ module: "slot-utils" });
|
|
7
|
+
const getSlotDuration = async (chain, block) => {
|
|
8
|
+
const babe = await getConstant(block, "Babe", "ExpectedBlockTime");
|
|
9
|
+
if (babe) return BigInt(babe);
|
|
10
|
+
const async = await getConstant(block, "AsyncBacking", "ExpectedBlockTime");
|
|
11
|
+
if (async) return BigInt(async);
|
|
12
|
+
return getAuraSlotDuration(chain, block);
|
|
13
|
+
};
|
|
14
|
+
const getCurrentTimestamp = async (chain, block) => {
|
|
15
|
+
const codecs = await getStorageCodecs(block, "Timestamp", "Now");
|
|
16
|
+
if (!codecs) {
|
|
17
|
+
throw new Error("No Timestamp.Now");
|
|
18
|
+
}
|
|
19
|
+
const node = await chain.getStorage(block.hash, codecs.keys.enc());
|
|
20
|
+
if (node.value != null) {
|
|
21
|
+
const decoded = codecs.value.dec(node.value);
|
|
22
|
+
return typeof decoded === "bigint" ? decoded : BigInt(decoded);
|
|
23
|
+
}
|
|
24
|
+
const fallback = codecs.fallback ?? BigInt(Date.now());
|
|
25
|
+
return typeof fallback === "bigint" ? fallback : BigInt(fallback);
|
|
26
|
+
};
|
|
27
|
+
const getCurrentSlot = async (chain, block) => {
|
|
28
|
+
const [timestamp, slotDuration] = await Promise.all([
|
|
29
|
+
getCurrentTimestamp(chain, block),
|
|
30
|
+
getSlotDuration(chain, block)
|
|
31
|
+
]);
|
|
32
|
+
return timestamp / slotDuration;
|
|
33
|
+
};
|
|
34
|
+
const getAuraSlotDuration = async (chain, block) => {
|
|
35
|
+
try {
|
|
36
|
+
const { result } = await runRuntimeCall({
|
|
37
|
+
chain,
|
|
38
|
+
hash: block.hash,
|
|
39
|
+
call: "AuraApi_slot_duration",
|
|
40
|
+
params: "0x"
|
|
41
|
+
});
|
|
42
|
+
return u64.dec(result);
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
log.error("couldn't get aura slot duration, defaulting to 12s");
|
|
46
|
+
return 12000n;
|
|
47
|
+
};
|
|
48
|
+
const digestVal = Tuple(Hex(4), Bytes());
|
|
49
|
+
const digest = Variant(
|
|
50
|
+
{
|
|
51
|
+
Other: Bytes(),
|
|
52
|
+
Consensus: digestVal,
|
|
53
|
+
Seal: digestVal,
|
|
54
|
+
PreRuntime: digestVal,
|
|
55
|
+
RuntimeEnvironmentUpdated: _void
|
|
56
|
+
},
|
|
57
|
+
[0, 4, 5, 6, 8]
|
|
58
|
+
);
|
|
59
|
+
const runtimeBlockHeader = Struct({
|
|
60
|
+
parent_hash: Hex(32),
|
|
61
|
+
number: compactNumber,
|
|
62
|
+
state_root: Hex(32),
|
|
63
|
+
extrinsics_root: Hex(32),
|
|
64
|
+
digest: Vector(digest)
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export { getCurrentSlot, getCurrentTimestamp, getSlotDuration, runtimeBlockHeader };
|
|
68
|
+
//# sourceMappingURL=slot-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-utils.js","sources":["../../../src/block-builder/slot-utils.ts"],"sourcesContent":["import {\n _void,\n Bytes,\n compactNumber,\n Hex,\n Struct,\n Tuple,\n u64,\n Variant,\n Vector,\n type CodecType,\n} from \"@polkadot-api/substrate-bindings\";\nimport type { Chain } from \"../chain\";\nimport { logger } from \"../logger\";\n\nconst log = logger.child({ module: \"slot-utils\" });\nimport { getConstant, getStorageCodecs } from \"../codecs\";\nimport { runRuntimeCall } from \"../executor\";\nimport type { Block } from \"./create-block\";\n\nexport const getSlotDuration = async (chain: Chain, block: Block) => {\n const babe = await getConstant(block, \"Babe\", \"ExpectedBlockTime\");\n if (babe) return BigInt(babe);\n\n const async = await getConstant(block, \"AsyncBacking\", \"ExpectedBlockTime\");\n if (async) return BigInt(async);\n\n return getAuraSlotDuration(chain, block);\n};\n\nexport const getCurrentTimestamp = async (chain: Chain, block: Block) => {\n const codecs = await getStorageCodecs(block, \"Timestamp\", \"Now\");\n if (!codecs) {\n throw new Error(\"No Timestamp.Now\");\n }\n\n const node = await chain.getStorage(block.hash, codecs.keys.enc());\n if (node.value != null) {\n const decoded = codecs.value.dec(node.value);\n return typeof decoded === \"bigint\" ? decoded : BigInt(decoded);\n }\n\n const fallback = codecs.fallback ?? BigInt(Date.now());\n return typeof fallback === \"bigint\" ? fallback : BigInt(fallback);\n};\n\nexport const getCurrentSlot = async (chain: Chain, block: Block) => {\n const [timestamp, slotDuration] = await Promise.all([\n getCurrentTimestamp(chain, block),\n getSlotDuration(chain, block),\n ]);\n\n return timestamp / slotDuration;\n};\n\nconst getAuraSlotDuration = async (chain: Chain, block: Block) => {\n try {\n const { result } = await runRuntimeCall({\n chain,\n hash: block.hash,\n call: \"AuraApi_slot_duration\",\n params: \"0x\",\n });\n\n return u64.dec(result);\n } catch {}\n\n log.error(\"couldn't get aura slot duration, defaulting to 12s\");\n return 12_000n;\n};\n\nconst digestVal = Tuple(Hex(4), Bytes());\n\nconst digest = Variant(\n {\n Other: Bytes(),\n Consensus: digestVal,\n Seal: digestVal,\n PreRuntime: digestVal,\n RuntimeEnvironmentUpdated: _void,\n },\n [0, 4, 5, 6, 8]\n);\n\nexport const runtimeBlockHeader = Struct({\n parent_hash: Hex(32),\n number: compactNumber,\n state_root: Hex(32),\n extrinsics_root: Hex(32),\n digest: Vector(digest),\n});\nexport type RuntimeBlockHeader = CodecType<typeof runtimeBlockHeader>;\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getCallData, unsignedExtrinsic } from '../codecs.js';
|
|
2
|
+
import { getSlotDuration, getCurrentTimestamp } from './slot-utils.js';
|
|
3
|
+
|
|
4
|
+
const timestampInherent = async (chain, parentBlock) => {
|
|
5
|
+
const now = await getNextTimestamp(chain, parentBlock);
|
|
6
|
+
const callData = await getCallData(parentBlock, "Timestamp", "set", {
|
|
7
|
+
now
|
|
8
|
+
});
|
|
9
|
+
return callData && unsignedExtrinsic(callData);
|
|
10
|
+
};
|
|
11
|
+
const getNextTimestamp = async (chain, block) => {
|
|
12
|
+
const [slotDuration, timestamp] = await Promise.all([
|
|
13
|
+
getSlotDuration(chain, block),
|
|
14
|
+
getCurrentTimestamp(chain, block)
|
|
15
|
+
]);
|
|
16
|
+
return timestamp + slotDuration;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { timestampInherent };
|
|
20
|
+
//# sourceMappingURL=timestamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timestamp.js","sources":["../../../src/block-builder/timestamp.ts"],"sourcesContent":["import type { Chain } from \"../chain\";\nimport { getCallData, unsignedExtrinsic } from \"../codecs\";\nimport type { Block } from \"./create-block\";\nimport { getCurrentTimestamp, getSlotDuration } from \"./slot-utils\";\n\nexport const timestampInherent = async (chain: Chain, parentBlock: Block) => {\n const now = await getNextTimestamp(chain, parentBlock);\n\n const callData = await getCallData(parentBlock, \"Timestamp\", \"set\", {\n now,\n });\n return callData && unsignedExtrinsic(callData);\n};\n\nconst getNextTimestamp = async (chain: Chain, block: Block) => {\n const [slotDuration, timestamp] = await Promise.all([\n getSlotDuration(chain, block),\n getCurrentTimestamp(chain, block),\n ]);\n return timestamp + slotDuration;\n};\n"],"names":[],"mappings":";;;AAKO,MAAM,iBAAA,GAAoB,OAAO,KAAA,EAAc,WAAA,KAAuB;AAC3E,EAAA,MAAM,GAAA,GAAM,MAAM,gBAAA,CAAiB,KAAA,EAAO,WAAW,CAAA;AAErD,EAAA,MAAM,QAAA,GAAW,MAAM,WAAA,CAAY,WAAA,EAAa,aAAa,KAAA,EAAO;AAAA,IAClE;AAAA,GACD,CAAA;AACD,EAAA,OAAO,QAAA,IAAY,kBAAkB,QAAQ,CAAA;AAC/C;AAEA,MAAM,gBAAA,GAAmB,OAAO,KAAA,EAAc,KAAA,KAAiB;AAC7D,EAAA,MAAM,CAAC,YAAA,EAAc,SAAS,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,IAClD,eAAA,CAAgB,OAAO,KAAK,CAAA;AAAA,IAC5B,mBAAA,CAAoB,OAAO,KAAK;AAAA,GACjC,CAAA;AACD,EAAA,OAAO,SAAA,GAAY,YAAA;AACrB,CAAA;;;;"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { file } from 'bun';
|
|
2
|
+
import { Binary } from 'polkadot-api';
|
|
3
|
+
import { BehaviorSubject, Subject, filter, pairwise, withLatestFrom, map } from 'rxjs';
|
|
4
|
+
import { createBlock } from './block-builder/create-block.js';
|
|
5
|
+
import { setBlockMeta } from './codecs.js';
|
|
6
|
+
import { getRuntimeVersion } from './executor.js';
|
|
7
|
+
import { logger } from './logger.js';
|
|
8
|
+
import { insertValue, createRoot, getDiff, getDescendantNodes, getNode, forEachDescendant, getSoftDeletedDescendantKeys, deleteValue } from './storage.js';
|
|
9
|
+
|
|
10
|
+
const log = logger.child({ module: "chain" });
|
|
11
|
+
const CODE_KEY = "0x3a636f6465";
|
|
12
|
+
const createChain = (source, key) => {
|
|
13
|
+
const cacheFile = key ? `code_${key}.bin` : null;
|
|
14
|
+
const blocks$ = new BehaviorSubject({});
|
|
15
|
+
const newBlocks$ = new Subject();
|
|
16
|
+
const bestSrc$ = new BehaviorSubject(null);
|
|
17
|
+
const best$ = bestSrc$.pipe(filter((v) => v != null));
|
|
18
|
+
const finalizedSrc$ = new BehaviorSubject(null);
|
|
19
|
+
const finalized$ = finalizedSrc$.pipe(filter((v) => v != null));
|
|
20
|
+
const asyncInitialBlock = source.block.then(async (block) => {
|
|
21
|
+
log.debug("loading code");
|
|
22
|
+
const code = cacheFile && await file(cacheFile).exists() ? await file(cacheFile).bytes() : await source.getStorage(CODE_KEY);
|
|
23
|
+
if (!code) {
|
|
24
|
+
throw new Error("No runtime code found at source block");
|
|
25
|
+
}
|
|
26
|
+
if (cacheFile) file(cacheFile).write(code);
|
|
27
|
+
log.debug("code loaded, getting runtime");
|
|
28
|
+
const initialRuntime = await getRuntimeVersion(code);
|
|
29
|
+
log.debug("runtime loaded");
|
|
30
|
+
const result = {
|
|
31
|
+
hash: block.blockHash,
|
|
32
|
+
parent: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
33
|
+
header: block.header,
|
|
34
|
+
body: block.body,
|
|
35
|
+
code,
|
|
36
|
+
storageRoot: insertValue(
|
|
37
|
+
createRoot(),
|
|
38
|
+
Binary.fromHex(CODE_KEY),
|
|
39
|
+
CODE_KEY.length - 2,
|
|
40
|
+
code
|
|
41
|
+
),
|
|
42
|
+
runtime: initialRuntime,
|
|
43
|
+
children: []
|
|
44
|
+
};
|
|
45
|
+
blocks$.next({
|
|
46
|
+
[result.hash]: result
|
|
47
|
+
});
|
|
48
|
+
setBlockMeta(chain, result);
|
|
49
|
+
bestSrc$.next(result.hash);
|
|
50
|
+
finalizedSrc$.next(result.hash);
|
|
51
|
+
return result;
|
|
52
|
+
});
|
|
53
|
+
const getBlock = (hash) => blocks$.getValue()[hash];
|
|
54
|
+
const assertBlock = (hash) => {
|
|
55
|
+
const block = getBlock(hash);
|
|
56
|
+
if (!block) {
|
|
57
|
+
throw new Error(`Block not found`);
|
|
58
|
+
}
|
|
59
|
+
return block;
|
|
60
|
+
};
|
|
61
|
+
const isDescendant = (parentHash, descendantHash) => {
|
|
62
|
+
const parent = getBlock(parentHash);
|
|
63
|
+
let block = getBlock(descendantHash);
|
|
64
|
+
while (block.header.number > parent.header.number) {
|
|
65
|
+
block = getBlock(block.parent);
|
|
66
|
+
}
|
|
67
|
+
return block.hash === parent.hash;
|
|
68
|
+
};
|
|
69
|
+
const assertFinalizedDescendant = (hash) => {
|
|
70
|
+
if (!isDescendant(finalizedSrc$.getValue(), hash)) {
|
|
71
|
+
throw new Error(`Block is not a descendant of finalized`);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const changeBest = (hash) => {
|
|
75
|
+
assertBlock(hash);
|
|
76
|
+
assertFinalizedDescendant(hash);
|
|
77
|
+
bestSrc$.next(hash);
|
|
78
|
+
};
|
|
79
|
+
const changeFinalized = (hash) => {
|
|
80
|
+
assertBlock(hash);
|
|
81
|
+
assertFinalizedDescendant(hash);
|
|
82
|
+
if (!isDescendant(hash, bestSrc$.getValue())) {
|
|
83
|
+
bestSrc$.next(hash);
|
|
84
|
+
}
|
|
85
|
+
finalizedSrc$.next(hash);
|
|
86
|
+
};
|
|
87
|
+
const setStorage = (hash, changes) => {
|
|
88
|
+
const block = assertBlock(hash);
|
|
89
|
+
for (const key2 in changes) {
|
|
90
|
+
const binKey = Binary.fromHex(key2);
|
|
91
|
+
if (changes[key2]) {
|
|
92
|
+
block.storageRoot = insertValue(
|
|
93
|
+
block.storageRoot,
|
|
94
|
+
binKey,
|
|
95
|
+
binKey.length * 2,
|
|
96
|
+
changes[key2]
|
|
97
|
+
);
|
|
98
|
+
} else {
|
|
99
|
+
block.storageRoot = deleteValue(
|
|
100
|
+
block.storageRoot,
|
|
101
|
+
binKey,
|
|
102
|
+
binKey.length * 2
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const getStorage = async (hash, key2) => {
|
|
108
|
+
const initialBlock = await asyncInitialBlock;
|
|
109
|
+
const block = assertBlock(hash);
|
|
110
|
+
const binKey = Binary.fromHex(key2);
|
|
111
|
+
const node = getNode(block.storageRoot, binKey, binKey.length * 2) ?? // The initialBlock's storage might mutate as data is loaded from source
|
|
112
|
+
// and because of the immutable storage structure, newer blocks won't see that state.
|
|
113
|
+
getNode(initialBlock.storageRoot, binKey, binKey.length * 2);
|
|
114
|
+
if (node?.value !== void 0) {
|
|
115
|
+
return node;
|
|
116
|
+
}
|
|
117
|
+
const sourceResult = await source.getStorage(key2);
|
|
118
|
+
initialBlock.storageRoot = insertValue(
|
|
119
|
+
initialBlock.storageRoot,
|
|
120
|
+
binKey,
|
|
121
|
+
binKey.length * 2,
|
|
122
|
+
sourceResult
|
|
123
|
+
);
|
|
124
|
+
return getNode(initialBlock.storageRoot, binKey, binKey.length * 2);
|
|
125
|
+
};
|
|
126
|
+
const getStorageBatch = async (hash, keys) => {
|
|
127
|
+
const initialBlock = await asyncInitialBlock;
|
|
128
|
+
const block = assertBlock(hash);
|
|
129
|
+
const keysIndexed = keys.map((key2, idx) => ({ key: key2, idx }));
|
|
130
|
+
const pending = new Array();
|
|
131
|
+
const result = keysIndexed.map(({ key: key2, idx }) => {
|
|
132
|
+
const binKey = Binary.fromHex(key2);
|
|
133
|
+
const node = getNode(block.storageRoot, binKey, binKey.length * 2) ?? // The initialBlock's storage might mutate as data is loaded from source
|
|
134
|
+
// and because of the immutable storage structure, newer blocks won't see that state.
|
|
135
|
+
getNode(initialBlock.storageRoot, binKey, binKey.length * 2);
|
|
136
|
+
if (node?.value !== void 0) {
|
|
137
|
+
return node;
|
|
138
|
+
}
|
|
139
|
+
pending.push({ key: key2, idx, binKey });
|
|
140
|
+
return null;
|
|
141
|
+
});
|
|
142
|
+
const loadedResults = await source.getStorageBatch(
|
|
143
|
+
pending.map(({ key: key2 }) => key2)
|
|
144
|
+
);
|
|
145
|
+
loadedResults.forEach((res, i) => {
|
|
146
|
+
const { idx, binKey } = pending[i];
|
|
147
|
+
initialBlock.storageRoot = insertValue(
|
|
148
|
+
initialBlock.storageRoot,
|
|
149
|
+
binKey,
|
|
150
|
+
binKey.length * 2,
|
|
151
|
+
res
|
|
152
|
+
);
|
|
153
|
+
result[idx] = getNode(
|
|
154
|
+
initialBlock.storageRoot,
|
|
155
|
+
binKey,
|
|
156
|
+
binKey.length * 2
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
return result;
|
|
160
|
+
};
|
|
161
|
+
const getStorageDescendants = async (hash, prefix) => {
|
|
162
|
+
const initialBlock = await asyncInitialBlock;
|
|
163
|
+
const block = assertBlock(hash);
|
|
164
|
+
const binPrefix = Binary.fromHex(prefix);
|
|
165
|
+
const getNodeDescendants = (node) => node ? Object.fromEntries(
|
|
166
|
+
getDescendantNodes(node, binPrefix, binPrefix.length * 2).map(
|
|
167
|
+
({ key: key2, node: node2 }) => [Binary.toHex(key2), node2]
|
|
168
|
+
)
|
|
169
|
+
) : {};
|
|
170
|
+
const blockNode = getNode(
|
|
171
|
+
block.storageRoot,
|
|
172
|
+
binPrefix,
|
|
173
|
+
binPrefix.length * 2
|
|
174
|
+
);
|
|
175
|
+
if (blockNode?.exhaustive) {
|
|
176
|
+
return getNodeDescendants(blockNode);
|
|
177
|
+
}
|
|
178
|
+
let rootNode = getNode(
|
|
179
|
+
initialBlock.storageRoot,
|
|
180
|
+
binPrefix,
|
|
181
|
+
binPrefix.length * 2
|
|
182
|
+
);
|
|
183
|
+
if (!rootNode?.exhaustive) {
|
|
184
|
+
const sourceDescendants = await source.getStorageDescendants(prefix);
|
|
185
|
+
if (!Object.keys(sourceDescendants).length)
|
|
186
|
+
initialBlock.storageRoot = insertValue(
|
|
187
|
+
initialBlock.storageRoot,
|
|
188
|
+
binPrefix,
|
|
189
|
+
binPrefix.length * 2,
|
|
190
|
+
null
|
|
191
|
+
);
|
|
192
|
+
for (const key2 in sourceDescendants) {
|
|
193
|
+
const binKey = Binary.fromHex(key2);
|
|
194
|
+
initialBlock.storageRoot = insertValue(
|
|
195
|
+
initialBlock.storageRoot,
|
|
196
|
+
binKey,
|
|
197
|
+
binKey.length * 2,
|
|
198
|
+
sourceDescendants[key2]
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
rootNode = getNode(
|
|
202
|
+
initialBlock.storageRoot,
|
|
203
|
+
binPrefix,
|
|
204
|
+
binPrefix.length * 2
|
|
205
|
+
);
|
|
206
|
+
rootNode.exhaustive = true;
|
|
207
|
+
forEachDescendant(rootNode, (node) => node.exhaustive = true);
|
|
208
|
+
}
|
|
209
|
+
const deletedKeys = blockNode ? new Set(
|
|
210
|
+
getSoftDeletedDescendantKeys(
|
|
211
|
+
blockNode,
|
|
212
|
+
binPrefix,
|
|
213
|
+
binPrefix.length * 2
|
|
214
|
+
).map(Binary.toHex)
|
|
215
|
+
) : null;
|
|
216
|
+
const rootDescendants = getNodeDescendants(rootNode);
|
|
217
|
+
return {
|
|
218
|
+
...deletedKeys ? Object.fromEntries(
|
|
219
|
+
Object.entries(rootDescendants).filter(
|
|
220
|
+
([key2]) => !deletedKeys.has(key2)
|
|
221
|
+
)
|
|
222
|
+
) : rootDescendants,
|
|
223
|
+
...getNodeDescendants(blockNode)
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
const getStorageDiff = async (hash, baseHash) => {
|
|
227
|
+
const target = getBlock(hash);
|
|
228
|
+
if (!target) {
|
|
229
|
+
throw new Error(`Block not found`);
|
|
230
|
+
}
|
|
231
|
+
const base = getBlock(baseHash ?? target.parent);
|
|
232
|
+
if (!base) {
|
|
233
|
+
throw new Error(`Parent block not loaded`);
|
|
234
|
+
}
|
|
235
|
+
const diff = getDiff(
|
|
236
|
+
base.storageRoot,
|
|
237
|
+
(await asyncInitialBlock).storageRoot,
|
|
238
|
+
target.storageRoot
|
|
239
|
+
);
|
|
240
|
+
const prevs = Object.fromEntries(
|
|
241
|
+
getDescendantNodes(diff.prev, new Uint8Array(), 0).map(
|
|
242
|
+
({ key: key2, node }) => [Binary.toHex(key2), node.value]
|
|
243
|
+
)
|
|
244
|
+
);
|
|
245
|
+
const inserts = getDescendantNodes(diff.insert, new Uint8Array(), 0).map(
|
|
246
|
+
({ key: key2, node }) => [Binary.toHex(key2), node.value]
|
|
247
|
+
);
|
|
248
|
+
const deletes = diff.deleteValues.map(
|
|
249
|
+
({ key: key2 }) => [Binary.toHex(key2), null]
|
|
250
|
+
);
|
|
251
|
+
return Object.fromEntries(
|
|
252
|
+
[...inserts, ...deletes].map(([key2, value]) => [
|
|
253
|
+
key2,
|
|
254
|
+
{ value, prev: prevs[key2] }
|
|
255
|
+
])
|
|
256
|
+
);
|
|
257
|
+
};
|
|
258
|
+
const newBlock = async (type, params) => {
|
|
259
|
+
assertBlock(params.parent);
|
|
260
|
+
assertFinalizedDescendant(params.parent);
|
|
261
|
+
const block = await createBlock(chain, params);
|
|
262
|
+
assertFinalizedDescendant(params.parent);
|
|
263
|
+
blocks$.next({
|
|
264
|
+
...blocks$.getValue(),
|
|
265
|
+
[block.hash]: block
|
|
266
|
+
});
|
|
267
|
+
setBlockMeta(chain, block);
|
|
268
|
+
newBlocks$.next(block.hash);
|
|
269
|
+
if (type === "best") {
|
|
270
|
+
bestSrc$.next(block.hash);
|
|
271
|
+
} else if (type === "finalized") {
|
|
272
|
+
bestSrc$.next(block.hash);
|
|
273
|
+
finalizedSrc$.next(block.hash);
|
|
274
|
+
}
|
|
275
|
+
return block;
|
|
276
|
+
};
|
|
277
|
+
const hrmpEgressChannels = /* @__PURE__ */ new Set();
|
|
278
|
+
const chain = {
|
|
279
|
+
blocks$: blocks$.asObservable(),
|
|
280
|
+
newBlocks$: newBlocks$.asObservable(),
|
|
281
|
+
best$,
|
|
282
|
+
finalized$,
|
|
283
|
+
getBlock,
|
|
284
|
+
newBlock,
|
|
285
|
+
changeBest,
|
|
286
|
+
changeFinalized,
|
|
287
|
+
setStorage,
|
|
288
|
+
getStorage,
|
|
289
|
+
getStorageBatch,
|
|
290
|
+
getStorageDescendants,
|
|
291
|
+
getStorageDiff,
|
|
292
|
+
hrmpChannels: hrmpEgressChannels,
|
|
293
|
+
openHrmpChannel: (recipientParaId) => hrmpEgressChannels.add(recipientParaId)
|
|
294
|
+
};
|
|
295
|
+
return chain;
|
|
296
|
+
};
|
|
297
|
+
const finalizedAndPruned$ = (chain) => chain.finalized$.pipe(
|
|
298
|
+
pairwise(),
|
|
299
|
+
withLatestFrom(chain.blocks$),
|
|
300
|
+
map(([[prev, next], blocks]) => {
|
|
301
|
+
const finalized = [next];
|
|
302
|
+
let blockHash = next;
|
|
303
|
+
while (blocks[blockHash]?.parent !== prev && blocks[blockHash]?.parent in blocks) {
|
|
304
|
+
blockHash = blocks[blockHash].parent;
|
|
305
|
+
finalized.push(blockHash);
|
|
306
|
+
}
|
|
307
|
+
finalized.reverse();
|
|
308
|
+
const pruned = [];
|
|
309
|
+
const pruneBranch = (hash) => {
|
|
310
|
+
const block = blocks[hash];
|
|
311
|
+
if (!block) return;
|
|
312
|
+
pruned.push(hash);
|
|
313
|
+
block.children.forEach(pruneBranch);
|
|
314
|
+
};
|
|
315
|
+
let i = 0;
|
|
316
|
+
blockHash = prev;
|
|
317
|
+
while (blockHash !== next) {
|
|
318
|
+
const block = blocks[blockHash];
|
|
319
|
+
for (const child of block.children) {
|
|
320
|
+
if (child === finalized[i]) continue;
|
|
321
|
+
pruneBranch(child);
|
|
322
|
+
}
|
|
323
|
+
blockHash = finalized[i];
|
|
324
|
+
i++;
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
finalized,
|
|
328
|
+
pruned
|
|
329
|
+
};
|
|
330
|
+
})
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
export { createChain, finalizedAndPruned$ };
|
|
334
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sources":["../../src/chain.ts"],"sourcesContent":["import { file } from \"bun\";\nimport { Binary, type HexString } from \"polkadot-api\";\nimport {\n BehaviorSubject,\n filter,\n map,\n pairwise,\n Subject,\n withLatestFrom,\n type Observable,\n} from \"rxjs\";\nimport {\n createBlock,\n type Block,\n type CreateBlockParams,\n} from \"./block-builder/create-block\";\nimport { setBlockMeta } from \"./codecs\";\nimport { getRuntimeVersion } from \"./executor\";\nimport { logger } from \"./logger\";\nimport type { Source } from \"./source\";\n\nconst log = logger.child({ module: \"chain\" });\nimport {\n createRoot,\n deleteValue,\n forEachDescendant,\n getDescendantNodes,\n getDiff,\n getNode,\n getSoftDeletedDescendantKeys,\n insertValue,\n type StorageNode,\n} from \"./storage\";\n\nexport interface Chain {\n blocks$: Observable<Record<HexString, Block>>;\n newBlocks$: Observable<HexString>;\n best$: Observable<HexString>;\n finalized$: Observable<HexString>;\n\n getBlock: (hash: HexString) => Block | undefined;\n\n newBlock: (\n type: \"best\" | \"finalized\" | \"fork\",\n params: CreateBlockParams\n ) => Promise<Block>;\n changeBest: (hash: HexString) => void;\n changeFinalized: (hash: HexString) => void;\n setStorage: (\n hash: HexString,\n changes: Record<HexString, Uint8Array | null>\n ) => void;\n\n getStorage: (hash: HexString, key: HexString) => Promise<StorageNode>;\n getStorageBatch: (\n hash: HexString,\n keys: HexString[]\n ) => Promise<StorageNode[]>;\n getStorageDescendants: (\n hash: HexString,\n prefix: HexString\n ) => Promise<Record<HexString, StorageNode>>;\n\n // prev: undefined means unknown: the storage value wasn't loaded. So it was set, but we don't know the value we had previously\n // prev: null means the value was empty.\n getStorageDiff: (\n hash: HexString,\n baseHash?: HexString\n ) => Promise<\n Record<string, { value: Uint8Array | null; prev?: Uint8Array | null }>\n >;\n\n hrmpChannels: Set<number>;\n openHrmpChannel: (recipientParaId: number) => void;\n}\n\nconst CODE_KEY: HexString = \"0x3a636f6465\"; // hex-encoded \":code\"\n\nexport const createChain = (source: Source, key?: string): Chain => {\n const cacheFile = key ? `code_${key}.bin` : null;\n\n const blocks$ = new BehaviorSubject<Record<HexString, Block>>({});\n const newBlocks$ = new Subject<HexString>();\n const bestSrc$ = new BehaviorSubject<HexString | null>(null);\n const best$ = bestSrc$.pipe(filter((v) => v != null));\n const finalizedSrc$ = new BehaviorSubject<HexString | null>(null);\n const finalized$ = finalizedSrc$.pipe(filter((v) => v != null));\n\n // Create the initial block from the source\n const asyncInitialBlock: Promise<Block> = source.block.then(async (block) => {\n log.debug(\"loading code\");\n const code =\n cacheFile && (await file(cacheFile).exists())\n ? await file(cacheFile).bytes()\n : await source.getStorage(CODE_KEY);\n\n if (!code) {\n throw new Error(\"No runtime code found at source block\");\n }\n if (cacheFile) file(cacheFile).write(code);\n\n log.debug(\"code loaded, getting runtime\");\n const initialRuntime = await getRuntimeVersion(code);\n log.debug(\"runtime loaded\");\n\n const result: Block = {\n hash: block.blockHash,\n parent:\n \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n header: block.header,\n body: block.body,\n code,\n storageRoot: insertValue(\n createRoot(),\n Binary.fromHex(CODE_KEY),\n CODE_KEY.length - 2,\n code\n ),\n runtime: initialRuntime,\n children: [],\n };\n\n blocks$.next({\n [result.hash]: result,\n });\n setBlockMeta(chain, result);\n\n bestSrc$.next(result.hash);\n finalizedSrc$.next(result.hash);\n\n return result;\n });\n\n const getBlock = (hash: HexString) => blocks$.getValue()[hash]!;\n const assertBlock = (hash: HexString) => {\n const block = getBlock(hash);\n if (!block) {\n throw new Error(`Block not found`);\n }\n return block;\n };\n\n const isDescendant = (parentHash: HexString, descendantHash: HexString) => {\n const parent = getBlock(parentHash);\n let block = getBlock(descendantHash);\n while (block.header.number > parent.header.number) {\n block = getBlock(block.parent);\n }\n return block.hash === parent.hash;\n };\n const assertFinalizedDescendant = (hash: HexString) => {\n if (!isDescendant(finalizedSrc$.getValue()!, hash)) {\n throw new Error(`Block is not a descendant of finalized`);\n }\n };\n\n const changeBest = (hash: HexString) => {\n assertBlock(hash);\n assertFinalizedDescendant(hash);\n\n bestSrc$.next(hash);\n };\n\n const changeFinalized = (hash: HexString) => {\n assertBlock(hash);\n assertFinalizedDescendant(hash);\n\n if (!isDescendant(hash, bestSrc$.getValue()!)) {\n bestSrc$.next(hash);\n }\n finalizedSrc$.next(hash);\n };\n\n const setStorage = (\n hash: HexString,\n changes: Record<HexString, Uint8Array | null>\n ): void => {\n const block = assertBlock(hash);\n for (const key in changes) {\n const binKey = Binary.fromHex(key);\n if (changes[key]) {\n block.storageRoot = insertValue(\n block.storageRoot,\n binKey,\n binKey.length * 2,\n changes[key]\n );\n } else {\n block.storageRoot = deleteValue(\n block.storageRoot,\n binKey,\n binKey.length * 2\n );\n }\n }\n };\n\n const getStorage = async (\n hash: HexString,\n key: HexString\n ): Promise<StorageNode> => {\n const initialBlock = await asyncInitialBlock;\n\n const block = assertBlock(hash);\n const binKey = Binary.fromHex(key);\n const node =\n getNode(block.storageRoot, binKey, binKey.length * 2) ??\n // The initialBlock's storage might mutate as data is loaded from source\n // and because of the immutable storage structure, newer blocks won't see that state.\n getNode(initialBlock.storageRoot, binKey, binKey.length * 2);\n\n if (node?.value !== undefined) {\n return node;\n }\n\n const sourceResult = await source.getStorage(key);\n initialBlock.storageRoot = insertValue(\n initialBlock.storageRoot,\n binKey,\n binKey.length * 2,\n sourceResult\n );\n return getNode(initialBlock.storageRoot, binKey, binKey.length * 2)!;\n };\n\n const getStorageBatch = async (\n hash: HexString,\n keys: HexString[]\n ): Promise<StorageNode[]> => {\n const initialBlock = await asyncInitialBlock;\n const block = assertBlock(hash);\n\n const keysIndexed = keys.map((key, idx) => ({ key, idx }));\n const pending = new Array<{\n binKey: Uint8Array;\n key: HexString;\n idx: number;\n }>();\n\n const result = keysIndexed.map(({ key, idx }) => {\n const binKey = Binary.fromHex(key);\n const node =\n getNode(block.storageRoot, binKey, binKey.length * 2) ??\n // The initialBlock's storage might mutate as data is loaded from source\n // and because of the immutable storage structure, newer blocks won't see that state.\n getNode(initialBlock.storageRoot, binKey, binKey.length * 2);\n\n if (node?.value !== undefined) {\n return node;\n }\n pending.push({ key, idx, binKey });\n return null!;\n });\n\n const loadedResults = await source.getStorageBatch(\n pending.map(({ key }) => key)\n );\n loadedResults.forEach((res, i) => {\n const { idx, binKey } = pending[i]!;\n initialBlock.storageRoot = insertValue(\n initialBlock.storageRoot,\n binKey,\n binKey.length * 2,\n res\n );\n result[idx] = getNode(\n initialBlock.storageRoot,\n binKey,\n binKey.length * 2\n )!;\n });\n\n return result;\n };\n\n const getStorageDescendants = async (\n hash: HexString,\n prefix: HexString\n ): Promise<Record<HexString, StorageNode>> => {\n const initialBlock = await asyncInitialBlock;\n const block = assertBlock(hash);\n const binPrefix = Binary.fromHex(prefix);\n\n const getNodeDescendants = (node: StorageNode | null) =>\n node\n ? Object.fromEntries(\n getDescendantNodes(node, binPrefix, binPrefix.length * 2).map(\n ({ key, node }) => [Binary.toHex(key), node]\n )\n )\n : {};\n\n const blockNode = getNode(\n block.storageRoot,\n binPrefix,\n binPrefix.length * 2\n );\n if (blockNode?.exhaustive) {\n return getNodeDescendants(blockNode);\n }\n\n let rootNode = getNode(\n initialBlock.storageRoot,\n binPrefix,\n binPrefix.length * 2\n );\n if (!rootNode?.exhaustive) {\n const sourceDescendants = await source.getStorageDescendants(prefix);\n if (!Object.keys(sourceDescendants).length)\n initialBlock.storageRoot = insertValue(\n initialBlock.storageRoot,\n binPrefix,\n binPrefix.length * 2,\n null\n );\n for (const key in sourceDescendants) {\n const binKey = Binary.fromHex(key);\n initialBlock.storageRoot = insertValue(\n initialBlock.storageRoot,\n binKey,\n binKey.length * 2,\n sourceDescendants[key]!\n );\n }\n // mark node as exhaustive\n rootNode = getNode(\n initialBlock.storageRoot,\n binPrefix,\n binPrefix.length * 2\n )!;\n rootNode.exhaustive = true;\n forEachDescendant(rootNode, (node) => (node.exhaustive = true));\n }\n\n // There's a temptation to propagate this exhaustive to the blockNode\n // but then it could mess up storage diffs.\n\n // Soft-deleted keys in blockNode must explicitly exclude entries from rootNode.\n // getDescendantNodes skips null-valued nodes, so without this the old rootNode\n // value would leak through for deleted keys.\n const deletedKeys = blockNode\n ? new Set(\n getSoftDeletedDescendantKeys(\n blockNode,\n binPrefix,\n binPrefix.length * 2\n ).map(Binary.toHex)\n )\n : null;\n\n const rootDescendants = getNodeDescendants(rootNode);\n return {\n ...(deletedKeys\n ? Object.fromEntries(\n Object.entries(rootDescendants).filter(\n ([key]) => !deletedKeys.has(key)\n )\n )\n : rootDescendants),\n ...getNodeDescendants(blockNode),\n };\n };\n\n const getStorageDiff = async (hash: HexString, baseHash?: HexString) => {\n const target = getBlock(hash);\n if (!target) {\n throw new Error(`Block not found`);\n }\n\n const base = getBlock(baseHash ?? target.parent);\n if (!base) {\n throw new Error(`Parent block not loaded`);\n }\n const diff = getDiff(\n base.storageRoot,\n (await asyncInitialBlock).storageRoot,\n target.storageRoot\n );\n const prevs = Object.fromEntries(\n getDescendantNodes(diff.prev, new Uint8Array(), 0).map(\n ({ key, node }) => [Binary.toHex(key), node.value]\n )\n );\n\n const inserts = getDescendantNodes(diff.insert, new Uint8Array(), 0).map(\n ({ key, node }) => [Binary.toHex(key), node.value!] as const\n );\n const deletes = diff.deleteValues.map(\n ({ key }) => [Binary.toHex(key), null] as const\n );\n\n return Object.fromEntries(\n [...inserts, ...deletes].map(([key, value]) => [\n key,\n { value, prev: prevs[key] },\n ])\n );\n };\n\n const newBlock: Chain[\"newBlock\"] = async (type, params): Promise<Block> => {\n assertBlock(params.parent);\n assertFinalizedDescendant(params.parent);\n\n const block = await createBlock(chain, params);\n\n // If the finalized has changed while we were building the block and this one\n // became pruned, then we should fail.\n assertFinalizedDescendant(params.parent);\n\n // Add block to blocks$\n blocks$.next({\n ...blocks$.getValue(),\n [block.hash]: block,\n });\n\n setBlockMeta(chain, block);\n\n // Emit newBlocks$ event\n newBlocks$.next(block.hash);\n\n // Update best/finalized based on type\n if (type === \"best\") {\n bestSrc$.next(block.hash);\n } else if (type === \"finalized\") {\n bestSrc$.next(block.hash);\n finalizedSrc$.next(block.hash);\n }\n\n return block;\n };\n\n const hrmpEgressChannels = new Set<number>();\n\n const chain: Chain = {\n blocks$: blocks$.asObservable(),\n newBlocks$: newBlocks$.asObservable(),\n best$: best$,\n finalized$: finalized$,\n getBlock,\n newBlock,\n changeBest,\n changeFinalized,\n setStorage,\n getStorage,\n getStorageBatch,\n getStorageDescendants,\n getStorageDiff,\n hrmpChannels: hrmpEgressChannels,\n openHrmpChannel: (recipientParaId) =>\n hrmpEgressChannels.add(recipientParaId),\n };\n\n return chain;\n};\n\nexport const finalizedAndPruned$ = (chain: Chain) =>\n chain.finalized$.pipe(\n pairwise(),\n withLatestFrom(chain.blocks$),\n map(([[prev, next], blocks]) => {\n const finalized = [next];\n let blockHash = next;\n while (\n blocks[blockHash]?.parent !== prev &&\n blocks[blockHash]?.parent! in blocks\n ) {\n blockHash = blocks[blockHash]!.parent;\n finalized.push(blockHash);\n }\n finalized.reverse();\n\n const pruned: HexString[] = [];\n const pruneBranch = (hash: HexString) => {\n const block = blocks[hash];\n if (!block) return;\n pruned.push(hash);\n block.children.forEach(pruneBranch);\n };\n\n let i = 0;\n blockHash = prev;\n while (blockHash !== next) {\n const block = blocks[blockHash]!;\n for (const child of block.children) {\n if (child === finalized[i]) continue;\n pruneBranch(child);\n }\n blockHash = finalized[i]!;\n i++;\n }\n\n return {\n finalized,\n pruned,\n };\n })\n );\n"],"names":["key","node"],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { getLookupFn, getDynamicBuilder } from '@polkadot-api/metadata-builders';
|
|
2
|
+
import { u32, unifyMetadata, decAnyMetadata, compact } from '@polkadot-api/substrate-bindings';
|
|
3
|
+
import { getExtrinsicDecoder as getExtrinsicDecoder$1 } from '@polkadot-api/tx-utils';
|
|
4
|
+
import { Binary } from 'polkadot-api';
|
|
5
|
+
import { mergeUint8 } from 'polkadot-api/utils';
|
|
6
|
+
import { runRuntimeCall } from './executor.js';
|
|
7
|
+
import { logger } from './logger.js';
|
|
8
|
+
|
|
9
|
+
const log = logger.child({ module: "codecs" });
|
|
10
|
+
const blockMeta = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
const setBlockMeta = async (chain, block) => {
|
|
12
|
+
const parentMeta = blockMeta.get(chain.getBlock(block.parent));
|
|
13
|
+
if (!block.hasNewRuntime && parentMeta) {
|
|
14
|
+
blockMeta.set(block, parentMeta);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
blockMeta.set(
|
|
18
|
+
block,
|
|
19
|
+
new Promise(async (resolve) => {
|
|
20
|
+
const metadata = await runRuntimeCall({
|
|
21
|
+
chain,
|
|
22
|
+
hash: block.hash,
|
|
23
|
+
call: "Metadata_metadata_at_version",
|
|
24
|
+
params: Binary.toHex(u32.enc(15))
|
|
25
|
+
});
|
|
26
|
+
const metadataRaw = Binary.fromHex(metadata.result);
|
|
27
|
+
const lookup = getLookupFn(unifyMetadata(decAnyMetadata(metadataRaw)));
|
|
28
|
+
const dynamicBuilder = getDynamicBuilder(lookup);
|
|
29
|
+
resolve({ lookup, dynamicBuilder, metadataRaw });
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
const getConstant = async (block, palletName, entryName) => {
|
|
34
|
+
const meta = await blockMeta.get(block);
|
|
35
|
+
if (!meta) {
|
|
36
|
+
throw new Error("Block doesn't have metadata set");
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const codec = meta.dynamicBuilder.buildConstant(palletName, entryName);
|
|
40
|
+
const pallet = meta.lookup.metadata.pallets.find(
|
|
41
|
+
(p) => p.name === palletName
|
|
42
|
+
);
|
|
43
|
+
const entry = pallet.constants.find((ct) => ct.name === entryName);
|
|
44
|
+
return codec.dec(entry.value);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const getStorageCodecs = async (block, palletName, entryName) => {
|
|
50
|
+
const meta = await blockMeta.get(block);
|
|
51
|
+
if (!meta) {
|
|
52
|
+
throw new Error("Block doesn't have metadata set");
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
return meta.dynamicBuilder.buildStorage(palletName, entryName);
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const getTxCodec = async (block, palletName, txName) => {
|
|
61
|
+
const meta = await blockMeta.get(block);
|
|
62
|
+
if (!meta) {
|
|
63
|
+
throw new Error("Block doesn't have metadata set");
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
return meta.dynamicBuilder.buildCall(palletName, txName);
|
|
67
|
+
} catch (ex) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const getCallCodec = async (block, palletName, apiName) => {
|
|
72
|
+
const meta = await blockMeta.get(block);
|
|
73
|
+
if (!meta) {
|
|
74
|
+
throw new Error("Block doesn't have metadata set");
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return meta.dynamicBuilder.buildRuntimeCall(palletName, apiName);
|
|
78
|
+
} catch (ex) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const getCallData = async (block, palletName, txName, params) => {
|
|
83
|
+
const tx = await getTxCodec(block, palletName, txName);
|
|
84
|
+
if (!tx) return null;
|
|
85
|
+
try {
|
|
86
|
+
const { location, codec } = tx;
|
|
87
|
+
return mergeUint8([new Uint8Array(location), codec.enc(params)]);
|
|
88
|
+
} catch (ex) {
|
|
89
|
+
log.error(ex, "getCallData failed");
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const getExtrinsicDecoder = async (block) => {
|
|
94
|
+
const meta = await blockMeta.get(block);
|
|
95
|
+
if (!meta) {
|
|
96
|
+
throw new Error("Block doesn't have metadata set");
|
|
97
|
+
}
|
|
98
|
+
return getExtrinsicDecoder$1(meta.metadataRaw);
|
|
99
|
+
};
|
|
100
|
+
const unsignedExtrinsic = (callData) => mergeUint8([compact.enc(callData.length + 1), new Uint8Array([4]), callData]);
|
|
101
|
+
|
|
102
|
+
export { getCallCodec, getCallData, getConstant, getExtrinsicDecoder, getStorageCodecs, getTxCodec, setBlockMeta, unsignedExtrinsic };
|
|
103
|
+
//# sourceMappingURL=codecs.js.map
|