Skip to content

Generate V1.5.1 chain specs #720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This changelog is based on [Keep A Changelog](https://keepachangelog.com/en/1.1.
# v1.5.0

## Changed
* `smart-contracts reserve release` command parameter `--amount` semantic has changed, it now represent the amount of tokens to release in this command execution
* Replaced custom weights with default substrate weights for few pallets
* Updated to polkadot-stable2409-4 (aka v1.16.4).
* `setup-main-chain-state` command now uses native Rust to upsert the D-Parameter and upsert permissioned candidates
Expand Down
40 changes: 40 additions & 0 deletions dev/envs/ci-preview/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export GENESIS_UTXO="de7b8efb08243b770be30cfa22a9ed64317c50052bb4394392960ddcc9810048#1"

# unique identifier of the beneficiary that will be credited
# producer rewards for blocks produced by this node
export SIDECHAIN_BLOCK_BENEFICIARY="0x0000000000000000000000000000000000000000000000000000000000000201"

# below exports parse config/addresses.json file, which needs to regenerated for each new sidechain by running
# sidechain-main-cli addresses ... > config/addresses.json
export COMMITTEE_CANDIDATE_ADDRESS=$(jq -r '.addresses.CommitteeCandidateValidator' dev/envs/ci-preview/addresses.json)
export D_PARAMETER_POLICY_ID=$(jq -r '.mintingPolicies.DParameterPolicy' dev/envs/ci-preview/addresses.json)
export PERMISSIONED_CANDIDATES_POLICY_ID=$(jq -r '.mintingPolicies.PermissionedCandidatesPolicy' dev/envs/ci-preview/addresses.json)

# native token observability
export NATIVE_TOKEN_POLICY_ID='ada83ddd029614381f00e28de0922ab0dec6983ea9dd29ae20eef9b4'
export NATIVE_TOKEN_ASSET_NAME='5043546f6b656e44656d6f'
export ILLIQUID_SUPPLY_VALIDATOR_ADDRESS='addr_test1wrhvtvx3f0g9wv9rx8kfqc60jva3e07nqujk2cspekv4mqs9rjdvz'

# Preview parameters
export CARDANO_SECURITY_PARAMETER=432
export CARDANO_ACTIVE_SLOTS_COEFF=0.05
export DB_SYNC_POSTGRES_CONNECTION_STRING="postgres://postgres:password123@localhost/cexplorer"

# A minimum block distance from the most recent MC stable block.
# Used by block producers to select the stable block to include in the block header.
export BLOCK_STABILITY_MARGIN=0

# Timestamp for the MC_FIRST_EPOCH_NUMBER
# Genesis should not have a timestamp before this one, this should be divisible by both sidechain slot and epoch durations
export MC__FIRST_EPOCH_TIMESTAMP_MILLIS=1666656000000
# First Shelley epoch number on Cardano
export MC__FIRST_EPOCH_NUMBER=0
# Should be divisible by Sidechain epoch duration (which is SlotDuration * SlotsPerEpoch and those params can be found in runtime/src/lib.rs)
export MC__EPOCH_DURATION_MILLIS=86400000
# First Shelley slot number on Cardano
export MC__FIRST_SLOT_NUMBER=0

