feat(revive): v0.0.37 — pallet-revive workspace scaffold + ChainAction Phase 3 extension 🎉

Phase 3 Slice 3.1 Ship 1 SCAFFOLD shipped. Path A inicio post sesión 3+
extended histórica (35 ships v0.0.1→v0.0.36 + Slice 2e WASM RESUELTO). David
autorizó "vamos con todas en orden desde A" — pallet-revive smart contracts
PolkaVM RISC-V + ink! v6 + Solidity per SBS-5 ratificado (supersedes CHN-6 v1.0).

Cambios:
- Cargo.toml workspace.dependencies: pallet-revive 0.12.2 + pallet-revive-uapi 0.13.0
  Version pin canonical para stable2512-3 verificado vía
  github.com/paritytech/polkadot-sdk/blob/polkadot-stable2512-3/substrate/frame/revive/Cargo.toml
  (latest 0.17.0 requiere bump Substrate generation — scope Phase 8+).
- crates/origin-chain-types/src/actions.rs: ChainAction enum extension OCAFB-2
  semver-respecting con 3 nuevas variants ordinals 4/5/6:
  * DeployContract (pallet-revive::instantiate)
  * CallContract (pallet-revive::call)
  * UploadContractCode (pallet-revive::upload_code sin instantiate)
  Ordinals 0-3 {Read/Write/Compute/Transfer} preservados intactos. Wire format
  stable canonical — name() snake_case + ordinal() u8 + from_ordinal() forward-compat
  + serde + scale-codec roundtrip todos actualizados. +1 test
  chain_action_phase_3_variants_distinct_from_legacy.
- crates/origin-chain-fees/src/fee_schedule.rs: subsidy_basis_points + entitlement_unlocked
  matches updated exhaustivamente para 3 nuevas variants. Mapping interim conservador
  (DeployContract/UploadContractCode ~= Write semantics, CallContract ~= Compute).
  Refinement Phase 3.2 con Mathi OitFeeSchedule extension post-OCAFB ratify +
  measurements empíricos gas/deposit reales.

Verificación:
- cargo check --workspace clean (0 errors, warnings pre-existentes)
- cargo test --workspace: 203 tests verde (baseline 202 + 1 new test) 0 failures
- ChainAction actions::tests 7/7 verde (4 originales updated + 3 nuevos covered)

Próximo Ship 2 v0.0.38: pallet-revive wired runtime Index 11 (27 Config types
associated types + parameter_types canonical Asset Hub Westend reference).

⚓ Path A Phase 3 kickoff. La nave continúa zarpando.

🤖 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
davidherran committed 2026-05-26 20:29:11 -05:00
1 parent 199636ac05
commit ec5b5bd2b2
3 files changed
+127 -20

No files matched your search

