feat(node): Origin Chain produce su primer bloque — el bloqueo arquitectural era un diagnostico falso
El node nunca habia producido un bloque: service.rs y rpc.rs estaban fuera del build desde v0.0.49 por un «bloqueo arquitectural» que afirmaba que las crates publicadas sc-consensus-aura 0.52.0 y sp-consensus-aura 0.45.0 no tenian standalone::slot_duration_at ni from_timestamp_and_slot_duration. Las dos estan ahi, en crates.io. La nota guio la decision durante meses. Causa real, medida con cargo check (362 errores) y cargo tree: el workspace mezclaba dos releases de polkadot-sdk. Las sc-* del cliente arrastraban sp-runtime 43 y las frame-* del runtime sp-runtime 44: 36 crates del nucleo duplicadas y errores de la forma «Block no satisface Block». Cura: alinear diez versiones del Cargo.toml (sc-cli 0.55, sc-service 0.54, sc-network 0.53, sc-consensus 0.52, sc-consensus-aura 0.53, sc-consensus-grandpa 0.38, sc-offchain 48, sp-blockchain 42, substrate-frame-rpc-system 47, sc-telemetry 30.0.1). El lock solo PIERDE la generacion vieja (1210 -> 1123 entradas); ninguna crate que use el runtime cambia de version. rpc.rs: el client pasa a ser el FullClient concreto. Nuestro node trabaja sobre el Block completo del runtime, que lleva dentro ChainAccountId, una proyeccion (<<MultiSignature as Verify>::Signer as IdentifyAccount>::AccountId) que rustc no normaliza dentro de un where-clause generico: 6 errores de «un bound declarado en la firma no se satisface». Con el generico fallaba, con el concreto compila. main.rs: subcomando run (sc_cli::RunCmd), que arranca new_full con litep2p o libp2p. chain_spec.rs: node_chain_spec construye un GenericChainSpec con el WASM real del runtime (build-spec sigue con su JSON). run --chain mainnet se RECHAZA: sus validadores son placeholder sin llave (gate L-3) y un node con ese genesis no produciria nunca, en silencio. Test con contrafactual: sin el brazo mainnet el id cae en la rama de ruta y falla como «fichero no encontrado»; el test exige la razon, y en rojo lo dijo asi. Medido (build con --features wasm-build, run --dev --tmp): - bloque #1 importado 2026-09-23 20:04:30, uno cada ~6 s (Aura); - GRANDPA finaliza: #7 finalizado con best #9 a los 60 s; - RPC: chain_getHeader, chain_getFinalizedHead, system_accountNextIndex (Alice = 0) y system_properties (OGC, 18 decimales, ss58 42) responden; - «Essential task txpool-background failed» aparece SOLO al SIGINT (0 ocurrencias a los 50 s con RPC servido; 1 al segundo del SIGINT). - cargo test --workspace: 318 passed, 0 failed (igual que RV14) + 1 nuevo. macOS 27: el build necesita DEVELOPER_DIR=/Library/Developer/CommandLineTools mientras la licencia de Xcode 27 no este aceptada (exit 69 en cc y git). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
defd3fa580
commit
63918f365b
6 files changed
+681
-1696
No files matched your search
@@ -181,13 +181,71 @@ pub fn load_spec(name: &str) -> Result<Value, String> {
|
||||
}
|
||||
}
|
||||
|
||||
/// El chain spec del node: sin extensiones (sin relay chain ni fork blocks).
|
||||
type NodeChainSpec = sc_service::GenericChainSpec;
|
||||
|
||||
/// ChainSpec REAL para `origin-chain-node run`: el WASM verdadero del runtime y el
|
||||
/// genesis de sus presets, construido con `sc_service::GenericChainSpec`.
|
||||
///
|
||||
/// Es distinto de [`load_spec`], que sigue sirviendo a `build-spec` con el JSON
|
||||
/// armado a mano y `code: "0x"`. Con ese `code` vacío ningún node puede ejecutar
|
||||
/// el bloque génesis; con éste sí.
|
||||
///
|
||||
/// Acepta `dev` / `local` o la RUTA a un chain spec JSON. `mainnet` se rechaza a
|
||||
/// propósito: sus validadores son llaves placeholder `CA FE 00…04…` que nadie posee
|
||||
/// (gate L-3 de `docs/ORIGIN_CHAIN_LISTA_PARA_LANZAR_V1.md` del monorepo) — un node
|
||||
/// arrancado con ese génesis no produciría un bloque jamás, y lo haría en silencio.
|
||||
pub fn node_chain_spec(id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
|
||||
let (name, chain_id, chain_type, preset) = match id {
|
||||
"" | "dev" | "development" => (
|
||||
"Origin Chain Development",
|
||||
CHAIN_ID_DEVELOPMENT,
|
||||
sc_service::ChainType::Development,
|
||||
genesis_config_presets::PRESET_DEVELOPMENT,
|
||||
),
|
||||
"local" | "local_testnet" => (
|
||||
"Origin Chain Local Testnet",
|
||||
CHAIN_ID_LOCAL_TESTNET,
|
||||
sc_service::ChainType::Local,
|
||||
genesis_config_presets::PRESET_LOCAL_TESTNET,
|
||||
),
|
||||
"mainnet" | "mainnet_genesis" => {
|
||||
return Err(
|
||||
"el génesis de mainnet aún tiene validadores placeholder sin llave \
|
||||
(gate L-3): no se arranca un node con él. Genera el chain spec \
|
||||
con las llaves reales y pásalo como ruta a --chain."
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
path => {
|
||||
return NodeChainSpec::from_json_file(path.into())
|
||||
.map(|spec| Box::new(spec) as Box<dyn sc_service::ChainSpec>)
|
||||
}
|
||||
};
|
||||
let wasm = origin_chain_runtime::WASM_BINARY.ok_or_else(|| {
|
||||
"este binario se compiló sin el WASM del runtime: \
|
||||
cargo build -p origin-chain-node --features wasm-build"
|
||||
.to_string()
|
||||
})?;
|
||||
let properties = chain_properties().as_object().cloned().unwrap_or_default();
|
||||
Ok(Box::new(
|
||||
NodeChainSpec::builder(wasm, None)
|
||||
.with_name(name)
|
||||
.with_id(chain_id)
|
||||
.with_chain_type(chain_type)
|
||||
.with_protocol_id(PROTOCOL_ID)
|
||||
.with_properties(properties)
|
||||
.with_genesis_config_preset_name(preset)
|
||||
.build(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Serialize chain spec canonical a JSON string canonical (pretty o raw canonical).
|
||||
pub fn serialize_chain_spec(spec: &Value, raw: bool) -> Result<String, String> {
|
||||
if raw {
|
||||
serde_json::to_string(spec).map_err(|e| format!("JSON serialization canonical: {e}"))
|
||||
} else {
|
||||
serde_json::to_string_pretty(spec)
|
||||
.map_err(|e| format!("JSON serialization canonical: {e}"))
|
||||
serde_json::to_string_pretty(spec).map_err(|e| format!("JSON serialization canonical: {e}"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +253,21 @@ pub fn serialize_chain_spec(spec: &Value, raw: bool) -> Result<String, String> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// `run --chain mainnet` se rechaza POR EL GÉNESIS, no por casualidad. Sin el
|
||||
/// brazo `mainnet`, el id caería en la rama de ruta y también fallaría — como
|
||||
/// «fichero no encontrado». Por eso el test exige la razón (gate L-3) y no sólo
|
||||
/// el error: sin ella pasaría con y sin la salvaguarda.
|
||||
#[test]
|
||||
fn run_rechaza_el_genesis_de_mainnet_con_validadores_placeholder() {
|
||||
for id in ["mainnet", "mainnet_genesis"] {
|
||||
let err = node_chain_spec(id).err().expect("mainnet debe rechazarse");
|
||||
assert!(
|
||||
err.contains("gate L-3"),
|
||||
"{id}: rechazado por otra razón: {err}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn development_chain_spec_builds_canonical() {
|
||||
let spec = development_chain_spec().expect("development chain spec canonical");
|
||||
|
||||
Reference in new issue
Block a user