Skip to content
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

Add Governance Configuration and Chopsticks setup #6

Merged
merged 18 commits into from
Feb 29, 2024
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ build/
/dist/
/target

# Chopsticks
/chopsticks/*.db.sqlite*

# Before adding new lines, see the comment at the top.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 49 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,52 @@
[![codecov](https://codecov.io/gh/ajuna-network/ajuna-runtimes-bajun/branch/main/graph/badge.svg?token=V2Y88ZUD6C)](https://codecov.io/gh/ajuna-network/Ajuna)
[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/ajuna/parachain-bajun?label=bajun%20network&logo=docker&sort=semver&style=plastic)](https://hub.docker.com/repository/docker/ajuna/parachain-bajun/tags?page=1&ordering=last_updated)

A game platform [parachain](https://wiki.polkadot.network/docs/learn-parachains) built with [Substrate](https://docs.substrate.io/).
A game platform [parachain](https://wiki.polkadot.network/docs/learn-parachains) built
with [Substrate](https://docs.substrate.io/).

## Chopsticks

Chopsticks can be used to create a local fork of a life network, copying all its storage values and override specific
storage values with a config file. The fork will create a block whenever an extrinsic is added to the tx-pool.
Otherwise, it will be stale, but exposes a fast-forward rpc to produce 'n' blocks, which is useful for scheduler
testing.

Chopsticks can be used to:

* Test runtime upgrades and functionality thereafter
* Setup XCM with multiple networks and allow for XCM testing
* Test execution of scheduled task, which is mostly execution of governance proposals.

**Preliminary Note**
Chopsticks will by default listen on the IPV6 localhost port 8000, which means we can either access it with:

* ws://localhost:8000
* ws://[::1]:8000

but ws://127.0.0.1:8000 doesn't work.

### Test Runtime Upgrades

Note: Currently, try-runtime seems to be a better solution to test the runtime upgrade itself, but chopsticks will be
good to test functionality after the runtime upgrade happened.

The following command overrides the runtime with the local build of the upgraded runtime and will run the migration
upon the next block, which means as soon as we send an arbitrary extrinsic.

```bash
nvm use 20
npx @acala-network/chopsticks@latest --config ./chopsticks/bajun.yml --wasm-override ./target/release/wbuild/bajun-runtime/bajun_runtime.compact.compressed.wasm
```

Then we can send an arbitrary extrinsic to trigger the next block and observe the logs of the runtime upgrade.

### Test XCM stuff

TBD when we actually start setting up XCM.

### Test Governance execution

Simply create an external proposal and fast-track it with a small voting period and delay, e.g. 10 blocks. Then, in
polkadot-js/apps, go to Developer -> JavaScript and execute the following chopsticks-dev-rpc:
`api.rpc('dev_newBlock', { count: 10 })`. After this you can observe the blocks being created one by one until the
proposal is executed.
30 changes: 30 additions & 0 deletions chopsticks/bajun.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# In the future we want to add this config to https://github.com/AcalaNetwork/chopsticks/tree/master/configs.
# But we should wait until we have the governance pallets included because this will change this config.
endpoint:
- wss://rpc-parachain.bajun.network
- wss://bajun.api.onfinality.io/public-ws
- wss://bajun.public.curie.radiumblock.co/ws
mock-signature-host: true
block: ${env.BAJUN_PARACHAIN_BLOCK_NUMBER}
db: ./chopsticks/bajun-parachain.db.sqlite
runtime-log-level: 5
# wasm-override: bajun_runtime.wasm

# Once we have governance we want to make Alice single councillor and technical committee member.
import-storage:
Sudo:
Key: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY # Alice
System:
Account: # Give our dev accounts some funds
- - - 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY # Alice
- providers: 1
data:
free: 1000000000000000
- - - 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty # Bob
- providers: 1
data:
free: 1000000000000000
- - - 5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y # Charlie
- providers: 1
data:
free: 1000000000000000
darkfriend77 marked this conversation as resolved.
Show resolved Hide resolved
14 changes: 14 additions & 0 deletions node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ fn testnet_genesis(
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": EXISTENTIAL_DEPOSIT * 16,
},
"council": {
"members": vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Charlie"),
]
},
"technicalCommittee": {
"members": vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Charlie"),
]
},
"session": {
"keys": invulnerables
.into_iter()
Expand Down
4 changes: 4 additions & 0 deletions runtime/bajun/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pallet-aura = { workspace = true }
pallet-authorship = { workspace = true }
pallet-balances = { workspace = true }
pallet-collective = { workspace = true }
pallet-democracy = { workspace = true }
pallet-identity = { workspace = true }
pallet-insecure-randomness-collective-flip = { workspace = true }
pallet-membership = { workspace = true }
Expand Down Expand Up @@ -121,6 +122,7 @@ std = [
"pallet-balances/std",
"pallet-collective/std",
"pallet-collator-selection/std",
"pallet-democracy/std",
"pallet-identity/std",
"pallet-membership/std",
"pallet-message-queue/std",
Expand Down Expand Up @@ -170,6 +172,7 @@ runtime-benchmarks = [
"pallet-balances/runtime-benchmarks",
"pallet-collator-selection/runtime-benchmarks",
"pallet-collective/runtime-benchmarks",
"pallet-democracy/runtime-benchmarks",
"pallet-identity/runtime-benchmarks",
"pallet-membership/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
Expand Down Expand Up @@ -205,6 +208,7 @@ try-runtime = [
"pallet-balances/try-runtime",
"pallet-collator-selection/try-runtime",
"pallet-collective/try-runtime",
"pallet-democracy/try-runtime",
"pallet-identity/try-runtime",
"pallet-membership/try-runtime",
"pallet-message-queue/try-runtime",
Expand Down
169 changes: 169 additions & 0 deletions runtime/bajun/src/gov.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Ajuna Node
// Copyright (C) 2022 BlogaTech AG

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use crate::{
AccountId, Balance, BlockNumber, Council, CouncilMembership, OriginCaller, Runtime,
RuntimeBlockWeights, RuntimeCall, RuntimeEvent, RuntimeOrigin, TechnicalCommittee, BAJUN, DAYS,
};
use frame_support::{
parameter_types,
traits::{ConstBool, ConstU32, EitherOfDiverse},
weights::Weight,
};
use frame_system::{EnsureRoot, EnsureSignedBy};
use pallet_collective::{EnsureMember, EnsureProportionAtLeast, EnsureProportionMoreThan};
use sp_runtime::Perbill;

pub type EnsureRootOrMoreThanHalfCouncil = EitherOfDiverse<
EnsureRoot<AccountId>,
EnsureProportionMoreThan<AccountId, CouncilCollectiveInstance, 1, 2>,
>;

pub type EnsureRootOrMoreThanHalfTechnicalCommittee = EitherOfDiverse<
EnsureRoot<AccountId>,
EnsureProportionAtLeast<AccountId, TechnicalCommitteeInstance, 1, 2>,
>;

pub type EnsureRootOrAllTechnicalCommittee = EitherOfDiverse<
EnsureRoot<AccountId>,
EnsureProportionAtLeast<AccountId, TechnicalCommitteeInstance, 1, 1>,
>;

/// Council collective instance declaration.
///
/// The council primarily serves to optimize and balance the inclusive referendum system
/// by being allowed to propose external democracy proposals, which can be fast tracked and
/// bypass the one active referendum at a time rule.
///
/// It also controls the treasury.
type CouncilCollectiveInstance = pallet_collective::Instance2;

parameter_types! {
pub CouncilMotionDuration: BlockNumber = 3 * DAYS;
pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block;
pub CouncilMaxMembers: u32 = 100;
}

impl pallet_collective::Config<CouncilCollectiveInstance> for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type MotionDuration = CouncilMotionDuration;
type MaxProposals = ConstU32<100>;
type MaxMembers = CouncilMaxMembers;
type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
type SetMembersOrigin = EnsureRootOrMoreThanHalfCouncil;
type MaxProposalWeight = MaxProposalWeight;
}

/// Helper pallet to manage Council members.
type CouncilMembershipInstance = pallet_membership::Instance2;
impl pallet_membership::Config<CouncilMembershipInstance> for Runtime {
type RuntimeEvent = RuntimeEvent;
type AddOrigin = EnsureRootOrMoreThanHalfCouncil;
type RemoveOrigin = EnsureRootOrMoreThanHalfCouncil;
type SwapOrigin = EnsureRootOrMoreThanHalfCouncil;
type ResetOrigin = EnsureRootOrMoreThanHalfCouncil;
type PrimeOrigin = EnsureRootOrMoreThanHalfCouncil;
type MembershipInitialized = Council;
type MembershipChanged = Council;
type MaxMembers = CouncilMaxMembers;
type WeightInfo = pallet_membership::weights::SubstrateWeight<Runtime>;
}

/// The technical committee primarily serves to safeguard against malicious referenda
/// and fast track critical referenda.
pub type TechnicalCommitteeInstance = pallet_collective::Instance1;

parameter_types! {
pub const TechnicalMotionDuration: BlockNumber = 3 * DAYS;
pub const TechnicalCommitteeMaxMembers: u32 = 100;
}

impl pallet_collective::Config<TechnicalCommitteeInstance> for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type MotionDuration = TechnicalMotionDuration;
type MaxProposals = ConstU32<100>;
type MaxMembers = TechnicalCommitteeMaxMembers;
type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
type SetMembersOrigin = EnsureRootOrMoreThanHalfCouncil;
type MaxProposalWeight = MaxProposalWeight;
}

/// Helper pallet to manage TechnicalCommittee members.
type TechnicalCommitteeMembershipInstance = pallet_membership::Instance1;
impl pallet_membership::Config<TechnicalCommitteeMembershipInstance> for Runtime {
type RuntimeEvent = RuntimeEvent;
type AddOrigin = EnsureRootOrMoreThanHalfCouncil;
type RemoveOrigin = EnsureRootOrMoreThanHalfCouncil;
type SwapOrigin = EnsureRootOrMoreThanHalfCouncil;
type ResetOrigin = EnsureRootOrMoreThanHalfCouncil;
type PrimeOrigin = EnsureRootOrMoreThanHalfCouncil;
type MembershipInitialized = TechnicalCommittee;
type MembershipChanged = TechnicalCommittee;
type MaxMembers = TechnicalCommitteeMaxMembers;
type WeightInfo = pallet_membership::weights::SubstrateWeight<Runtime>;
}

parameter_types! {
pub const ThreeDays: BlockNumber = 3 * DAYS;
pub const TwentyEightDays: BlockNumber = 28 * DAYS;
pub const ThirtyDays: BlockNumber = 30 * DAYS;
pub EnactmentPeriod: BlockNumber = 7 * DAYS;
pub const MinimumDeposit: Balance = BAJUN;
}

impl pallet_democracy::Config for Runtime {
type WeightInfo = pallet_democracy::weights::SubstrateWeight<Runtime>;
type RuntimeEvent = RuntimeEvent;
type Scheduler = pallet_scheduler::Pallet<Runtime>;
type Preimages = pallet_preimage::Pallet<Runtime>;
type Currency = pallet_balances::Pallet<Runtime>;
type EnactmentPeriod = EnactmentPeriod;
type LaunchPeriod = TwentyEightDays;
type VotingPeriod = TwentyEightDays;
type VoteLockingPeriod = EnactmentPeriod;
type MinimumDeposit = MinimumDeposit;
type InstantAllowed = ConstBool<true>;
type FastTrackVotingPeriod = ThreeDays;
type CooloffPeriod = TwentyEightDays;
type MaxVotes = ConstU32<100>;
type MaxProposals = ConstU32<100>;
type MaxDeposits = ConstU32<100>;
type MaxBlacklisted = ConstU32<100>;
type ExternalOrigin = EnsureRootOrMoreThanHalfCouncil;
type ExternalMajorityOrigin = EnsureRootOrMoreThanHalfCouncil;
type ExternalDefaultOrigin = EnsureRootOrMoreThanHalfCouncil;
// Initially, we want that only the council can submit proposals to
// prevent malicious proposals.
type SubmitOrigin = EnsureSignedBy<CouncilMembership, AccountId>;
type FastTrackOrigin = EnsureRootOrMoreThanHalfTechnicalCommittee;
type InstantOrigin = EnsureRootOrMoreThanHalfTechnicalCommittee;
// To cancel a proposal that has passed.
type CancellationOrigin = EnsureRoot<AccountId>;
type BlacklistOrigin = EnsureRootOrMoreThanHalfCouncil;
// To cancel a proposal before it has passed, and slash its backers.
type CancelProposalOrigin = EnsureRootOrAllTechnicalCommittee;
// Any single technical committee member may veto a coming council proposal, however they can
// only do it once and it lasts only for the cooloff period.
type VetoOrigin = EnsureMember<AccountId, TechnicalCommitteeInstance>;
type PalletsOrigin = OriginCaller;
type Slash = pallet_treasury::Pallet<Runtime>;
}
Loading
Loading