+10
View File
@@ -71,6 +71,16 @@ pallet-grandpa = { version = "40.0.0", default-features = false }
# FRAME pallets canonical Phase 1.5 — Session rotation per CHN-1 4h epochs # FRAME pallets canonical Phase 1.5 — Session rotation per CHN-1 4h epochs
pallet-session = { version = "40.0.1", default-features = false } pallet-session = { version = "40.0.1", default-features = false }
# ============================================================
# Phase 3 — pallet-revive smart contracts per SBS-5 ratified
# (supersedes CHN-6 v1.0 → CHN-6 v2.0 PolkaVM + ink! v6 + Solidity)
# Version pin: 0.12.2 (canonical para stable2512-3, verified vía
# github.com/paritytech/polkadot-sdk/blob/polkadot-stable2512-3/substrate/frame/revive/Cargo.toml).
# Bump a 0.17.0 scope Phase 8+ (post-mainnet Substrate generation upgrade).
# ============================================================
pallet-revive = { version = "0.12.2", default-features = false }
pallet-revive-uapi = { version = "0.13.0", default-features = false, features = ["scale"] }
# pallet-identity DEFERRED a Phase 2.7 — canonical decision empírica 2026-05-21: # pallet-identity DEFERRED a Phase 2.7 — canonical decision empírica 2026-05-21:
# pallet-identity 41.0.0 usa ReservableCurrency trait (deprecated en stable2512, # pallet-identity 41.0.0 usa ReservableCurrency trait (deprecated en stable2512,
# replaced por fungible::Mutate). Compat work canonical es scope Phase 2.7 cuando # replaced por fungible::Mutate). Compat work canonical es scope Phase 2.7 cuando
+30 -1
View File
@@ -99,6 +99,24 @@ pub const fn subsidy_basis_points(hw: HardwareTier, action: ChainAction) -> u32
(Ultra, Write) => 0, (Ultra, Write) => 0,
(Ultra, Compute) => 0, (Ultra, Compute) => 0,
(Ultra, Transfer) => 0, (Ultra, Transfer) => 0,
// Phase 3 SBS-5 contract actions — anti-clasista mapping interim
// (Slice 3.1 SCAFFOLD v0.0.37). Mappeo conservativo análogo a Write
// (DeployContract + UploadContractCode = storage-heavy) y Compute
// (CallContract = PolkaVM gas execution). Refinement Slice 3.2 cuando
// Mathi extiende OitFeeSchedule con measurements empíricos gas/deposit
// reales post-Phase 3 Ship 2 wired runtime Index 11.
(EmbeddedArm, DeployContract) => 9000, // Pi 5 dev contracts canonical
(EmbeddedArm, CallContract) => 10000, // educational call free
(EmbeddedArm, UploadContractCode) => 9000, // Pi 5 storage subsidy
(Portable, DeployContract) => 7500,
(Portable, CallContract) => 5000,
(Portable, UploadContractCode) => 7500,
(Desktop, DeployContract) => 2500,
(Desktop, CallContract) => 2500,
(Desktop, UploadContractCode) => 2500,
(Ultra, DeployContract) => 0,
(Ultra, CallContract) => 0,
(Ultra, UploadContractCode) => 0,
} }
} }
@@ -120,7 +138,18 @@ pub const fn entitlement_unlocked(tier: SubscriptionTier, action: ChainAction) -
(Pro, Write) => true, (Pro, Write) => true,
(Pro, Compute) => true, // basic compute unlocked (Pro, Compute) => true, // basic compute unlocked
(Pro, Transfer) => true, (Pro, Transfer) => true,
// Ultra: ALL incluyendo EEG Compute (Inmutable #18) // Phase 3 SBS-5 contract actions Free tier — conservativo interim
// (Slice 3.1 SCAFFOLD v0.0.37). Free user blocked de smart contract
// operations por default. Refinement Slice 3.2 con Mathi: educational
// world override + Pi 5 dev path canonical via subscription upgrade
// gratuita post-OCAFB ratify Phase 3 maduración.
(Free, DeployContract) => false, // requires Pro+ initial
(Free, CallContract) => false, // requires Pro+ initial
(Free, UploadContractCode) => false, // requires Pro+ initial
(Pro, DeployContract) => true,
(Pro, CallContract) => true,
(Pro, UploadContractCode) => true,
// Ultra: ALL incluyendo EEG Compute (Inmutable #18) y contracts
(Ultra, _) => true, (Ultra, _) => true,
} }
} }
+87 -19
View File
@@ -7,9 +7,17 @@
//! análogo DCM-4 `default_material()` Marihan + `HardwareTier` mirror Phanes //! análogo DCM-4 `default_material()` Marihan + `HardwareTier` mirror Phanes
//! `arkhe-asset::manifest_validator`). //! `arkhe-asset::manifest_validator`).
//! //!
//! 4 variants canonical {Read, Write, Compute, Transfer} con ordinals 0/1/2/3 //! 7 variants canonical {Read, Write, Compute, Transfer, DeployContract,
//! stable wire format — adding variants future appende al final preservando //! CallContract, UploadContractCode} con ordinals 0..=6 stable wire format —
//! ordinals existentes (semver respect canonical). //! adding variants future appende al final preservando ordinals existentes
//! (semver respect canonical).
//!
//! **Phase 3 SBS-5 ratified extension (2026-05-27, Slice 3.1 Ship 1 v0.0.37)**:
//! variants 4/5/6 añadidas para `pallet-revive` smart contract operations
//! (PolkaVM RISC-V + ink! v6 + Solidity). Permiten fee differentiation futura
//! por Mathi `OitFeeSchedule` post-OCAFB ratify — `DeployContract` gas-heavy
//! (storage deposit + bytecode upload), `CallContract` execution-metered,
//! `UploadContractCode` storage-only (sin instantiate).
//! //!
//! Bidirectional conversion canonical wire-compat via `From<u8>` + serde //! Bidirectional conversion canonical wire-compat via `From<u8>` + serde
//! `rename_all="snake_case"` + scale-codec derives canonical. //! `rename_all="snake_case"` + scale-codec derives canonical.
@@ -45,6 +53,20 @@ pub enum ChainAction {
/// Transfer OGC token (peer-to-peer, fee redirect, governance staking). /// Transfer OGC token (peer-to-peer, fee redirect, governance staking).
/// Free user limitado a basic ≤10 OGC/day per OCAFB-4 entitlement. /// Free user limitado a basic ≤10 OGC/day per OCAFB-4 entitlement.
Transfer, Transfer,
/// Deploy smart contract via `pallet-revive::instantiate` (Phase 3 SBS-5).
/// Carga code hash + storage deposit + instantiate constructor. Fee
/// modulado por storage deposit (DepositPerByte + DepositPerItem) + gas
/// metering PolkaVM execution.
DeployContract,
/// Invoke smart contract method via `pallet-revive::call` (Phase 3 SBS-5).
/// Fee gas-metered en PolkaVM execution + storage write deposits si la
/// llamada muta state. Read-only views también incurren minimal gas fee.
CallContract,
/// Upload PolkaVM bytecode WITHOUT instantiate via `pallet-revive::upload_code`
/// (Phase 3 SBS-5). Solo deposita code en storage por su size + lockup
/// deposit canonical. Permite separar code authorship de instantiation
/// (e.g. template publishing pattern por Sussi Ethos credentials Slice 3.4).
UploadContractCode,
} }
impl ChainAction { impl ChainAction {
@@ -55,18 +77,25 @@ impl ChainAction {
ChainAction::Write => "write", ChainAction::Write => "write",
ChainAction::Compute => "compute", ChainAction::Compute => "compute",
ChainAction::Transfer => "transfer", ChainAction::Transfer => "transfer",
ChainAction::DeployContract => "deploy_contract",
ChainAction::CallContract => "call_contract",
ChainAction::UploadContractCode => "upload_contract_code",
} }
} }
/// Ordinal canonical para wire format `u8` (cross-crate sin requerir serde). /// Ordinal canonical para wire format `u8` (cross-crate sin requerir serde).
/// `0=Read 1=Write 2=Compute 3=Transfer`. Stable order — adding variants /// `0=Read 1=Write 2=Compute 3=Transfer 4=DeployContract 5=CallContract
/// future appende al final preservando ordinals existentes (semver respect). /// 6=UploadContractCode`. Stable order — adding variants future appende al
/// final preservando ordinals existentes (semver respect).
pub const fn ordinal(self) -> u8 { pub const fn ordinal(self) -> u8 {
match self { match self {
ChainAction::Read => 0, ChainAction::Read => 0,
ChainAction::Write => 1, ChainAction::Write => 1,
ChainAction::Compute => 2, ChainAction::Compute => 2,
ChainAction::Transfer => 3, ChainAction::Transfer => 3,
ChainAction::DeployContract => 4,
ChainAction::CallContract => 5,
ChainAction::UploadContractCode => 6,
} }
} }
@@ -78,6 +107,9 @@ impl ChainAction {
1 => Some(ChainAction::Write), 1 => Some(ChainAction::Write),
2 => Some(ChainAction::Compute), 2 => Some(ChainAction::Compute),
3 => Some(ChainAction::Transfer), 3 => Some(ChainAction::Transfer),
4 => Some(ChainAction::DeployContract),
5 => Some(ChainAction::CallContract),
6 => Some(ChainAction::UploadContractCode),
_ => None, _ => None,
} }
} }
@@ -87,38 +119,58 @@ impl ChainAction {
mod tests { mod tests {
use super::*; use super::*;
/// All 7 canonical variants para iteración exhaustiva en tests.
const ALL_VARIANTS: [ChainAction; 7] = [
ChainAction::Read,
ChainAction::Write,
ChainAction::Compute,
ChainAction::Transfer,
ChainAction::DeployContract,
ChainAction::CallContract,
ChainAction::UploadContractCode,
];
#[test] #[test]
fn chain_action_name_lowercase_canonical() { fn chain_action_name_lowercase_canonical() {
assert_eq!(ChainAction::Read.name(), "read"); assert_eq!(ChainAction::Read.name(), "read");
assert_eq!(ChainAction::Write.name(), "write"); assert_eq!(ChainAction::Write.name(), "write");
assert_eq!(ChainAction::Compute.name(), "compute"); assert_eq!(ChainAction::Compute.name(), "compute");
assert_eq!(ChainAction::Transfer.name(), "transfer"); assert_eq!(ChainAction::Transfer.name(), "transfer");
assert_eq!(ChainAction::DeployContract.name(), "deploy_contract");
assert_eq!(ChainAction::CallContract.name(), "call_contract");
assert_eq!(
ChainAction::UploadContractCode.name(),
"upload_contract_code"
);
} }
#[test] #[test]
fn chain_action_ordinal_stable_canonical() { fn chain_action_ordinal_stable_canonical() {
// Ordinals 0-3 preservados canonical (OCAFB-2 wire format estable).
assert_eq!(ChainAction::Read.ordinal(), 0); assert_eq!(ChainAction::Read.ordinal(), 0);
assert_eq!(ChainAction::Write.ordinal(), 1); assert_eq!(ChainAction::Write.ordinal(), 1);
assert_eq!(ChainAction::Compute.ordinal(), 2); assert_eq!(ChainAction::Compute.ordinal(), 2);
assert_eq!(ChainAction::Transfer.ordinal(), 3); assert_eq!(ChainAction::Transfer.ordinal(), 3);
// Phase 3 SBS-5 extension: ordinals 4-6 appended preservando 0-3.
assert_eq!(ChainAction::DeployContract.ordinal(), 4);
assert_eq!(ChainAction::CallContract.ordinal(), 5);
assert_eq!(ChainAction::UploadContractCode.ordinal(), 6);
} }
#[test] #[test]
fn chain_action_from_ordinal_roundtrip_canonical() { fn chain_action_from_ordinal_roundtrip_canonical() {
for action in [ for action in ALL_VARIANTS {
ChainAction::Read,
ChainAction::Write,
ChainAction::Compute,
ChainAction::Transfer,
] {
assert_eq!(ChainAction::from_ordinal(action.ordinal()), Some(action)); assert_eq!(ChainAction::from_ordinal(action.ordinal()), Some(action));
} }
} }
#[test] #[test]
fn chain_action_from_ordinal_unknown_returns_none() { fn chain_action_from_ordinal_unknown_returns_none() {
// Forward-compat: ordinals futuros NO conocidos retornan None safe // Forward-compat: ordinals futuros NO conocidos retornan None safe.
assert_eq!(ChainAction::from_ordinal(4), None); // Ordinal 7+ NO assigned aún (reserved para variants futuras tipo
// CrossChainBridge, PrecompileInvoke, etc).
assert_eq!(ChainAction::from_ordinal(7), None);
assert_eq!(ChainAction::from_ordinal(100), None);
assert_eq!(ChainAction::from_ordinal(255), None); assert_eq!(ChainAction::from_ordinal(255), None);
} }
@@ -128,19 +180,35 @@ mod tests {
assert_eq!(json, "\"read\""); assert_eq!(json, "\"read\"");
let parsed: ChainAction = serde_json::from_str("\"compute\"").unwrap(); let parsed: ChainAction = serde_json::from_str("\"compute\"").unwrap();
assert_eq!(parsed, ChainAction::Compute); assert_eq!(parsed, ChainAction::Compute);
// Phase 3 SBS-5 variants también serializan snake_case.
assert_eq!(
serde_json::to_string(&ChainAction::DeployContract).unwrap(),
"\"deploy_contract\""
);
let parsed_upload: ChainAction =
serde_json::from_str("\"upload_contract_code\"").unwrap();
assert_eq!(parsed_upload, ChainAction::UploadContractCode);
} }
#[test] #[test]
fn chain_action_scale_encode_decode_roundtrip_canonical() { fn chain_action_scale_encode_decode_roundtrip_canonical() {
for action in [ for action in ALL_VARIANTS {
ChainAction::Read,
ChainAction::Write,
ChainAction::Compute,
ChainAction::Transfer,
] {
let encoded = action.encode(); let encoded = action.encode();
let decoded = ChainAction::decode(&mut &encoded[..]).unwrap(); let decoded = ChainAction::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, action); assert_eq!(decoded, action);
} }
} }
#[test]
fn chain_action_phase_3_variants_distinct_from_legacy() {
// Phase 3 contract operations NO se solapan con generic Read/Write/Compute.
// Diseñadas para fee differentiation post-Mathi OitFeeSchedule extensión
// canonical post-OCAFB ratify Phase 3.x maduración.
assert_ne!(ChainAction::DeployContract, ChainAction::Write);
assert_ne!(ChainAction::CallContract, ChainAction::Compute);
assert_ne!(ChainAction::UploadContractCode, ChainAction::Write);
// Pero ChainAction::DeployContract es semánticamente "Write con bytecode" —
// Mathi puede mapear DeployContract → Write fee_for_action() base
// multiplicado por bytecode size (canonical decision deferred Phase 3.2).
}
} }