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:
1 parent
199636ac05
commit
ec5b5bd2b2
3 files changed
+127
-20
No files matched your search
+10
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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).
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user