Skip to content

Conversation

ladamesny
Copy link
Contributor

@ladamesny ladamesny commented Jun 16, 2025

Description

Overview

Added a new automatic-generate-keys command that automatically generates session keys by connecting to a running Partner Chain node via RPC, eliminating the need for manual key generation and parsing. Jira Ticket ETCM-11971

Implementation Details

Command Structure:

  • New command: partner-chains-cli automatic-generate-keys --url <NODE_URL>
  • Default URL: http://localhost:9933
  • Outputs session keys with correct type identifiers to session_keys.json
  • Technical Approach:

Uses a clean two-RPC-call approach:

  1. author_rotateKeys - Generates new session keys on the node
  2. sessionKeys_decodeSessionKeys - Decodes the keys to get exact key types and public keys

Key Benefits:

✅ No assumptions - Node provides actual key types (e.g., "gran", "imon", "aura")
✅ Runtime-agnostic - Works with any SessionKeys configuration
✅ No manual parsing - Node handles all SCALE decoding internally
✅ Always accurate - Impossible to get key order wrong

Checklist

  • Commit sequence broadly makes sense and commits have useful messages.
  • The size limit of 400 LOC isn't needlessly exceeded
  • The PR refers to a JIRA ticket (if one exists)
  • New tests are added if needed and existing tests are updated.
  • New code is documented and existing documentation is updated.
  • Relevant logging and metrics added
  • Any changes are noted in the changelog.md for affected crate
  • Self-reviewed the diff

@@ -40,6 +41,9 @@ plutus-datum-derive = { workspace = true }
ed25519-zebra = { workspace = true }
sp-session-validator-management = { workspace = true, features = ["std"] }
pallet-session-validator-management = { workspace = true, features = ["std"] }
subxt = "0.35"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put these on the main cargo.toml on top level - use the workspace syntax { workspace = true }

#[derive(Debug, Serialize, Deserialize)]
pub struct SessionKeyInfo {
pub key_type: String,
pub key_type_bytes: String,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need key_type_bytes

// Step 1: Generate keys using author_rotateKeys RPC via jsonrpsee
context.eprint("⚙️ Calling author_rotateKeys() RPC method...");

let rpc_client = HttpClientBuilder::default()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May not need this - use subxt api

.build(&config.node_url)
.context("Failed to build RPC client")?;

let keys_hex: String = rpc_client
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here - use subxt (online client)

.context("Failed to connect to node")?;

context.eprint("✅ Connected to node successfully");
context.eprint("🔍 Extracting SessionKeys type definition from runtime metadata...");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this step is not needed anymore. We can get ready list by invoking RPC command on the node

Comment on lines 128 to 139
// Step 2: Decode the keys using the extracted type information
context.eprint("🔍 Decoding session keys using runtime type information...");

let decoded_keys = decode_session_keys_from_type_info(&keys_hex, &session_keys_type_info)
.context("Failed to decode session keys using type information")?;

context.eprint(&format!("✅ Successfully decoded {} session keys:", decoded_keys.len()));
for (key_type, key_bytes) in &decoded_keys {
let key_type_str = String::from_utf8_lossy(key_type);
let key_hex = format!("0x{}", hex::encode(key_bytes));
context.eprint(&format!(" • {} key: {}", key_type_str, key_hex));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above, decoding will be done by the node, we have to convert the output to our internal output

Comment on lines 121 to 124
let keys_hex = context
.run_command(&format!("{node_executable} rpc author_rotateKeys --url {}", config.node_url))?
.trim()
.to_string();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use some client module for execution of RPC calls

Comment on lines 147 to 56
/// Extract the actual SessionKeys type definition from runtime metadata
/// This is truly runtime-aware - it reads the actual type definition
fn extract_session_keys_type_from_metadata(
metadata: &subxt::Metadata,
) -> Result<Vec<SessionKeyTypeInfo>> {
// Look for the SessionKeys type in the metadata
let session_keys_type = find_session_keys_type(metadata)
.context("SessionKeys type not found in runtime metadata")?;

// Parse the SessionKeys type definition
parse_session_keys_type(session_keys_type, metadata)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will be done by the node, we don't need it anymore

parse_session_keys_type(session_keys_type, metadata)
}

/// Find the SessionKeys type in the metadata by looking at type paths
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that all the below lines are not needed then

@ladamesny ladamesny self-assigned this Jun 24, 2025
@ladamesny ladamesny force-pushed the feat/automatic-generate-keys branch from d21fec0 to ddf2921 Compare June 24, 2025 15:27
@ladamesny ladamesny marked this pull request as ready for review June 24, 2025 15:27
@ladamesny ladamesny force-pushed the feat/automatic-generate-keys branch from cd4b818 to 2654c45 Compare June 26, 2025 09:15

let mut session_keys = Vec::new();
let mut offset = 0;
let key_types = ["aura", "gran", "imon", "auth"];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code still assumes key types


/// Parse session keys from hex string by splitting into common key lengths
/// Substrate session keys are typically concatenated public keys of fixed lengths
fn parse_session_keys_hex<C: IOContext>(keys_hex: &str, context: &C) -> Vec<SessionKeyInfo> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not parse anything, it is already done by the node

@ladamesny ladamesny force-pushed the feat/automatic-generate-keys branch 5 times, most recently from 8ad297f to ea3b076 Compare July 7, 2025 12:08
@ladamesny ladamesny force-pushed the feat/automatic-generate-keys branch 2 times, most recently from a35816b to c85315d Compare July 8, 2025 22:19
@ladamesny ladamesny requested a review from Klapeyron July 8, 2025 22:37
@ladamesny ladamesny force-pushed the feat/automatic-generate-keys branch from bbbb6ec to 7663893 Compare July 9, 2025 14:11
@ladamesny ladamesny force-pushed the feat/automatic-generate-keys branch from 7663893 to 8b38ac2 Compare July 22, 2025 23:29
@ladamesny ladamesny closed this Jul 22, 2025
@ladamesny ladamesny force-pushed the feat/automatic-generate-keys branch from 8b38ac2 to 9cffa3f Compare July 22, 2025 23:50
@ladamesny
Copy link
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants