Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions docs/protocol-wire-ids.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Protocol wire-tag IDs

> Generated by `scripts/protocol-wire-ids.mjs`. Do not edit by hand — re-run the script.

- Date: 2026-05-27
- Source: `packages/host-api/src/protocol/impl.ts` (variant order) + `packages/host-api/src/protocol/messageCodec.ts` (flattening)
- Methods: 54 (43 request, 11 subscribe)
- Variants (wire tags): **130** of max **256**
- Remaining capacity: **126** variants before the single-byte discriminant overflows

The discriminant is one byte; index `255` is the last representable value.

| Index (dec) | Index (hex) | Wire tag | Method kind |
| ----------: | ----------- | -------- | ----------- |
| 0 | 0x00 | `host_handshake_request` | request |
| 1 | 0x01 | `host_handshake_response` | request |
| 2 | 0x02 | `host_feature_supported_request` | request |
| 3 | 0x03 | `host_feature_supported_response` | request |
| 4 | 0x04 | `host_push_notification_request` | request |
| 5 | 0x05 | `host_push_notification_response` | request |
| 6 | 0x06 | `host_navigate_to_request` | request |
| 7 | 0x07 | `host_navigate_to_response` | request |
| 8 | 0x08 | `host_device_permission_request` | request |
| 9 | 0x09 | `host_device_permission_response` | request |
| 10 | 0x0A | `remote_permission_request` | request |
| 11 | 0x0B | `remote_permission_response` | request |
| 12 | 0x0C | `host_local_storage_read_request` | request |
| 13 | 0x0D | `host_local_storage_read_response` | request |
| 14 | 0x0E | `host_local_storage_write_request` | request |
| 15 | 0x0F | `host_local_storage_write_response` | request |
| 16 | 0x10 | `host_local_storage_clear_request` | request |
| 17 | 0x11 | `host_local_storage_clear_response` | request |
| 18 | 0x12 | `host_account_connection_status_subscribe_start` | subscribe |
| 19 | 0x13 | `host_account_connection_status_subscribe_stop` | subscribe |
| 20 | 0x14 | `host_account_connection_status_subscribe_interrupt` | subscribe |
| 21 | 0x15 | `host_account_connection_status_subscribe_receive` | subscribe |
| 22 | 0x16 | `host_account_get_request` | request |
| 23 | 0x17 | `host_account_get_response` | request |
| 24 | 0x18 | `host_account_get_alias_request` | request |
| 25 | 0x19 | `host_account_get_alias_response` | request |
| 26 | 0x1A | `host_account_create_proof_request` | request |
| 27 | 0x1B | `host_account_create_proof_response` | request |
| 28 | 0x1C | `host_get_legacy_accounts_request` | request |
| 29 | 0x1D | `host_get_legacy_accounts_response` | request |
| 30 | 0x1E | `host_create_transaction_request` | request |
| 31 | 0x1F | `host_create_transaction_response` | request |
| 32 | 0x20 | `host_create_transaction_with_legacy_account_request` | request |
| 33 | 0x21 | `host_create_transaction_with_legacy_account_response` | request |
| 34 | 0x22 | `host_sign_raw_with_legacy_account_request` | request |
| 35 | 0x23 | `host_sign_raw_with_legacy_account_response` | request |
| 36 | 0x24 | `host_sign_payload_with_legacy_account_request` | request |
| 37 | 0x25 | `host_sign_payload_with_legacy_account_response` | request |
| 38 | 0x26 | `host_chat_create_room_request` | request |
| 39 | 0x27 | `host_chat_create_room_response` | request |
| 40 | 0x28 | `host_chat_register_bot_request` | request |
| 41 | 0x29 | `host_chat_register_bot_response` | request |
| 42 | 0x2A | `host_chat_list_subscribe_start` | subscribe |
| 43 | 0x2B | `host_chat_list_subscribe_stop` | subscribe |
| 44 | 0x2C | `host_chat_list_subscribe_interrupt` | subscribe |
| 45 | 0x2D | `host_chat_list_subscribe_receive` | subscribe |
| 46 | 0x2E | `host_chat_post_message_request` | request |
| 47 | 0x2F | `host_chat_post_message_response` | request |
| 48 | 0x30 | `host_chat_action_subscribe_start` | subscribe |
| 49 | 0x31 | `host_chat_action_subscribe_stop` | subscribe |
| 50 | 0x32 | `host_chat_action_subscribe_interrupt` | subscribe |
| 51 | 0x33 | `host_chat_action_subscribe_receive` | subscribe |
| 52 | 0x34 | `product_chat_custom_message_render_subscribe_start` | subscribe |
| 53 | 0x35 | `product_chat_custom_message_render_subscribe_stop` | subscribe |
| 54 | 0x36 | `product_chat_custom_message_render_subscribe_interrupt` | subscribe |
| 55 | 0x37 | `product_chat_custom_message_render_subscribe_receive` | subscribe |
| 56 | 0x38 | `remote_statement_store_subscribe_start` | subscribe |
| 57 | 0x39 | `remote_statement_store_subscribe_stop` | subscribe |
| 58 | 0x3A | `remote_statement_store_subscribe_interrupt` | subscribe |
| 59 | 0x3B | `remote_statement_store_subscribe_receive` | subscribe |
| 60 | 0x3C | `remote_statement_store_create_proof_request` | request |
| 61 | 0x3D | `remote_statement_store_create_proof_response` | request |
| 62 | 0x3E | `remote_statement_store_submit_request` | request |
| 63 | 0x3F | `remote_statement_store_submit_response` | request |
| 64 | 0x40 | `remote_preimage_lookup_subscribe_start` | subscribe |
| 65 | 0x41 | `remote_preimage_lookup_subscribe_stop` | subscribe |
| 66 | 0x42 | `remote_preimage_lookup_subscribe_interrupt` | subscribe |
| 67 | 0x43 | `remote_preimage_lookup_subscribe_receive` | subscribe |
| 68 | 0x44 | `remote_preimage_submit_request` | request |
| 69 | 0x45 | `remote_preimage_submit_response` | request |
| 70 | 0x46 | `host_jsonrpc_message_send_request` | request |
| 71 | 0x47 | `host_jsonrpc_message_send_response` | request |
| 72 | 0x48 | `host_jsonrpc_message_subscribe_start` | subscribe |
| 73 | 0x49 | `host_jsonrpc_message_subscribe_stop` | subscribe |
| 74 | 0x4A | `host_jsonrpc_message_subscribe_interrupt` | subscribe |
| 75 | 0x4B | `host_jsonrpc_message_subscribe_receive` | subscribe |
| 76 | 0x4C | `remote_chain_head_follow_subscribe_start` | subscribe |
| 77 | 0x4D | `remote_chain_head_follow_subscribe_stop` | subscribe |
| 78 | 0x4E | `remote_chain_head_follow_subscribe_interrupt` | subscribe |
| 79 | 0x4F | `remote_chain_head_follow_subscribe_receive` | subscribe |
| 80 | 0x50 | `remote_chain_head_header_request` | request |
| 81 | 0x51 | `remote_chain_head_header_response` | request |
| 82 | 0x52 | `remote_chain_head_body_request` | request |
| 83 | 0x53 | `remote_chain_head_body_response` | request |
| 84 | 0x54 | `remote_chain_head_storage_request` | request |
| 85 | 0x55 | `remote_chain_head_storage_response` | request |
| 86 | 0x56 | `remote_chain_head_call_request` | request |
| 87 | 0x57 | `remote_chain_head_call_response` | request |
| 88 | 0x58 | `remote_chain_head_unpin_request` | request |
| 89 | 0x59 | `remote_chain_head_unpin_response` | request |
| 90 | 0x5A | `remote_chain_head_continue_request` | request |
| 91 | 0x5B | `remote_chain_head_continue_response` | request |
| 92 | 0x5C | `remote_chain_head_stop_operation_request` | request |
| 93 | 0x5D | `remote_chain_head_stop_operation_response` | request |
| 94 | 0x5E | `remote_chain_spec_genesis_hash_request` | request |
| 95 | 0x5F | `remote_chain_spec_genesis_hash_response` | request |
| 96 | 0x60 | `remote_chain_spec_chain_name_request` | request |
| 97 | 0x61 | `remote_chain_spec_chain_name_response` | request |
| 98 | 0x62 | `remote_chain_spec_properties_request` | request |
| 99 | 0x63 | `remote_chain_spec_properties_response` | request |
| 100 | 0x64 | `remote_chain_transaction_broadcast_request` | request |
| 101 | 0x65 | `remote_chain_transaction_broadcast_response` | request |
| 102 | 0x66 | `remote_chain_transaction_stop_request` | request |
| 103 | 0x67 | `remote_chain_transaction_stop_response` | request |
| 104 | 0x68 | `host_theme_subscribe_start` | subscribe |
| 105 | 0x69 | `host_theme_subscribe_stop` | subscribe |
| 106 | 0x6A | `host_theme_subscribe_interrupt` | subscribe |
| 107 | 0x6B | `host_theme_subscribe_receive` | subscribe |
| 108 | 0x6C | `host_derive_entropy_request` | request |
| 109 | 0x6D | `host_derive_entropy_response` | request |
| 110 | 0x6E | `host_get_user_id_request` | request |
| 111 | 0x6F | `host_get_user_id_response` | request |
| 112 | 0x70 | `host_request_login_request` | request |
| 113 | 0x71 | `host_request_login_response` | request |
| 114 | 0x72 | `host_sign_raw_request` | request |
| 115 | 0x73 | `host_sign_raw_response` | request |
| 116 | 0x74 | `host_sign_payload_request` | request |
| 117 | 0x75 | `host_sign_payload_response` | request |
| 118 | 0x76 | `host_payment_balance_subscribe_start` | subscribe |
| 119 | 0x77 | `host_payment_balance_subscribe_stop` | subscribe |
| 120 | 0x78 | `host_payment_balance_subscribe_interrupt` | subscribe |
| 121 | 0x79 | `host_payment_balance_subscribe_receive` | subscribe |
| 122 | 0x7A | `host_payment_top_up_request` | request |
| 123 | 0x7B | `host_payment_top_up_response` | request |
| 124 | 0x7C | `host_payment_request_request` | request |
| 125 | 0x7D | `host_payment_request_response` | request |
| 126 | 0x7E | `host_payment_status_subscribe_start` | subscribe |
| 127 | 0x7F | `host_payment_status_subscribe_stop` | subscribe |
| 128 | 0x80 | `host_payment_status_subscribe_interrupt` | subscribe |
| 129 | 0x81 | `host_payment_status_subscribe_receive` | subscribe |