# When true, node will use the mock implementation of main chain follower. Overrides USE_INTERNAL_MAIN_CHAIN_FOLLOWER if true.
export USE_MAIN_CHAIN_FOLLOWER_MOCK=false
# This one is redundant when USE_MAIN_CHAIN_FOLLOWER_MOCK is absent of 'false'.
#export MAIN_CHAIN_FOLLOWER_MOCK_REGISTRATIONS_FILE=res/bb-mock/default-registrations.json
25 changes: 25 additions & 0 deletions dev/envs/ci-preview/addresses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"endpoint": "GetAddrs",
"addresses": {
"CommitteeCandidateValidator": "addr_test1wp4sjcwh2n7qmtmjyzq70ax5sgk32krytkqu9vrg8vxp82g0lkps6",
"VersionOracleValidator": "addr_test1wzm7xhlxtuquuk6594sh4xuu874850vzrwh5x272yvdf3ngx5phw2",
"PermissionedCandidatesValidator": "addr_test1wpfs2kw8a8ry0svtmdexmqyjz67qxmssgufg688ykw7ruucjj3856",
"DParameterValidator": "addr_test1wpvtw0r3acskmgrphlz0m4c57djpxdvw9gdcwx0rwter9acadwzzc",
"ReserveValidator": "addr_test1wz6tjn546lnvjftl08mw8xhv8n3amr7rze6emn49wjnwn6qwqefww",
"IlliquidCirculationSupplyValidator": "addr_test1wzzjx5flq6xj5ydp62vn57v46e8hrspj7q693qtz2m7ya8qekdzlk"
},
"validatorHashes": {
"CommitteeCandidateValidator": "6b0961d754fc0daf722081e7f4d4822d1558645d81c2b0683b0c13a9",
"VersionOracleValidator": "b7e35fe65f01ce5b542d617a9b9c3faa7a3d821baf432bca231a98cd",
"PermissionedCandidatesValidator": "530559c7e9c647c18bdb726d809216bc036e1047128d1ce4b3bc3e73",
"DParameterValidator": "58b73c71ee216da061bfc4fdd714f36413358e2a1b8719e372f232f7",
"ReserveValidator": "b4b94e95d7e6c9257f79f6e39aec3ce3dd8fc316759dcea574a6e9e8",
"IlliquidCirculationSupplyValidator": "8523513f068d2a11a1d2993a7995d64f71c032f03458816256fc4e9c"
},
"mintingPolicies": {
"VersionOraclePolicy": "488996bae9a3a1c48183f47debef321c957028c9664a397dae7d8222",
"PermissionedCandidatesPolicy": "1c99b6b45338e56ef7765c4d38163acd40954f21d451e59d746a31f6",
"DParameterPolicy": "7c4678633cab3ab39fc5880e15c3bc4fb41a6ac6eb7d7deb71bc8b07",
"ReserveAuthPolicy": "41478956696ac58c8672723a245aab289fb40abb9bf71e17ada64f2b"
}
}
11 changes: 2 additions & 9 deletions docs/developer-guides/native-token-reserve-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ Objective: Release available reserve tokens (defined by the `VFunction`).
--ogmios-url ws://localhost:1337 \
--payment-key-file <PAYMENT_KEY_FILE> \
--reference-utxo 156803a18a4dbde48dc83a21b8b1007b693cdf096b73596252745fdef1de6414#0 \
--token <TOKEN> \
--amount <AMOUNT>
```

Expand All @@ -236,17 +235,11 @@ Objective: Release available reserve tokens (defined by the `VFunction`).

* `--reference-utxo`: UTXO where the `VFunction` script is attached as a reference.

* `--token`: Reserve token asset id encoded in form `<policy_id_hex>.<asset_name_hex>`.

* `--amount`: amount of tokens to release

- The number should be calculated as `number of tokens release up to this time + amount of tokens to release`

- If 10 tokens have already been released and you want to release 10 more, then the total accrued until now should be defined as 20.

- If `--amount` passed by the user is lower than the factual number, then nothing will be released.
- Command will fail if amount is greater than the number of tokens in the reserve.

- Ensure you have enough tokens to release in this time frame (the `VFunction` defines release logic).
- Command will fail if the `VFunction` refuses to relase given amount.

#### Steps

Expand Down
7 changes: 3 additions & 4 deletions e2e-tests/config/substrate/staging_nodes.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"deployment_mc_epoch": 813,
"initial_pc_epoch": 4824881,
"genesis_utxo": "0c1fe996e4bdc2480d1e16c57823b4c5cd80b190d0814212977835ecce24afe3#1",
"deployment_version": "v1.5.0-rc4",
"deployment_mc_epoch": 840,
"genesis_utxo": "de7b8efb08243b770be30cfa22a9ed64317c50052bb4394392960ddcc9810048#1",
"deployment_version": "v1.5.0-rc10",
"test_environment": "staging",
"nodes_config": {
"nodes": {
Expand Down
3 changes: 2 additions & 1 deletion e2e-tests/src/blockchain_api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from abc import ABC, abstractmethod
from src.partner_chain_rpc import PartnerChainRpcResponse, DParam
from config.api_config import Node


class Transaction:
Expand Down Expand Up @@ -159,7 +160,7 @@ def deregister_candidate(self, candidate: str) -> (bool, int):
pass

@abstractmethod
def upsert_permissioned_candidates(self, new_candidates_list: list) -> (bool, int):
def upsert_permissioned_candidates(self, new_candidates_list: dict[str, Node]) -> (bool, int):
pass

@abstractmethod
Expand Down
10 changes: 3 additions & 7 deletions e2e-tests/src/partner_chains_node.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .run_command import RunnerFactory
from config.api_config import ApiConfig
from config.api_config import ApiConfig, Node
import json
import re
import logging as logger
Expand Down Expand Up @@ -137,15 +137,11 @@ def deregister_candidate(self, payment_key, spo_public_key):
logger.error(f"Wrong response format from deregister command: {response}")
return None

def upsert_permissioned_candidates(self, governance_key, new_candidates_list):
def upsert_permissioned_candidates(self, governance_key, new_candidates_list: dict[str, Node]):
# Create permissioned candidates file to be used in CLI command
permissioned_candidates = []
for candidate in new_candidates_list:
permissioned_candidates.append(self.config.nodes_config.nodes[candidate.name])

candidates_file_content = "\n".join(
f"{candidate.public_key}:{candidate.aura_public_key}:{candidate.grandpa_public_key}"
for candidate in permissioned_candidates
for candidate in new_candidates_list.values()
)
permissioned_candidates_file = "/tmp/permissioned_candidates.csv"
save_file_cmd = f"echo '{candidates_file_content}' > {permissioned_candidates_file}"
Expand Down
2 changes: 1 addition & 1 deletion e2e-tests/src/substrate_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def sign_transaction(self, tx: Transaction, wallet: Wallet):

@long_running_function
def submit_transaction(self, tx: Transaction, wait_for_finalization):
tx._receipt = self.substrate.submit_extrinsic(tx._signed, wait_for_finalization)
tx._receipt = self.substrate.submit_extrinsic(tx._signed, wait_for_finalization=wait_for_finalization)
logger.debug(f"Transaction sent {tx._receipt.extrinsic}")
tx.hash = tx._receipt.extrinsic_hash
tx.total_fee_amount = tx._receipt.total_fee_amount
Expand Down
77 changes: 43 additions & 34 deletions e2e-tests/tests/committee/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import random
from config.api_config import ApiConfig
from typing import Tuple
from config.api_config import ApiConfig, Node
from pytest import fixture, skip
from sqlalchemy import select, func, text
from sqlalchemy.orm import Session, aliased
Expand Down Expand Up @@ -149,44 +150,42 @@ def candidate(request, initialize_candidates, api: BlockchainApi, config: ApiCon

@fixture
def permissioned_candidates(
initialize_permissioned_candidates, api: BlockchainApi, config: ApiConfig, db: Session
) -> (list[PermissionedCandidates], PermissionedCandidates):
initialize_permissioned_candidates, api: BlockchainApi, config: ApiConfig
) -> Tuple[dict[str, Node], str]:
"""
Get list of permissioned candidates and swap one active with inactive candidate to test rotation.
"""
rotation_permissioned_candidates = [
name for name, node in config.nodes_config.nodes.items() if node.permissioned_candidate
]
if not rotation_permissioned_candidates:
skip("No rotation permissioned candidates available in config.")

current_epoch = api.get_mc_epoch()
Creates a tuple of new permissioned candidates to set and the name of the candidate to remove.

committee_for_query = aliased(PermissionedCandidates, name='query')
committee_for_subquery = aliased(PermissionedCandidates, name='subquery')
subquery = (
select(func.max(committee_for_subquery.next_status_epoch))
.where(committee_for_subquery.name == committee_for_query.name)
.where(committee_for_subquery.next_status_epoch <= current_epoch + 1)
).scalar_subquery()
query = (
select(committee_for_query)
.where(committee_for_query.next_status_epoch == subquery)
.where(committee_for_query.name.in_(rotation_permissioned_candidates))
)
candidates = db.scalars(query).all()
* get permissioned candidates from config
* get <current_mc_epoch+2> candidates from RPC
* delete one active candidate to test rotation
* if no current active candidates, delete one from config list and return the rest

Returns:
Tuple[dict[str, Node], str]: config <Node> objects, name of the candidate to remove
"""
candidates = {name: node for name, node in config.nodes_config.nodes.items() if node.permissioned_candidate}
if not candidates:
skip("No permissioned candidates available in db.")
skip("No permissioned candidates available in config.")

# Remove one active candidate to test rotation
active_candidates = [candidate for candidate in candidates if candidate.next_status == 'active']
current_epoch = api.get_mc_epoch()
active_candidates = api.get_permissioned_candidates(current_epoch + 2, valid_only=True)

if active_candidates:
candidate_to_remove = random.choice(active_candidates)
candidates.remove(candidate_to_remove)
candidate_name_to_remove = next(
(name for name, node in candidates.items() if node.aura_public_key == candidate_to_remove["auraPublicKey"]),
None,
)
if not candidate_name_to_remove:
raise ValueError(
f"Could not find candidate with aura key {candidate_to_remove['auraPublicKey']} in config."
)
del candidates[candidate_name_to_remove]
else:
candidate_name_to_remove = random.choice(list(candidates.keys()))
del candidates[candidate_name_to_remove]

yield candidates, candidate_to_remove
return candidates, candidate_name_to_remove


@fixture
Expand Down Expand Up @@ -215,17 +214,27 @@ def trustless_rotation_candidates(request, mc_epoch, db: Session, config: ApiCon
def permissioned_rotation_candidates(request, mc_epoch, db: Session, config: ApiConfig) -> PermissionedCandidates:
"""Parameterized fixture to get all the 'active' or 'inactive' rotation (permissioned) candidates
for given mc epoch. Use @pytest.mark.candidate_status() to pass data ('active' or 'inactive' only).
If there are multiple entries for the same candidate, the one with the highest ID is returned.
"""
all_rotation_candidates = [name for name, node in config.nodes_config.nodes.items() if node.permissioned_candidate]
candidate_status = request.node.get_closest_marker("candidate_status").args[0]

query = (
select(PermissionedCandidates)
# Create an alias for the table to use in a subquery
latest_entries = (
db.query(func.max(PermissionedCandidates.id).label("latest_id"))
.group_by(PermissionedCandidates.name)
.where(PermissionedCandidates.name.in_(all_rotation_candidates))
.where(PermissionedCandidates.next_status == candidate_status)
.where(PermissionedCandidates.next_status_epoch == mc_epoch)
.subquery()
)

# Query the latest statuses using a join
rotation_candidates = (
db.query(PermissionedCandidates)
.join(latest_entries, PermissionedCandidates.id == latest_entries.c.latest_id)
.where(PermissionedCandidates.next_status == candidate_status)
.all()
)
rotation_candidates = db.scalars(query).all()

if not rotation_candidates:
skip(f"No {candidate_status} permissioned candidates for MC epoch {mc_epoch}.")
Expand Down
4 changes: 3 additions & 1 deletion e2e-tests/tests/committee/test_committee.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,10 @@ def test_epoch_committee_size_complies_with_dparam(
2. Get epoch committee length (RPC:partner_chain_getEpochCommittee)
3. Assert both numbers are equal
"""
if pc_epoch <= config.initial_pc_epoch:
if pc_epoch < config.initial_pc_epoch:
skip("Cannot query committee before initial epoch.")
if pc_epoch == config.initial_pc_epoch:
skip("Initial committee is set in chain-spec, not DParam.")
mc_epoch = pc_epoch_calculator.find_mc_epoch(pc_epoch, current_mc_epoch)
d_param_cache: DParam = d_param_cache(mc_epoch)
max_validators = config.max_validators
Expand Down
20 changes: 12 additions & 8 deletions e2e-tests/tests/committee/test_permissioned_registrations.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import logging
from config.api_config import Node
from src.blockchain_api import BlockchainApi
from src.db.models import PermissionedCandidates
from sqlalchemy.orm import Session
from pytest import mark
from typing import Tuple


@mark.skip_blockchain("pc_evm", reason="not implemented yet")
Expand All @@ -11,7 +13,9 @@
@mark.registration
@mark.xdist_group(name="governance_action")
@mark.usefixtures("governance_skey_with_cli")
def test_upsert_permissioned_candidates(permissioned_candidates, api: BlockchainApi, db: Session):
def test_upsert_permissioned_candidates(
permissioned_candidates: Tuple[dict[str, Node], str], api: BlockchainApi, db: Session
):
"""Test addition of the permissioned candidate

* add inactive permissioned candidate
Expand All @@ -23,28 +27,28 @@ def test_upsert_permissioned_candidates(permissioned_candidates, api: Blockchain
result, next_status_epoch = api.upsert_permissioned_candidates(new_candidates_list)
assert result, f"Addition of permissioned candidate {new_candidates_list} failed."

for candidate in new_candidates_list:
for candidate in new_candidates_list.keys():
new_permission_candidate = PermissionedCandidates()
new_permission_candidate.name = candidate.name
new_permission_candidate.name = candidate
new_permission_candidate.next_status = "active"
new_permission_candidate.next_status_epoch = next_status_epoch
db.add(new_permission_candidate)

removed_candidate = PermissionedCandidates()
removed_candidate.name = candidate_to_remove.name
removed_candidate.name = candidate_to_remove
removed_candidate.next_status = "inactive"
removed_candidate.next_status_epoch = next_status_epoch
db.add(removed_candidate)
db.commit()

# TODO: split into separate test
expected_candidates = []
for candidate in new_candidates_list:
for candidate in new_candidates_list.values():
expected_candidates.append(
{
"sidechainPublicKey": api.config.nodes_config.nodes[candidate.name].public_key,
"auraPublicKey": api.config.nodes_config.nodes[candidate.name].aura_public_key,
"grandpaPublicKey": api.config.nodes_config.nodes[candidate.name].grandpa_public_key,
"sidechainPublicKey": candidate.public_key,
"auraPublicKey": candidate.aura_public_key,
"grandpaPublicKey": candidate.grandpa_public_key,
"isValid": True,
}
)
Expand Down
10 changes: 4 additions & 6 deletions toolkit/cli/smart-contracts-commands/src/reserve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use partner_chains_cardano_offchain::{
},
};
use sidechain_domain::{AssetId, ScriptHash, UtxoId};
use std::num::NonZero;

#[derive(Clone, Debug, clap::Subcommand)]
#[allow(clippy::large_enum_variant)]
Expand Down Expand Up @@ -208,20 +209,17 @@ pub struct ReleaseReserveCmd {
/// Reference UTXO containing the V-Function script
#[arg(long, short('r'))]
reference_utxo: UtxoId,
/// Encoded asset id in form <policy_id_hex>.<asset_name_hex>.
/// Amount of reserve tokens to be released to the illiquid supply.
#[arg(long)]
token: AssetId,
/// Current value of the V-Function
#[arg(long)]
amount: u64,
amount: NonZero<u64>,
}

impl ReleaseReserveCmd {
pub async fn execute(self) -> crate::CmdResult<()> {
let payment_key = self.payment_key_file.read_key()?;
let ogmios_client = client_for_url(&self.common_arguments.ogmios_url).await?;
let _ = release_reserve_funds(
TokenAmount { token: self.token, amount: self.amount },
self.amount,
self.genesis_utxo,
self.reference_utxo,
&payment_key,
Expand Down
4 changes: 2 additions & 2 deletions toolkit/offchain/src/csl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ pub(crate) trait OgmiosUtxoExt {

fn to_domain(&self) -> sidechain_domain::UtxoId;

fn get_asset_amount(&self, asset: &AssetId) -> i128;
fn get_asset_amount(&self, asset: &AssetId) -> u64;

fn get_plutus_data(&self) -> Option<PlutusData>;
}
Expand Down Expand Up @@ -336,7 +336,7 @@ impl OgmiosUtxoExt for OgmiosUtxo {
}
}

fn get_asset_amount(&self, asset_id: &AssetId) -> i128 {
fn get_asset_amount(&self, asset_id: &AssetId) -> u64 {
self.value
.native_tokens
.get(&asset_id.policy_id.0)
Expand Down
Loading
Loading