-
Notifications
You must be signed in to change notification settings - Fork 0
Add user_registry contract and AuthApi RPC for DID-to-account linking #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Implements RPC endpoint for verifying JWTs issued by authnz-rs, enabling integration between the authentication service and the Substrate node. Features: - New RPC endpoint: arkavo_verifyAuthToken(jwt: String) - JWT verification using ES256 (ECDSA P-256) signatures - Public key loaded from AUTHNZ_PUBLIC_KEY_PATH env variable - Returns AuthTokenInfo with validity, user_id, error, and expiration Dependencies added: - jsonwebtoken v9 for JWT parsing and verification - log v0.4 for logging 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Adds new RPC method to support transactional account creation between authnz-rs and arkavo-node. New endpoint: arkavo_linkAccountWithProof(jwt, did, address) - Verifies JWT signature using ES256 - Validates DID format (must start with did:key:) - Validates address format (0x + 40 hex chars) - Verifies DID and address match JWT claims - Returns LinkAccountResult with success/error status This enables authnz-rs to make a backchannel RPC call after successful registration to ensure the DID-to-address binding is recorded on-chain atomically with the passkey registration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
…king - Update workspace edition from 2021 to 2024 - Add user_registry ink! contract with link_account() and link_account_for() - Implement contract call in arkavo_linkAccountWithProof RPC endpoint - RPC now calls user_registry.link_account_for() via pallet-revive runtime API - Configure via USER_REGISTRY_ADDRESS and USER_REGISTRY_OWNER env vars - Update deployer README with user_registry deployment and RPC integration docs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comprehensive PR Review: Add user_registry contract and AuthApi RPC for DID-to-account linking
PR #24 | Branch: feature/auth-api-rpc | Author: Paul Flynn (@arkavo-com)
Executive Summary
This PR introduces a well-architected DID-to-account linking system consisting of:
- A new
user_registryink! smart contract for permanent DID-to-address bindings - An RPC endpoint (
arkavo_linkAccountWithProof) for secure backchannel account linking - Comprehensive documentation and deployment guides
Overall Assessment: ✅ APPROVE WITH MINOR RECOMMENDATIONS
The implementation demonstrates solid engineering practices with proper access control, comprehensive testing, and clear documentation. The code quality is high, with appropriate error handling and validation. A few minor improvements are recommended before merging, primarily around documentation clarity and potential edge case handling.
Key Strengths:
- Clean, well-documented contract code with comprehensive test coverage (11 tests)
- Proper separation of concerns between contract and RPC layers
- Strong input validation and error handling
- Excellent documentation in README
- Appropriate use of permanent bindings for security-critical operations
Areas for Improvement:
- Minor documentation enhancements needed
- Some edge cases could be better documented
- Consider adding integration tests
- Gas optimization opportunities exist
Detailed Findings
1. CODE QUALITY
1.1 Smart Contract Architecture (contracts/user_registry/lib.rs)
Severity: ✅ EXCELLENT
Positive Observations:
- Clean separation of concerns with
do_link()internal method - Proper use of ink! storage patterns with
Mapping - Well-structured error types with clear semantics
- Appropriate use of events for off-chain monitoring
- Good use of validation methods (
validate_did())
Findings:
Minor - Line 106: Counter overflow protection
self.total_linked = self.total_linked.saturating_add(1);✅ Good: Uses saturating_add to prevent overflow. However, consider documenting the maximum expected number of linked accounts.
Recommendation: Add a comment explaining the expected scale:
// Increment counter (saturating to prevent overflow at u32::MAX)
// Note: At 1 link/second, would take 136 years to overflow
self.total_linked = self.total_linked.saturating_add(1);Minor - Line 78-82: DID validation could be more comprehensive
fn validate_did(&self, did: &str) -> Result<()> {
if did.is_empty() {
return Err(Error::EmptyDid);
}
if !did.starts_with("did:key:") {
return Err(Error::InvalidDidFormat);
}
Ok(())
}Recommendation: Consider adding length validation to prevent extremely long DIDs:
fn validate_did(&self, did: &str) -> Result<()> {
if did.is_empty() {
return Err(Error::EmptyDid);
}
if !did.starts_with("did:key:") {
return Err(Error::InvalidDidFormat);
}
// Prevent DoS via extremely long DIDs (typical did:key is ~60 chars)
if did.len() > 256 {
return Err(Error::InvalidDidFormat);
}
Ok(())
}1.2 RPC Implementation (node/src/rpc.rs)
Severity: ✅ EXCELLENT
Positive Observations:
- Comprehensive input validation (UUID, H160, DID format)
- Proper error handling with descriptive messages
- Good logging for debugging and monitoring
- Clean separation of encoding logic
- Appropriate use of runtime API
Findings:
Minor - Line 133-143: Selector computation
let selector: [u8; 4] = {
use sp_core::hashing::blake2_256;
let hash = blake2_256(b"link_account_for");
[hash[0], hash[1], hash[2], hash[3]]
};Recommendation: Add a compile-time test to verify the selector matches the contract:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_link_account_for_selector() {
use sp_core::hashing::blake2_256;
let hash = blake2_256(b"link_account_for");
let selector = [hash[0], hash[1], hash[2], hash[3]];
// This should match the selector in the deployed contract
// Update this value after contract deployment
assert_eq!(selector, [0x??, 0x??, 0x??, 0x??]);
}
}Suggestion - Line 155-165: Address parsing
The parse_h160 function is well-implemented. Consider extracting it to a shared utility module if other RPC methods need similar functionality.
Minor - Line 283-294: Error decoding
fn decode_contract_error(data: &[u8]) -> String {
if data.is_empty() {
return "Unknown contract error (empty data)".to_string();
}
match data[0] {
0 => "DID is already linked to another account".to_string(),
1 => "Account is already linked to a DID".to_string(),
// ...
}
}Recommendation: Add a comment linking to the contract's Error enum definition to maintain synchronization:
/// Decode contract error from return data
/// Must match the Error enum in contracts/user_registry/lib.rs:
/// 0 = DidAlreadyLinked
/// 1 = AccountAlreadyLinked
/// 2 = InvalidDidFormat
/// 3 = EmptyDid
/// 4 = NotOwner
fn decode_contract_error(data: &[u8]) -> String {1.3 Code Organization
Severity: ✅ GOOD
Positive Observations:
- Clear module structure
- Appropriate use of workspace dependencies
- Good separation between contracts and node code
Suggestion: Consider adding a CHANGELOG.md entry for this significant feature addition.
2. TESTING
2.1 Unit Test Coverage (contracts/user_registry/lib.rs)
Severity: ✅ EXCELLENT
Test Coverage Analysis:
- ✅ 11 comprehensive unit tests
- ✅ Tests cover happy paths and error cases
- ✅ Tests verify access control (owner vs non-owner)
- ✅ Tests check duplicate prevention
- ✅ Tests validate input validation
Test Cases Covered:
new_works- Constructor initializationlink_account_works- Self-linking successlink_account_for_works- Owner-linking successlink_account_for_rejects_non_owner- Access controllink_account_rejects_empty_did- Input validationlink_account_rejects_invalid_did_format- Format validationlink_account_rejects_duplicate_did- Duplicate DID preventionlink_account_rejects_duplicate_account- Duplicate account preventionmultiple_accounts_can_link- Multiple usersis_did_linked_works- Query functionalityget_returns_none_for_unlinked- Query edge cases
Recommendation - Missing Test Cases:
Major: Add edge case tests:
#[ink::test]
fn link_account_with_maximum_length_did() {
// Test with a very long (but valid) DID
let mut contract = UserRegistry::new();
let long_did = format!("did:key:{}", "z".repeat(200));
// Should this succeed or fail? Define the behavior.
}
#[ink::test]
fn link_account_with_special_characters_in_did() {
// Test DID with unicode or special characters
let mut contract = UserRegistry::new();
let did = String::from("did:key:z6Mk🔑test");
// Define expected behavior
}2.2 Integration Tests
Severity: MAJOR - Missing
Finding: No integration tests exist for the RPC endpoint calling the contract.
Recommendation: Add integration tests in node/src/rpc.rs:
#[cfg(test)]
mod integration_tests {
use super::*;
// Test the full flow:
// 1. Deploy contract
// 2. Configure RPC with contract address
// 3. Call link_account_with_proof
// 4. Verify on-chain state
#[test]
fn test_rpc_to_contract_integration() {
// Implementation needed
}
}2.3 RPC Tests
Severity: MAJOR - Missing
Finding: No unit tests for RPC methods.
Recommendation: Add tests for:
- Input validation (UUID, H160, DID format)
- Error handling paths
- Selector encoding
- Error decoding
3. DOCUMENTATION
3.1 Code Documentation
Severity: ✅ EXCELLENT
Positive Observations:
- Comprehensive doc comments on all public methods
- Clear explanation of contract behavior
- Good use of
# Argumentsand# Errorssections - Module-level documentation explains the purpose
Minor Improvements:
Line 8-16: Contract-level documentation is excellent. Consider adding:
/// # Security Model
/// - One-to-one permanent bindings (no updates or deletions)
/// - Owner can link on behalf of users (for RPC backchannel)
/// - DID format validation (must start with "did:key:")
/// - No token transfers or value handling
///
/// # Gas Considerations
/// - `link_account`: ~X gas (TODO: benchmark)
/// - `get_account_by_did`: ~Y gas (TODO: benchmark)
3.2 README Documentation (tools/deployer/README.md)
Severity: ✅ EXCELLENT
Positive Observations:
- Comprehensive deployment guide
- Clear step-by-step instructions
- Good examples with actual commands
- Troubleshooting section included
- RPC integration instructions
Minor Improvements:
Suggestion: Add a "Quick Start" section at the top:
## Quick Start
For the impatient, here's the minimal deployment:
```bash
# 1. Build contract
cd contracts && cargo contract build --manifest-path user_registry/Cargo.toml
# 2. Deploy
cargo contract instantiate --url ws://localhost:9944 --suri //Alice \
--constructor new --skip-confirm --execute \
contracts/target/ink/user_registry/user_registry.contract
# 3. Configure node
export USER_REGISTRY_ADDRESS=0x...
export USER_REGISTRY_OWNER=5GrwvaEF...
./target/release/arkavo-node --devFor detailed instructions, see below.
#### 3.3 API Documentation
**Severity:** **MINOR** - Could be improved
**Recommendation:** Add OpenAPI/JSON-RPC schema documentation for the RPC endpoint:
Create `docs/rpc-api.md`:
```markdown
# Arkavo RPC API
## arkavo_linkAccountWithProof
Links a DID to a blockchain address after WebAuthn registration.
### Request
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "arkavo_linkAccountWithProof",
"params": {
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"address": "0x0101010101010101010101010101010101010101"
}
}
Response (Success)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"success": true,
"did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"address": "0x0101010101010101010101010101010101010101",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"error": null
}
}Error Codes
| Error | Description |
|---|---|
| Invalid user_id | user_id is not a valid UUID |
| Invalid address format | address is not 0x-prefixed 20-byte hex |
| Invalid DID format | DID doesn't start with 'did:key:' |
| DID already linked | DID is already linked to another account |
| Account already linked | Account is already linked to a DID |
| Contract not configured | USER_REGISTRY_ADDRESS not set |
---
### 4. PERFORMANCE
#### 4.1 Gas Optimization
**Severity:** **MINOR** - Optimization opportunities
**Finding - Line 99-106:** Storage operations
```rust
// Check if DID is already linked
if self.did_to_account.contains(&did) {
return Err(Error::DidAlreadyLinked);
}
// Check if account is already linked
if self.account_to_did.contains(account) {
return Err(Error::AccountAlreadyLinked);
}
Recommendation: The current implementation is correct but performs 4 storage reads in the worst case (2 contains + 2 inserts). Consider documenting the gas cost:
// Gas cost: 2 storage reads (contains) + 2 storage writes (insert)
// Estimated: ~X gas for new link, ~Y gas for duplicate rejection4.2 String Storage
Severity: MINOR - Consider optimization
Finding: DIDs are stored as String which is heap-allocated.
Analysis: For typical did:key: identifiers (~60 chars), this is reasonable. However, if gas optimization is critical, consider:
Option 1: Store hash instead of full DID (breaking change):
// Store blake2_256 hash of DID instead of full string
did_hash_to_account: Mapping<[u8; 32], Address>,Option 2: Document the trade-off:
/// Note: DIDs are stored as full strings for readability and debugging.
/// For gas optimization, consider storing hashes in future versions.
Recommendation: Keep current implementation (full string storage) as it provides better developer experience and debugging capability. Document the trade-off.
4.3 RPC Performance
Severity: ✅ GOOD
Positive Observations:
- Efficient encoding without unnecessary allocations
- Proper use of runtime API (no unnecessary RPC calls)
- Good error handling without performance overhead
5. BEST PRACTICES
5.1 Rust/ink! Conventions
Severity: ✅ EXCELLENT
Positive Observations:
- ✅ Proper use of
#[ink(storage)],#[ink(message)],#[ink(event)] - ✅ Correct error handling with
Result<T, Error> - ✅ Appropriate use of
Mappingfor storage - ✅ Good use of
#[ink(topic)]for event indexing - ✅ Proper
Defaultimplementation - ✅ Correct use of
scale::Encodeandscale::Decode
Minor - Line 60: Consider implementing Display for Error:
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Error::DidAlreadyLinked => write!(f, "DID is already linked to another account"),
Error::AccountAlreadyLinked => write!(f, "Account is already linked to a DID"),
Error::InvalidDidFormat => write!(f, "Invalid DID format"),
Error::EmptyDid => write!(f, "DID cannot be empty"),
Error::NotOwner => write!(f, "Only the contract owner can perform this action"),
}
}
}5.2 Substrate/Polkadot SDK Conventions
Severity: ✅ EXCELLENT
Positive Observations:
- ✅ Proper use of workspace dependencies
- ✅ Correct edition (2024) usage
- ✅ Appropriate use of runtime API
- ✅ Good integration with pallet-revive
5.3 Security Best Practices
Severity: ✅ EXCELLENT
Positive Observations:
- ✅ Proper access control (owner-only methods)
- ✅ Input validation (DID format, UUID, H160)
- ✅ Permanent bindings (no update/delete)
- ✅ No reentrancy concerns (no external calls)
- ✅ No token handling (no value transfer)
Note: Security review already completed separately - no additional security concerns identified.
6. ERROR HANDLING
6.1 Contract Error Handling
Severity: ✅ EXCELLENT
Positive Observations:
- Comprehensive error types covering all failure cases
- Proper use of
Result<T, Error>pattern - Clear error messages
- Appropriate error propagation
6.2 RPC Error Handling
Severity: ✅ EXCELLENT
Positive Observations:
- Graceful handling of missing configuration
- Proper validation before contract calls
- Descriptive error messages in responses
- Good logging for debugging
Minor Improvement - Line 218-228: Consider adding error codes:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LinkAccountResult {
pub success: bool,
pub did: Option<String>,
pub address: Option<String>,
pub user_id: Option<String>,
pub error: Option<String>,
pub error_code: Option<String>, // Add error codes for programmatic handling
}
// Error codes: "INVALID_UUID", "INVALID_ADDRESS", "INVALID_DID",
// "DID_ALREADY_LINKED", "ACCOUNT_ALREADY_LINKED", etc.7. BREAKING CHANGES
7.1 API Compatibility
Severity: ✅ NO BREAKING CHANGES
Analysis:
- ✅ New RPC endpoint (additive change)
- ✅ New contract (no existing contracts affected)
- ✅ Workspace edition update (2021 → 2024) is compatible
- ✅ No changes to existing RPC methods
- ✅ No changes to runtime APIs (only additions)
Note: The workspace edition update from 2021 to 2024 is a forward-compatible change and should not break existing code.
7.2 Configuration Changes
Severity: MINOR - New environment variables required
Finding: New environment variables required for RPC functionality:
USER_REGISTRY_ADDRESS(H160 format)USER_REGISTRY_OWNER(SS58 format)
Recommendation: Document in migration guide:
## Migration Guide
### New Environment Variables
To enable DID-to-account linking, set these environment variables:
```bash
export USER_REGISTRY_ADDRESS=0x... # Deployed contract address
export USER_REGISTRY_OWNER=5Grw... # Contract owner accountIf not set, the RPC endpoint will return an error but the node will continue to function normally.
---
## Positive Observations
### What Was Done Well ✨
1. **Excellent Test Coverage**
- 11 comprehensive unit tests covering all major paths
- Good balance of positive and negative test cases
- Clear test names and assertions
2. **Outstanding Documentation**
- Comprehensive README with deployment instructions
- Clear code comments explaining intent
- Good examples and troubleshooting guide
3. **Clean Architecture**
- Proper separation of concerns (contract vs RPC)
- Well-structured error handling
- Good use of internal helper methods
4. **Security-First Design**
- Permanent bindings prevent tampering
- Proper access control implementation
- Comprehensive input validation
5. **Developer Experience**
- Clear error messages
- Good logging for debugging
- Helpful deployment guide
6. **Code Quality**
- Consistent formatting
- No clippy warnings (based on workspace lints)
- Good use of Rust idioms
---
## Recommendations
### Priority: CRITICAL
*None identified* ✅
### Priority: MAJOR
1. **Add Integration Tests**
- **File:** `node/src/rpc.rs`
- **Action:** Add integration tests for RPC-to-contract flow
- **Rationale:** Ensure end-to-end functionality works correctly
- **Effort:** Medium (2-4 hours)
2. **Add RPC Unit Tests**
- **File:** `node/src/rpc.rs`
- **Action:** Add unit tests for input validation and error handling
- **Rationale:** Improve test coverage for RPC layer
- **Effort:** Medium (2-3 hours)
### Priority: MINOR
3. **Add DID Length Validation**
- **File:** `contracts/user_registry/lib.rs`, Line 78-82
- **Action:** Add maximum length check to prevent DoS
- **Rationale:** Prevent extremely long DIDs from consuming excessive storage
- **Effort:** Low (15 minutes)
4. **Document Gas Costs**
- **File:** `contracts/user_registry/lib.rs`
- **Action:** Add gas cost estimates to contract documentation
- **Rationale:** Help users understand transaction costs
- **Effort:** Low (30 minutes, requires benchmarking)
5. **Add Error Codes to RPC Response**
- **File:** `node/src/rpc.rs`, Line 218-228
- **Action:** Add `error_code` field for programmatic error handling
- **Rationale:** Easier for clients to handle specific errors
- **Effort:** Low (30 minutes)
6. **Create API Documentation**
- **File:** New file `docs/rpc-api.md`
- **Action:** Create OpenAPI/JSON-RPC schema documentation
- **Rationale:** Better developer experience for API consumers
- **Effort:** Low (1 hour)
### Priority: SUGGESTION
7. **Add Selector Verification Test**
- **File:** `node/src/rpc.rs`
- **Action:** Add compile-time test to verify selector matches contract
- **Rationale:** Prevent selector mismatch bugs
- **Effort:** Low (15 minutes)
8. **Add Quick Start Section**
- **File:** `tools/deployer/README.md`
- **Action:** Add quick start section at the top
- **Rationale:** Faster onboarding for developers
- **Effort:** Low (15 minutes)
9. **Add CHANGELOG Entry**
- **File:** `CHANGELOG.md` (create if doesn't exist)
- **Action:** Document this feature addition
- **Rationale:** Track changes for users and developers
- **Effort:** Low (10 minutes)
10. **Consider Display Implementation for Error**
- **File:** `contracts/user_registry/lib.rs`
- **Action:** Implement `Display` trait for `Error` enum
- **Rationale:** Better error formatting in logs
- **Effort:** Low (10 minutes)
---
## Merge Recommendation
**Status:** ✅ **APPROVE WITH MINOR RECOMMENDATIONS**
This PR is well-implemented and ready to merge. The code quality is high, testing is comprehensive, and documentation is excellent. The recommended improvements are minor and can be addressed in follow-up PRs if needed.
### Before Merging (Optional but Recommended):
1. Add integration tests (MAJOR priority)
2. Add RPC unit tests (MAJOR priority)
3. Add DID length validation (MINOR priority)
### Can Be Addressed in Follow-up PRs:
- Gas cost documentation
- Error codes in RPC response
- API documentation
- All SUGGESTION priority items
---
## Summary Statistics
- **Files Changed:** 14
- **Lines Added:** 922
- **Lines Deleted:** 64
- **Net Change:** +858 lines
- **Test Coverage:** 11 unit tests (contract), 0 integration tests
- **Documentation:** Excellent (README, code comments)
- **Critical Issues:** 0
- **Major Issues:** 2 (missing tests)
- **Minor Issues:** 5
- **Suggestions:** 5
---
**Reviewed by:** SuperNinja AI Agent
**Review Date:** 2025-12-06
**Review Type:** Comprehensive Code Quality Review (Security review completed separately)
- Remove jsonwebtoken and p256 dependencies (declared but never used) - Add 10 unit tests for auth_api RPC helpers: - encode_link_account_for: selector and SCALE encoding verification - parse_h160: valid/invalid address parsing - decode_contract_error: all error variants 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Contract changes (user_registry): - Add MAX_DID_LENGTH (256 bytes) to prevent DoS via excessive storage - Add DidTooLong error variant with length validation - Implement Display trait for Error enum for better logging - Add test for DID length validation RPC changes (node/src/rpc.rs): - Add error_code field to LinkAccountResult for programmatic handling - Return structured ContractError with both message and code - Add error codes: INVALID_UUID, INVALID_ADDRESS, INVALID_DID_FORMAT, CONTRACT_NOT_CONFIGURED, DID_ALREADY_LINKED, ACCOUNT_ALREADY_LINKED, DID_TOO_LONG, NOT_OWNER, CONTRACT_EXECUTION_FAILED, RUNTIME_ERROR - Update tests for new error structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add .github/workflows/version-check.yaml to enforce version bumps when node/src/ or runtime/src/ source files change on PRs to main. The workflow: - Runs on PRs to main when relevant paths change - Skips check if component is new (doesn't exist on main) - Fails if node or runtime source changes without version bump - Warns (but doesn't fail) for contract version changes - Provides summary in GitHub Actions UI Version bumps only required when modifying existing code on main, not for new components introduced in a feature branch. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
e88f06c to
6e1bb03
Compare
MINOR version bump for new features: - arkavo-node 0.1.0 -> 0.2.0: AuthApi RPC with error codes - arkavo-runtime 0.1.0 -> 0.2.0: ReviveApi integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Enables secure WebSocket connections (wss://) directly in the node, eliminating the need for a TLS-terminating reverse proxy like HAProxy. New CLI arguments: - --rpc-tls-cert <PATH> Path to TLS certificate (PEM format) - --rpc-tls-key <PATH> Path to TLS private key (PEM format) - --rpc-tls-port <PORT> Port for TLS server (default: 9945) - --rpc-tls-addr <ADDR> Bind address (default: 0.0.0.0) Implementation uses tokio-rustls for async TLS, serving the same RPC methods as the standard HTTP/WS server. The TLS server injects DenyUnsafe to safely handle subscription methods. Tested with Polkadot.js Apps at wss://chain.arkavo.net 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace unmaintained rustls-pemfile crate (RUSTSEC-2025-0134) with the PemObject trait from rustls-pki-types, which includes the same PEM parsing functionality since version 1.9.0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
The aws-lc-sys crate (brought in by polkadot-sdk via rustls) uses the OpenSSL license. This fixes the cargo deny check licenses failure. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Summary
user_registryink! smart contract for permanent DID-to-account bindingsarkavo_linkAccountWithProof(user_id, did, address)for account linkingArchitecture
user_registry Contract
Permanent one-to-one DID-to-address bindings:
link_account(did)- User self-links their addresslink_account_for(did, address)- Owner-only, for RPC backchannelget_account_by_did(did)- Lookup address by DIDget_did_by_account(address)- Lookup DID by addressis_linked(address)/is_did_linked(did)- Check if linkedRPC Endpoint
arkavo_linkAccountWithProof
Links a DID to a blockchain address (called by authnz-rs after WebAuthn registration).
TLS RPC Server
Native TLS support for secure WebSocket connections, eliminating the need for a reverse proxy.
New CLI arguments:
--rpc-tls-cert <PATH>- Path to TLS certificate (PEM format)--rpc-tls-key <PATH>- Path to TLS private key (PEM format)--rpc-tls-port <PORT>- Port for TLS server (default: 9945)--rpc-tls-addr <ADDR>- Bind address (default: 0.0.0.0)Example usage:
Connect via Polkadot.js Apps:
https://polkadot.js.org/apps/?rpc=wss://chain.arkavo.net#/explorer
Configuration
Set environment variables before starting the node:
Related PRs
Test plan
🤖 Generated with Claude Code