Expand description
Pallet that establishes a Partner Chain as a Cardano sidechain
§Purpose of this pallet
This pallet serves as the starting point for building a Partner Chain runtime. It stores its genesis UTXO which serves as its global identifier and divides Partner Chain slots into Partner Chain epochs.
§Genesis UTXO
When a Partner Chain governance is initialized on Cardano, the transaction spends a special genesis UTXO. This UTXO serves multiple crucial roles:
- it serves as the unique identifier of the Partner Chain
- it affects the addresses of all Partner Chain Toolkit’s Plutus smart contracts to allow multiple Partner Chains to exist
- it is included in messages signed by various participants of the Partner Chain when submitting transactions (on both Cardano and the Partner Chain) to prevent replay attacks
The genesis UTXO is immutable throughout the lifetime of a Partner Chain in order to preserve its identity.
§Partner Chain Epochs
When producing blocks, Partner Chains divide time into slots in which a single block can be produced. These slots are in turn grouped into epochs which other Partner Chains features use as boundaries for some of their state transitions (eg. a Partner Chain block producing committees change at epoch boundaries). Both slot and epoch durations are constant and immutable throughout a Partner Chain’s lifetime.
§Usage
§Prerequisites
Before a Partner Chain can be started, its Cardano governance must be established by
running the init transaction, which also determines the genesis UTXO of the
Partner Chain. Consult docs/user-guides/governance/governance.md
for instructions.
As Partner Chains operate on the basis of slots and epochs, your Substrate node should use a slot-based consensus mechanism such as Aura.
§Optional - defining a new epoch hook
A Partner Chain may need to perform custom logic when a new epoch starts, eg. pay out block production rewards, update chain participant standings etc. For this purpose, the pallet can be configured with a handler that will be triggered during initialization of each first block of a new epoch.
To create a new epoch handler, simply define a type and have it implement the [OnNewEpoch] trait:
use sidechain_domain::{ ScEpochNumber, ScSlotNumber };
use sp_runtime::Weight;
struct MyNewEpochHandler;
impl sp_sidechain::OnNewEpoch for MyNewEpochHandler {
fn on_new_epoch(old_epoch: ScEpochNumber, new_epoch: ScEpochNumber) -> Weight {
log::info!("Partner Chain epoch changed from {old_epoch} to {new_epoch}");
Weight::zero()
}
}
The weight returned by on_new_epoch
should match its real resource use.
§Adding to runtime
The pallet requires minimal configuration, as it is only mandatory to inject the function that provides the current slot. Assuming that Aura consensus is used, the pallet can be configured like the following:
impl pallet_sidechain::Config for Runtime {
fn current_slot_number() -> ScSlotNumber {
ScSlotNumber(*pallet_aura::CurrentSlot::<Self>::get())
}
type OnNewEpoch = MyNewEpochHandler;
}
Optionally, a new epoch handler can be configured like in the example above. Partner Chains that do not need to run additional logic at epoch change can use the empty implementation available for [()]:
type OnNewEpoch = MyNewEpochHandler;
If multiple handlers need to be added, a tuple can be used for convenience:
type OnNewEpoch = (NewEpochHandler1, NewEpochHandler2);
§Genesis configuration
After the pallet is added to the runtime, configure it in your rust node code:
pallet_sidechain::GenesisConfig::<Runtime> {
genesis_utxo: UtxoId::from_str("0000000000000000000000000000000000000000000000000000000000000000#0").unwrap(),
slots_per_epoch: SlotsPerEpoch(60),
..Default::default()
}
or via a chain spec Json file:
{
"sidechain_pallet": {
"genesisUtxo": "0000000000000000000000000000000000000000000000000000000000000000#0",
"slotsPerEpoch": 60
}
}
Re-exports§
pub use pallet::*;
Modules§
- pallet
- The
pallet
module in each FRAME pallet hosts the most important items needed to construct this pallet.