Build + tests verde: agent-identity 18 (4 unit + 14 integration) + runtime 27.
Verificacion adversarial ultracode (3 skeptics): 2 confirmed + 1 partial/low,
todos los gaps PRE-EXISTENTES (no introducidos por FIX-3). Invariante "no
puedes registrar un public_key que no controlas" SE SOSTIENE.
FIX-3 (b) DID binding — V3-H1 anti-front-running:
- register_agent_did ahora exige signature: [u8;64] — una firma Ed25519 (por la
private key de public_key) sobre AGENT_DID_REGISTER_DOMAIN || who.encode().
- Verificacion on-chain via sp_io::crypto::ed25519_verify (host function, no
bloatea el wasm). Nuevo dep sp-io (no_std).
- Cierra el front-running: un atacante no puede registrar un public_key ajeno
(no produce la firma); el who en el mensaje ata la firma a este caller (no
replay-able a otra cuenta). Error InvalidSignature. Malleabilidad Ed25519
rechazada por ed25519-zebra (S canonico).
- Una sola fuente de verdad del mensaje (agent_did_register_message) compartida
entre verificador y firmante (evita divergencia tipo postcard-vs-SCALE).
- Orden: idempotency ANTES del verify (no gasta crypto en duplicados).
FIX-3 (c) derive_did domain-sep — V3-H2:
- blake3::derive_key("origin-chain/agent-did/v1", pk) en vez del concat ad-hoc
BLAKE3(pk || version). KDF domain-separado. Inmutable #16 preservado.
Tests: mock con keypairs Ed25519 reales (sp_core::ed25519::Pair) + sign helper.
12 scenarios (scenario_6 reformulado a front-running -> InvalidSignature, +
scenario_11 firma invalida, scenario_12 DID collision genuino del key-holder).
NOTA: la (a) domain-sep del attestation signing payload (el otro tercio de
FIX-3) ya esta cubierta por el DC ORIGIN_ATTESTATION_SIGNING_PAYLOAD_V1 (helper
de Ergon attestation_signed_message), pendiente su ship Cap 45+.
FOLLOW-UPS (low, pre-existentes, no bloquean):
- (a) anadir genesis_hash/chain-id al mensaje de registro (hardening cross-chain
replay) — ideal chain-wide junto al signing_payload de attestation.
- (b) DC para ratificar el modelo de autoridad Hybrid (quien firma) + si los
co_authors requieren prueba de consentimiento (lineage hoy no autenticado).
- (c) weight benchmarking real que contabilice el ed25519_verify (chain-wide,
post-testnet — ya en roadmap FIX-2 weights).
- creator = AccountId::new(public_key) (la cuenta del key-holder, no el caller):
coherente con el binding, semantica documentada.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
105 lines
3.4 KiB
Rust
105 lines
3.4 KiB
Rust
//! # Mock runtime canonical para integration tests v0.0.26
|
|
//!
|
|
//! Pattern v0.0.18 (Provenance) + v0.0.22 (Fees) mirror — construct_runtime! +
|
|
//! derive_impl + new_test_ext + helpers canonical.
|
|
|
|
#![cfg(test)]
|
|
|
|
use crate as origin_chain_agent_identity;
|
|
use frame_support::derive_impl;
|
|
use sp_core::{ed25519, Pair};
|
|
use sp_runtime::BuildStorage;
|
|
|
|
/// Mock block type canonical para tests.
|
|
type Block = frame_system::mocking::MockBlock<Test>;
|
|
|
|
frame_support::construct_runtime!(
|
|
pub enum Test {
|
|
System: frame_system,
|
|
AgentIdentity: origin_chain_agent_identity,
|
|
}
|
|
);
|
|
|
|
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
|
impl frame_system::Config for Test {
|
|
type Block = Block;
|
|
type AccountId = sp_runtime::AccountId32;
|
|
type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>;
|
|
}
|
|
|
|
impl origin_chain_agent_identity::Config for Test {
|
|
type RuntimeEvent = RuntimeEvent;
|
|
}
|
|
|
|
/// Test externalities builder canonical (pattern v0.0.18/v0.0.22 mirror).
|
|
pub fn new_test_ext() -> sp_io::TestExternalities {
|
|
let mut ext: sp_io::TestExternalities = frame_system::GenesisConfig::<Test>::default()
|
|
.build_storage()
|
|
.expect("genesis canonical builds")
|
|
.into();
|
|
ext.execute_with(|| {
|
|
System::set_block_number(1);
|
|
});
|
|
ext
|
|
}
|
|
|
|
/// Test origin canonical ALICE.
|
|
pub fn alice_origin() -> RuntimeOrigin {
|
|
RuntimeOrigin::signed(sp_runtime::AccountId32::new([1u8; 32]))
|
|
}
|
|
|
|
/// Test account canonical ALICE (AccountId32 value para storage assertions).
|
|
pub fn alice_account() -> sp_runtime::AccountId32 {
|
|
sp_runtime::AccountId32::new([1u8; 32])
|
|
}
|
|
|
|
/// Test origin canonical BOB.
|
|
pub fn bob_origin() -> RuntimeOrigin {
|
|
RuntimeOrigin::signed(sp_runtime::AccountId32::new([2u8; 32]))
|
|
}
|
|
|
|
/// Test account canonical BOB.
|
|
pub fn bob_account() -> sp_runtime::AccountId32 {
|
|
sp_runtime::AccountId32::new([2u8; 32])
|
|
}
|
|
|
|
// ─── Ed25519 keypairs canonical (FIX-3 V3-H1 DID binding) ──────────────
|
|
// Pairs reales desde seeds → pubkeys reales + firmas verificables. Reemplaza
|
|
// los pubkeys-bytes-arbitrarios previos (sin private key, incapaces de firmar el
|
|
// binding del registro).
|
|
|
|
/// Ed25519 pair canonical ALICE (agent identity key).
|
|
pub fn alice_pair() -> ed25519::Pair {
|
|
ed25519::Pair::from_seed(&[0x11u8; 32])
|
|
}
|
|
/// Ed25519 pair canonical BOB.
|
|
pub fn bob_pair() -> ed25519::Pair {
|
|
ed25519::Pair::from_seed(&[0x22u8; 32])
|
|
}
|
|
/// Ed25519 pair canonical CHARLIE (Hybrid co-author lineage).
|
|
pub fn charlie_pair() -> ed25519::Pair {
|
|
ed25519::Pair::from_seed(&[0x33u8; 32])
|
|
}
|
|
|
|
/// Public key bytes canonical ALICE (derivado del pair real).
|
|
pub fn alice_pubkey() -> [u8; 32] {
|
|
alice_pair().public().0
|
|
}
|
|
/// Public key bytes canonical BOB.
|
|
pub fn bob_pubkey() -> [u8; 32] {
|
|
bob_pair().public().0
|
|
}
|
|
/// Public key bytes canonical CHARLIE.
|
|
pub fn charlie_pubkey() -> [u8; 32] {
|
|
charlie_pair().public().0
|
|
}
|
|
|
|
/// Firma de binding canonical (FIX-3 (b)): el holder de `pair` firma el mensaje
|
|
/// de registro `AGENT_DID_REGISTER_DOMAIN || who.encode()` → prueba control de la
|
|
/// key. Usa el MISMO builder de mensaje que el pallet (una fuente de verdad).
|
|
pub fn sign_registration(pair: &ed25519::Pair, who: &sp_runtime::AccountId32) -> [u8; 64] {
|
|
use parity_scale_codec::Encode;
|
|
let msg = origin_chain_agent_identity::agent_did_register_message(&who.encode());
|
|
pair.sign(&msg).0
|
|
}
|