134 changes: 134 additions & 0 deletions scripts/protocol-wire-ids.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env node
// Reports the wire-tag index (SCALE enum discriminant) of every variant in the
// host <-> product protocol enum.
//
// The enum is built in packages/host-api/src/protocol/messageCodec.ts by walking
// `hostApiProtocol` (impl.ts) in declaration order and flattening each method into
// variants. scale-ts `Enum` assigns indices by insertion order, starting at 0.
// This script reproduces that flattening from source, so it needs no build step
// and no node_modules.
//
// Flattening rule (mirrors messageCodec.ts createPayload):
// request -> <method>_request, <method>_response
// subscribe -> <method>_start, <method>_stop, <method>_interrupt, <method>_receive
//
// The discriminant is a single byte, so the enum is capped at 256 variants
// (indices 0..=255). See docs note generated alongside this report.
//
// Usage:
// node scripts/protocol-wire-ids.mjs # print report to stdout
// node scripts/protocol-wire-ids.mjs -o FILE # also write report to FILE
// node scripts/protocol-wire-ids.mjs --json # emit JSON instead of markdown

import { readFileSync, writeFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative } from 'node:path';

const MAX_VARIANTS = 256; // single-byte discriminant

const here = dirname(fileURLToPath(import.meta.url));
const repoRoot = join(here, '..');
const implPath = join(repoRoot, 'packages/host-api/src/protocol/impl.ts');

