Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
17e5e22
migration: fix setting initial spec value at genesis
mnaamani Apr 14, 2020
d1d6687
runtime migration: fix comments
mnaamani Apr 15, 2020
e0b06e1
rustfmt
mnaamani Apr 15, 2020
407a925
migration: remainting steps
mnaamani Apr 21, 2020
a68eb4c
Merge branch 'development' into migration-constantinople
mnaamani Apr 22, 2020
6fc4a5f
Rome Constantinople migration test implementation
gleb-urvanov Apr 22, 2020
b71e471
updated runtime from Rome to Constantinople
gleb-urvanov Apr 24, 2020
c38eae6
Rome to Constantinople migration test fix
gleb-urvanov Apr 25, 2020
7ee50ee
new yarn command introduces to run migration test
gleb-urvanov Apr 27, 2020
b7a25ff
Merge branch 'development' into feature/rome-constatinople-migration-…
gleb-urvanov Apr 27, 2020
7ebeac8
Merge branch 'development' into migration-constantinople
mnaamani Apr 27, 2020
d2a0ce8
code cleaning, minor fixes
gleb-urvanov Apr 27, 2020
1dd4819
Merge branch 'development' into migration-constantinople
mnaamani Apr 28, 2020
e449e46
Merge branch 'development' into feature/rome-constatinople-migration-…
gleb-urvanov Apr 28, 2020
93e8a2f
migration: revet removing staked roles (storage providers, council me…
mnaamani Apr 28, 2020
425b9ef
Merge branch 'development' into migration-constantinople
mnaamani Apr 28, 2020
eb01b03
Merge branch 'development' into migration-constantinople
mnaamani Apr 28, 2020
79f9ef3
runtime: migration linter and fmt fixes
mnaamani Apr 28, 2020
2c7252f
make batch balance transfer sequential
gleb-urvanov Apr 28, 2020
cd1bf82
proposal tests skipped
gleb-urvanov Apr 28, 2020
2cd4010
moved proposals tests to constantinople folder
gleb-urvanov Apr 28, 2020
d125bb2
Merge branch 'migration-constantinople' into feature/new-proposals-tests
gleb-urvanov Apr 29, 2020
96bdcec
removed rome tests, introduced assertions for new proposal tests
gleb-urvanov Apr 29, 2020
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 @@ -22,3 +22,6 @@ yarn*

# Visual Studio Code
.vscode

# Compiled WASM code
*.wasm
6 changes: 4 additions & 2 deletions node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ use node_runtime::{
AuthorityDiscoveryConfig, BabeConfig, Balance, BalancesConfig, ContentWorkingGroupConfig,
CouncilConfig, CouncilElectionConfig, DataObjectStorageRegistryConfig,
DataObjectTypeRegistryConfig, ElectionParameters, GrandpaConfig, ImOnlineConfig, IndicesConfig,
MembersConfig, Perbill, ProposalsCodexConfig, SessionConfig, SessionKeys, Signature,
StakerStatus, StakingConfig, SudoConfig, SystemConfig, VersionedStoreConfig, DAYS, WASM_BINARY,
MembersConfig, MigrationConfig, Perbill, ProposalsCodexConfig, SessionConfig, SessionKeys,
Signature, StakerStatus, StakingConfig, SudoConfig, SystemConfig, VersionedStoreConfig, DAYS,
WASM_BINARY,
};
pub use node_runtime::{AccountId, GenesisConfig};
use primitives::{sr25519, Pair, Public};
Expand Down Expand Up @@ -301,6 +302,7 @@ pub fn testnet_genesis(
channel_banner_constraint: crate::forum_config::new_validation(5, 1024),
channel_title_constraint: crate::forum_config::new_validation(5, 1024),
}),
migration: Some(MigrationConfig {}),
proposals_codex: Some(ProposalsCodexConfig {
set_validator_count_proposal_voting_period: cpcp
.set_validator_count_proposal_voting_period,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"name": "joystream",
"license": "GPL-3.0-only",
"scripts": {
"test": "yarn && yarn workspaces run test"
"test": "yarn && yarn workspaces run test",
"test-migration": "yarn && yarn workspaces run test-migration"
},
"workspaces": [
"tests/network-tests"
Expand Down
2 changes: 1 addition & 1 deletion runtime-modules/content-working-group/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1894,7 +1894,7 @@ decl_module! {
origin,
curator_id: CuratorId<T>,
rationale_text: Vec<u8>
) {
) {

// Ensure lead is set and is origin signer
Self::ensure_origin_is_set_lead(origin)?;
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -889,12 +889,12 @@ construct_runtime!(
RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},
Sudo: sudo,
// Joystream
Migration: migration::{Module, Call, Storage, Event<T>, Config},
CouncilElection: election::{Module, Call, Storage, Event<T>, Config<T>},
Council: council::{Module, Call, Storage, Event<T>, Config<T>},
Memo: memo::{Module, Call, Storage, Event<T>},
Members: members::{Module, Call, Storage, Event<T>, Config<T>},
Forum: forum::{Module, Call, Storage, Event<T>, Config<T>},
Migration: migration::{Module, Call, Storage, Event<T>},
Actors: actors::{Module, Call, Storage, Event<T>, Config},
DataObjectTypeRegistry: data_object_type_registry::{Module, Call, Storage, Event<T>, Config<T>},
DataDirectory: data_directory::{Module, Call, Storage, Event<T>},
Expand Down
85 changes: 67 additions & 18 deletions runtime/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,65 @@
#![allow(clippy::redundant_closure_call)] // disable it because of the substrate lib design

use crate::VERSION;
use common::currency::BalanceOf;
use rstd::prelude::*;
use sr_primitives::{print, traits::Zero};
use srml_support::{decl_event, decl_module, decl_storage};
use srml_support::{debug, decl_event, decl_module, decl_storage};

impl<T: Trait> Module<T> {
/// This method is called from on_initialize() when a runtime upgrade is detected. This
/// happens when the runtime spec version is found to be higher than the stored value.
/// Important to note this method should be carefully maintained, because it runs on every runtime
/// upgrade.
fn runtime_upgraded() {
print("running runtime initializers...");
print("Running runtime upgraded handler");

// ...
// add initialization of modules introduced in new runtime release. This
// Add initialization of modules introduced in new runtime release. Typically this
// would be any new storage values that need an initial value which would not
// have been initialized with config() or build() mechanism.
// ...
// have been initialized with config() or build() chainspec construction mechanism.
// Other tasks like resetting values, migrating values etc.

// Runtime Upgrade Code for going from Rome to Constantinople

// Create the Council mint. If it fails, we can't do anything about it here.
let _ = governance::council::Module::<T>::create_new_council_mint(
if let Err(err) = governance::council::Module::<T>::create_new_council_mint(
minting::BalanceOf::<T>::zero(),
);
) {
debug::warn!(
"Failed to create a mint for council during migration: {:?}",
err
);
}

// Reset working group mint capacity
if let Err(err) = content_working_group::Module::<T>::set_mint_capacity(
system::RawOrigin::Root.into(),
minting::BalanceOf::<T>::zero(),
) {
debug::warn!(
"Failed to reset mint for working group during migration: {:?}",
err
);
}

// Set Storage Role reward to zero
if let Some(parameters) =
roles::actors::Parameters::<T>::get(roles::actors::Role::StorageProvider)
{
if let Err(err) = roles::actors::Module::<T>::set_role_parameters(
system::RawOrigin::Root.into(),
roles::actors::Role::StorageProvider,
roles::actors::RoleParameters {
reward: BalanceOf::<T>::zero(),
..parameters
},
) {
debug::warn!(
"Failed to set zero reward for storage role during migration: {:?}",
err
);
}
}

proposals_codex::Module::<T>::set_default_config_values();

Expand All @@ -31,21 +73,23 @@ impl<T: Trait> Module<T> {

pub trait Trait:
system::Trait
+ storage::data_directory::Trait
+ storage::data_object_storage_registry::Trait
+ forum::Trait
+ sudo::Trait
+ governance::council::Trait
+ governance::election::Trait
+ content_working_group::Trait
+ roles::actors::Trait
+ proposals_codex::Trait
{
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}

decl_storage! {
trait Store for Module<T: Trait> as Migration {
/// Records at what runtime spec version the store was initialized. This allows the runtime
/// to know when to run initialize code if it was installed as an update.
pub SpecVersion get(spec_version) build(|_| VERSION.spec_version) : Option<u32>;
/// Records at what runtime spec version the store was initialized. At genesis this will be
/// initialized to Some(VERSION.spec_version). It is an Option because the first time the module
/// was introduced was as a runtime upgrade and type was never changed.
/// When the runtime is upgraded the spec version be updated.
pub SpecVersion get(spec_version) build(|_config: &GenesisConfig| {
VERSION.spec_version
}) : Option<u32>;
}
}

Expand All @@ -61,11 +105,16 @@ decl_module! {

fn on_initialize(_now: T::BlockNumber) {
if Self::spec_version().map_or(true, |spec_version| VERSION.spec_version > spec_version) {
// mark store version with current version of the runtime
// Mark store version with current version of the runtime
SpecVersion::put(VERSION.spec_version);

// run migrations and store initializers
// Run migrations and store initializers
Self::runtime_upgraded();

Self::deposit_event(RawEvent::Migrated(
<system::Module<T>>::block_number(),
VERSION.spec_version,
));
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions tests/network-tests/.env
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,11 @@ COUNCIL_STAKE_GREATER_AMOUNT = 1500
COUNCIL_STAKE_LESSER_AMOUNT = 1000
# Number of members with greater stake in council election test.
COUNCIL_ELECTION_K = 2
# Stake for runtime upgrade proposal test
RUNTIME_UPGRADE_PROPOSAL_STAKE = 200
# Balance to spend using spending proposal
SPENDING_BALANCE = 1000
# Minting capacity increment for content working group minting capacity test.
MINTING_CAPACITY_INCREMENT = 20
# Minting capacity for council mint for spending proposal.
COUNCIL_MINTING_CAPACITY = 100000
# Stake amount for Rome runtime upgrade proposal
RUNTIME_UPGRADE_PROPOSAL_STAKE = 100000
7 changes: 5 additions & 2 deletions tests/network-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
"license": "GPL-3.0-only",
"scripts": {
"build": "tsc --build tsconfig.json",
"test": "mocha -r ts-node/register src/tests/*",
"test": "mocha -r ts-node/register src/tests/constantinople/proposals/*",
"test-migration": "mocha -r ts-node/register src/tests/rome/* && mocha -r ts-node/register src/tests/constantinople/*",
"lint": "tslint --project tsconfig.json",
"prettier": "prettier --write ./src"
},
"dependencies": {
"@joystream/types": "^0.7.0",
"@joystream/types": "../joystream-apps/packages/joy-types",
"@rome/types@npm:@joystream/types": "^0.7.0",
"@polkadot/api": "^0.96.1",
"@polkadot/keyring": "^1.7.0-beta.5",
"@types/bn.js": "^4.11.5",
"bn.js": "^4.11.8",
"dotenv": "^8.2.0",
"fs": "^0.0.1-security",
"uuid": "^7.0.3"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { membershipTest } from './membershipCreationTest';
import { KeyringPair } from '@polkadot/keyring/types';
import { ApiWrapper } from '../utils/apiWrapper';
import { ApiWrapper } from '../../utils/apiWrapper';
import { WsProvider, Keyring } from '@polkadot/api';
import { initConfig } from '../utils/config';
import { initConfig } from '../../utils/config';
import BN = require('bn.js');
import { registerJoystreamTypes, Seat } from '@joystream/types';
import { assert } from 'chai';
import { v4 as uuid } from 'uuid';
import { Utils } from '../utils/utils';
import { Utils } from '../../utils/utils';

export function councilTest(m1KeyPairs: KeyringPair[], m2KeyPairs: KeyringPair[]) {
initConfig();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Keyring } from '@polkadot/keyring';
import { assert } from 'chai';
import { KeyringPair } from '@polkadot/keyring/types';
import BN = require('bn.js');
import { ApiWrapper } from '../utils/apiWrapper';
import { initConfig } from '../utils/config';
import { ApiWrapper } from '../../utils/apiWrapper';
import { initConfig } from '../../utils/config';
import { v4 as uuid } from 'uuid';

export function membershipTest(nKeyPairs: KeyringPair[]) {
Expand Down Expand Up @@ -50,8 +50,8 @@ export function membershipTest(nKeyPairs: KeyringPair[]) {
);
nKeyPairs.forEach((keyPair, index) =>
apiWrapper
.getMembership(keyPair.address)
.then(membership => assert(!membership.isEmpty, `Account ${keyPair.address} is not a member`))
.getMemberIds(keyPair.address)
.then(membership => assert(membership.length > 0, `Account ${keyPair.address} is not a member`))
);
}).timeout(defaultTimeout);

Expand All @@ -65,7 +65,9 @@ export function membershipTest(nKeyPairs: KeyringPair[]) {
)
);
await apiWrapper.buyMembership(aKeyPair, paidTerms, `late_member_${aKeyPair.address.substring(0, 8)}`, true);
apiWrapper.getMembership(aKeyPair.address).then(membership => assert(membership.isEmpty, 'Account A is a member'));
apiWrapper
.getMemberIds(aKeyPair.address)
.then(membership => assert(membership.length === 0, 'Account A is a member'));
}).timeout(defaultTimeout);

it('Account A was able to buy the membership with sufficient funds', async () => {
Expand All @@ -77,8 +79,8 @@ export function membershipTest(nKeyPairs: KeyringPair[]) {
);
await apiWrapper.buyMembership(aKeyPair, paidTerms, `late_member_${aKeyPair.address.substring(0, 8)}`);
apiWrapper
.getMembership(aKeyPair.address)
.then(membership => assert(!membership.isEmpty, 'Account A is a not member'));
.getMemberIds(aKeyPair.address)
.then(membership => assert(membership.length > 0, 'Account A is a not member'));
}).timeout(defaultTimeout);

after(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { initConfig } from '../../../utils/config';
import { Keyring, WsProvider } from '@polkadot/api';
import { KeyringPair } from '@polkadot/keyring/types';
import { membershipTest } from '../membershipCreationTest';
import { councilTest } from '../electingCouncilTest';
import { registerJoystreamTypes } from '@joystream/types';
import { ApiWrapper } from '../../../utils/apiWrapper';
import { v4 as uuid } from 'uuid';
import BN = require('bn.js');
import { assert } from 'chai';

describe('Spending proposal network tests', () => {
initConfig();
const keyring = new Keyring({ type: 'sr25519' });
const nodeUrl: string = process.env.NODE_URL!;
const sudoUri: string = process.env.SUDO_ACCOUNT_URI!;
const spendingBalance: BN = new BN(+process.env.SPENDING_BALANCE!);
const mintCapacity: BN = new BN(+process.env.COUNCIL_MINTING_CAPACITY!);
const defaultTimeout: number = 120000;

const m1KeyPairs: KeyringPair[] = new Array();
const m2KeyPairs: KeyringPair[] = new Array();

let apiWrapper: ApiWrapper;
let sudo: KeyringPair;

before(async function () {
this.timeout(defaultTimeout);
registerJoystreamTypes();
const provider = new WsProvider(nodeUrl);
apiWrapper = await ApiWrapper.create(provider);
});

membershipTest(m1KeyPairs);
membershipTest(m2KeyPairs);
councilTest(m1KeyPairs, m2KeyPairs);

it('Spending proposal test', async () => {
// Setup
sudo = keyring.addFromUri(sudoUri);
const description: string = 'spending proposal which is used for API network testing with some mock data';
const runtimeVoteFee: BN = apiWrapper.estimateVoteForProposalFee();

// Topping the balances
const proposalStake: BN = await apiWrapper.getRequiredProposalStake(25, 10000);
const runtimeProposalFee: BN = apiWrapper.estimateProposeSpendingFee(
description,
description,
proposalStake,
spendingBalance,
sudo.address
);
await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, runtimeProposalFee.add(proposalStake));
await apiWrapper.transferBalanceToAccounts(sudo, m2KeyPairs, runtimeVoteFee);
await apiWrapper.sudoSetCouncilMintCapacity(sudo, mintCapacity);

// Proposal creation
const proposalPromise = apiWrapper.expectProposalCreated();
await apiWrapper.proposeSpending(
m1KeyPairs[0],
'testing spending' + uuid().substring(0, 8),
'spending to test proposal functionality' + uuid().substring(0, 8),
proposalStake,
spendingBalance,
sudo.address
);
const proposalNumber = await proposalPromise;

// Approving spending proposal
const balanceBeforeMinting: BN = await apiWrapper.getBalance(sudo.address);
const spendingPromise = apiWrapper.expectProposalFinalized();
await apiWrapper.batchApproveProposal(m2KeyPairs, proposalNumber);
await spendingPromise;
const balanceAfterMinting: BN = await apiWrapper.getBalance(sudo.address);
assert(
balanceAfterMinting.sub(balanceBeforeMinting).eq(spendingBalance),
`member ${
m1KeyPairs[0].address
} has unexpected balance ${balanceAfterMinting}, expected ${balanceBeforeMinting.add(spendingBalance)}`
);
}).timeout(defaultTimeout);

after(() => {
apiWrapper.close();
});
});
Loading