const VARIANTS_BY_KIND = {
versionedRequest: ['request', 'response'],
versionedSubscription: ['start', 'stop', 'interrupt', 'receive'],
};

/** Parse impl.ts and return the ordered list of { method, kind } entries. */
function parseProtocol(source) {
// Matches lines like: remote_chain_head_follow_subscribe: versionedSubscription({
const re = /^\s*([a-z][a-z0-9_]*)\s*:\s*(versionedRequest|versionedSubscription)\s*\(/gm;
const methods = [];
let m;
while ((m = re.exec(source)) !== null) {
methods.push({ method: m[1], kind: m[2] });
}
if (methods.length === 0) {
throw new Error(`No protocol methods found in ${implPath} — has the format changed?`);
}
return methods;
}

/** Expand methods into the flat, ordered list of enum variant tags. */
function buildVariants(methods) {
const variants = [];
for (const { method, kind } of methods) {
const suffixes = VARIANTS_BY_KIND[kind];
for (const suffix of suffixes) {
variants.push({ tag: `${method}_${suffix}`, method, kind });
}
}
return variants.map((v, index) => ({ index, ...v }));
}

function renderMarkdown(variants, methods) {
const total = variants.length;
const remaining = MAX_VARIANTS - total;
const requests = methods.filter((m) => m.kind === 'versionedRequest').length;
const subscriptions = methods.filter((m) => m.kind === 'versionedSubscription').length;
const now = new Date().toISOString().slice(0, 10);

const lines = [];
lines.push('# Protocol wire-tag IDs');
lines.push('');
lines.push('> Generated by `scripts/protocol-wire-ids.mjs`. Do not edit by hand — re-run the script.');
lines.push('');
lines.push(`- Date: ${now}`);
lines.push(`- Source: \`${relative(repoRoot, implPath)}\` (variant order) + \`packages/host-api/src/protocol/messageCodec.ts\` (flattening)`);
lines.push(`- Methods: ${methods.length} (${requests} request, ${subscriptions} subscribe)`);
lines.push(`- Variants (wire tags): **${total}** of max **${MAX_VARIANTS}**`);
lines.push(`- Remaining capacity: **${remaining}** variants before the single-byte discriminant overflows`);
lines.push('');
lines.push('The discriminant is one byte; index `255` is the last representable value.');
lines.push('');
lines.push('| Index (dec) | Index (hex) | Wire tag | Method kind |');
lines.push('| ----------: | ----------- | -------- | ----------- |');
for (const v of variants) {
const hex = '0x' + v.index.toString(16).toUpperCase().padStart(2, '0');
const kind = v.kind === 'versionedRequest' ? 'request' : 'subscribe';
lines.push(`| ${v.index} | ${hex} | \`${v.tag}\` | ${kind} |`);
}
lines.push('');
return lines.join('\n');
}

function main() {
const args = process.argv.slice(2);
const asJson = args.includes('--json');
const outIdx = args.findIndex((a) => a === '-o' || a === '--out');
const outFile = outIdx !== -1 ? args[outIdx + 1] : undefined;

const source = readFileSync(implPath, 'utf8');
const methods = parseProtocol(source);
const variants = buildVariants(methods);

if (variants.length > MAX_VARIANTS) {
console.error(
`WARNING: ${variants.length} variants exceeds the ${MAX_VARIANTS}-variant single-byte limit.`,
);
}

const output = asJson
? JSON.stringify(
{
generatedAt: new Date().toISOString(),
maxVariants: MAX_VARIANTS,
total: variants.length,
remaining: MAX_VARIANTS - variants.length,
variants,
},
null,
2,
)
: renderMarkdown(variants, methods);

process.stdout.write(output + '\n');
if (outFile) {
const target = outFile.startsWith('/') ? outFile : join(process.cwd(), outFile);
writeFileSync(target, output + '\n');
console.error(`Wrote report to ${target}`);
}
}

main();