Skip to content

Commit

Permalink
Merge pull request #5031 from mnaamani/nara-bugfix-disable-amm-when-f…
Browse files Browse the repository at this point in the history
…rozen

project-token pallet: disable all amm dispatch calls when pallet is frozen
  • Loading branch information
mnaamani authored Jan 17, 2024
2 parents e3db20d + 5b6b487 commit 09fc425
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 52 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/run-network-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ jobs:
name: Runtime Upgrade from production runtime
needs: build_images
runs-on: ubuntu-latest
if: github.ref != 'refs/heads/master'
# Disabling until we find a workaround
# as it is no longer practical to start the node
# while importing huge state from production network in genesis block.
# if: github.ref != 'refs/heads/master'
if: false
steps:
# Checkout master branch
- name: check out master repo
Expand Down
14 changes: 14 additions & 0 deletions runtime-modules/content/src/tests/creator_tokens/activate_amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
use crate::tests::fixtures::*;
use crate::tests::mock::*;
use crate::*;
use frame_support::assert_ok;
use frame_system::RawOrigin;
use project_token::Error as ProjectTokenError;

#[test]
fn unsuccessful_activate_amm_non_existing_channel() {
Expand Down Expand Up @@ -155,3 +158,14 @@ fn unsuccessful_activate_member_channel_creator_token_amm_with_ongoing_transfer(
.call_and_assert(Err(Error::<Test>::InvalidChannelTransferStatus.into()));
})
}

#[test]
fn unsuccessful_activate_creator_token_amm_with_frozen_pallet() {
with_default_mock_builder(|| {
ContentTest::with_member_channel().setup();
IssueCreatorTokenFixture::default().call_and_assert(Ok(()));
assert_ok!(Token::set_frozen_status(RawOrigin::Root.into(), true));
ActivateAmmFixture::default()
.call_and_assert(Err(ProjectTokenError::<Test>::PalletFrozen.into()));
})
}
15 changes: 15 additions & 0 deletions runtime-modules/content/src/tests/creator_tokens/deactivate_amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
use crate::tests::fixtures::*;
use crate::tests::mock::*;
use crate::*;
use frame_support::assert_ok;
use frame_system::RawOrigin;
use project_token::Error as ProjectTokenError;

#[test]
fn unsuccessful_deactivate_amm_non_existing_channel() {
Expand Down Expand Up @@ -135,3 +138,15 @@ fn successful_deactivate_curator_channel_creator_token_amm_by_lead() {
.call_and_assert(Ok(()));
})
}

#[test]
fn unsuccessful_deactivate_creator_token_amm_with_frozen_pallet() {
with_default_mock_builder(|| {
ContentTest::with_member_channel().setup();
IssueCreatorTokenFixture::default().call_and_assert(Ok(()));
ActivateAmmFixture::default().call_and_assert(Ok(()));
assert_ok!(Token::set_frozen_status(RawOrigin::Root.into(), true));
DeactivateAmmFixture::default()
.call_and_assert(Err(ProjectTokenError::<Test>::PalletFrozen.into()));
})
}
6 changes: 4 additions & 2 deletions runtime-modules/content/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Proof: Content CuratorGroupById (max_values: None, max_size: Some(1037), added: 3512, mode: MaxEncodedLen)
// Storage: Token TokenInfoById (r:1 w:1)
// Proof: Token TokenInfoById (max_values: None, max_size: Some(352), added: 2827, mode: MaxEncodedLen)
// Storage: Token PalletFrozen (r:1 w:0)
// Storage: Token MinAmmSlopeParameter (r:1 w:0)
// Proof: Token MinAmmSlopeParameter (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen)
// Storage: System Account (r:1 w:1)
Expand All @@ -1321,7 +1322,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Minimum execution time: 188_296 nanoseconds.
Weight::from_parts(192_189_000, 0u64)
.saturating_add(Weight::from_parts(0, 21427))
.saturating_add(T::DbWeight::get().reads(6_u64))
.saturating_add(T::DbWeight::get().reads(7_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
}
// Storage: Content ChannelById (r:1 w:0)
Expand All @@ -1332,6 +1333,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Proof: Content CuratorGroupById (max_values: None, max_size: Some(1037), added: 3512, mode: MaxEncodedLen)
// Storage: Token TokenInfoById (r:1 w:1)
// Proof: Token TokenInfoById (max_values: None, max_size: Some(352), added: 2827, mode: MaxEncodedLen)
// Storage: Token PalletFrozen (r:1 w:0)
// Storage: Token AmmDeactivationThreshold (r:1 w:0)
// Proof: Token AmmDeactivationThreshold (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
// Storage: System Account (r:1 w:0)
Expand All @@ -1343,7 +1345,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Minimum execution time: 164_519 nanoseconds.
Weight::from_parts(166_906_000, 0u64)
.saturating_add(Weight::from_parts(0, 21415))
.saturating_add(T::DbWeight::get().reads(6_u64))
.saturating_add(T::DbWeight::get().reads(7_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
// Storage: Content ChannelById (r:1 w:0)
Expand Down
8 changes: 8 additions & 0 deletions runtime-modules/project-token/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,8 @@ decl_module! {
/// - event deposited
#[weight = WeightInfoToken::<T>::buy_on_amm_with_existing_account()]
fn buy_on_amm(origin, token_id: T::TokenId, member_id: T::MemberId, amount: <T as Config>::Balance, slippage_tolerance: Option<(Permill, JoyBalanceOf<T>)>) -> DispatchResult {
Self::ensure_unfrozen_state()?;

if amount.is_zero() {
return Ok(()); // noop
}
Expand Down Expand Up @@ -916,6 +918,8 @@ decl_module! {
/// - event deposited
#[weight = WeightInfoToken::<T>::sell_on_amm()]
fn sell_on_amm(origin, token_id: T::TokenId, member_id: T::MemberId, amount: <T as Config>::Balance, slippage_tolerance: Option<(Permill, JoyBalanceOf<T>)>) -> DispatchResult {
Self::ensure_unfrozen_state()?;

if amount.is_zero() {
return Ok(()); // noop
}
Expand Down Expand Up @@ -1577,6 +1581,8 @@ impl<T: Config>
member_id: T::MemberId,
params: AmmParamsOf<T>,
) -> DispatchResult {
Self::ensure_unfrozen_state()?;

let token_data = Self::ensure_token_exists(token_id)?;

ensure!(
Expand Down Expand Up @@ -1620,6 +1626,8 @@ impl<T: Config>
/// - state set to idle
/// - event deposited
fn deactivate_amm(token_id: T::TokenId, member_id: T::MemberId) -> DispatchResult {
Self::ensure_unfrozen_state()?;

let token_data = Self::ensure_token_exists(token_id)?;
Self::ensure_amm_can_be_deactivated(&token_data)?;

Expand Down
59 changes: 59 additions & 0 deletions runtime-modules/project-token/src/tests/amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::tests::mock::*;
use crate::types::{AmmCurve, AmmOperation, VestingScheduleParamsOf};
use crate::{joy, last_event_eq, member, token, Error, RawEvent, RepayableBloatBondOf};
use frame_support::{assert_err, assert_ok};
use frame_system::RawOrigin;
use sp_arithmetic::traits::One;
use sp_runtime::{traits::Zero, DispatchError, Permill};

Expand Down Expand Up @@ -978,3 +979,61 @@ fn amm_deactivation_ok_with_event_deposit() {
));
})
}

#[test]
fn amm_buy_fails_when_pallet_frozen() {
let token_id = token!(1);
let amm_joy_variation = amm_function_buy_values(DEFAULT_AMM_BUY_AMOUNT, Zero::zero());
let (_, user_account_id) = member!(2);
build_default_test_externalities_with_balances(vec![(
user_account_id,
amm_joy_variation + ed(),
)])
.execute_with(|| {
IssueTokenFixture::default().execute_call().unwrap();
ActivateAmmFixture::default().execute_call().unwrap();

AmmBuyFixture::default()
.with_amount(DEFAULT_AMM_BUY_AMOUNT)
.execute_call()
.unwrap();

assert_ok!(Token::set_frozen_status(RawOrigin::Root.into(), true));

assert_err!(
AmmBuyFixture::default()
.with_amount(DEFAULT_AMM_BUY_AMOUNT)
.execute_call(),
Error::<Test>::PalletFrozen
);
})
}

#[test]
fn amm_sell_fails_when_pallet_frozen() {
let amm_joy_variation = amm_function_buy_values(DEFAULT_AMM_BUY_AMOUNT, Zero::zero());
let (_, user_account_id) = member!(2);
build_default_test_externalities_with_balances(vec![(
user_account_id,
amm_joy_variation + ed(),
)])
.execute_with(|| {
IssueTokenFixture::default().execute_call().unwrap();
ActivateAmmFixture::default().execute_call().unwrap();
AmmBuyFixture::default().execute_call().unwrap();

AmmSellFixture::default()
.with_amount(0u32.into())
.execute_call()
.unwrap();

assert_ok!(Token::set_frozen_status(RawOrigin::Root.into(), true));

assert_err!(
AmmSellFixture::default()
.with_amount(0u32.into())
.execute_call(),
Error::<Test>::PalletFrozen
);
})
}
9 changes: 6 additions & 3 deletions runtime-modules/project-token/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
}
// Storage: Token PalletFrozen (r:1 w:0)
// Storage: Membership MembershipById (r:1 w:0)
// Proof: Membership MembershipById (max_values: None, max_size: Some(125), added: 2600, mode: MaxEncodedLen)
// Storage: Token TokenInfoById (r:1 w:1)
Expand All @@ -246,9 +247,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Minimum execution time: 85_398 nanoseconds.
Weight::from_parts(87_934_000, 0u64)
.saturating_add(Weight::from_parts(0, 20547))
.saturating_add(T::DbWeight::get().reads(7_u64))
.saturating_add(T::DbWeight::get().reads(8_u64))
.saturating_add(T::DbWeight::get().writes(4_u64))
}
// Storage: Token PalletFrozen (r:1 w:0)
// Storage: Membership MembershipById (r:1 w:0)
// Proof: Membership MembershipById (max_values: None, max_size: Some(125), added: 2600, mode: MaxEncodedLen)
// Storage: Token TokenInfoById (r:1 w:1)
Expand All @@ -268,9 +270,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Minimum execution time: 86_178 nanoseconds.
Weight::from_parts(88_253_000, 0u64)
.saturating_add(Weight::from_parts(0, 20547))
.saturating_add(T::DbWeight::get().reads(7_u64))
.saturating_add(T::DbWeight::get().reads(8_u64))
.saturating_add(T::DbWeight::get().writes(4_u64))
}
// Storage: Token PalletFrozen (r:1 w:0)
// Storage: Membership MembershipById (r:1 w:0)
// Proof: Membership MembershipById (max_values: None, max_size: Some(125), added: 2600, mode: MaxEncodedLen)
// Storage: Token TokenInfoById (r:1 w:1)
Expand All @@ -288,7 +291,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Minimum execution time: 73_200 nanoseconds.
Weight::from_parts(75_404_000, 0u64)
.saturating_add(Weight::from_parts(0, 19046))
.saturating_add(T::DbWeight::get().reads(6_u64))
.saturating_add(T::DbWeight::get().reads(8_u64))
.saturating_add(T::DbWeight::get().writes(4_u64))
}
}
Expand Down
3 changes: 2 additions & 1 deletion tests/network-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"multihashes": "^4.0.3",
"node-cleanup": "^2.1.2",
"@joystream/js": "^1.6.0",
"uuid": "^7.0.3"
"uuid": "^7.0.3",
"sleep-promise": "^9.1.0"
},
"devDependencies": {
"@graphql-codegen/cli": "^1.21.4",
Expand Down
30 changes: 6 additions & 24 deletions tests/network-tests/run-runtime-upgrade-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ cd $SCRIPT_PATH

rm ./output.json || :

# Log only to stderr
# Only output from this script should be the container id of the node at the very end

# Location that will be mounted to /spec in containers
# This is where the initial balances files and generated chainspec files will be located.
DATA_PATH=$PWD/data
Expand Down Expand Up @@ -118,14 +115,16 @@ function fork_off_init() {

# download the raw storage state
if ! [[ -f ${DATA_PATH}/storage.json ]]; then
echo >&2 "fetching state storage from $HTTP_RPC_ENDPOINT"
curl $HTTP_RPC_ENDPOINT -H \
"Content-type: application/json" -d \
'{"jsonrpc":"2.0","id":1,"method":"state_getPairs","params":["0x"]}' \
>${DATA_PATH}/storage.json
echo >&2 "storage trie downloaded at ${DATA_PATH}/storage.json"
fi

yarn workspace api-scripts tsnode-strict src/fork-off.ts ${DATA_PATH} ${WS_RPC_ENDPOINT}
yarn workspace api-scripts tsnode-strict --max-old-space-size=6144 \
src/fork-off.ts ${DATA_PATH} ${WS_RPC_ENDPOINT}
}

#######################################
Expand Down Expand Up @@ -166,7 +165,6 @@ function main {
# 3. set path to new runtime.wasm
set_new_runtime_wasm_path
echo >&2 "new wasm path set"
<<<<<<< HEAD

# 4. early chain db init
export JOYSTREAM_NODE_TAG=${RUNTIME}
Expand All @@ -187,29 +185,13 @@ function main {
# Wait for chain and query node to get in sync
sleep 200

# 6. Bootstrap storage infra
./start-storage.sh
export REUSE_KEYS=true
export SKIP_STORAGE_AND_DISTRIBUTION=true

# Do some setup and checks before the upgrade
./run-test-scenario.sh preRuntimeUpgrade
=======
# 4. copy chainspec to disk
export_chainspec_file_to_disk
echo >&2 "chainspec exported"
# 5. start node
CONTAINER_ID=$(start_old_joystream_node)
echo >&2 "mainnet node starting"

# wait 1 minute
sleep 90

# 6. Bootstrap storage infra because we need to run content-directory tests after runtime upgrade
if [ "${NO_STORAGE}" != true ]; then
./start-storage.sh
fi
>>>>>>> master

# Do some setup and checks before the upgrade
./run-test-scenario.sh preRuntimeUpgrade

./run-test-scenario.sh runtimeUpgrade

Expand Down
4 changes: 4 additions & 0 deletions tests/network-tests/src/flows/content/activeVideoCounters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '../../fixtures/content'
import BN from 'bn.js'
import { createJoystreamCli } from '../utils'
import sleep from 'sleep-promise'

export default async function activeVideoCounters({ api, query, env }: FlowProps): Promise<void> {
const debug = extendDebug('flow:active-video-counters')
Expand Down Expand Up @@ -50,6 +51,9 @@ export default async function activeVideoCounters({ api, query, env }: FlowProps
await new FixtureRunner(createChannelsAndVideos).run()
const { channelIds, videosData } = createChannelsAndVideos.getCreatedItems()

// Allow time for processor to process videos created
await sleep(10 * 1000)

// check that active video counters are working
const activeVideoCountersFixture = new ActiveVideoCountersFixture(
api,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
DeleteVideoAssetsAsModeratorParams,
} from '../../fixtures/content/curatorModeration/DeleteVideoAssetsByModerator'
import { createJoystreamCli } from '../utils'
import sleep from 'sleep-promise'

export default async function curatorModerationActions({ api, query }: FlowProps): Promise<void> {
const debug = extendDebug('flow:curator-moderation-actions')
Expand Down Expand Up @@ -73,6 +74,9 @@ export default async function curatorModerationActions({ api, query }: FlowProps

const { channelIds, videosData } = createChannelsAndVideos.getCreatedItems()

// Allow time for processor to process videos created
await sleep(10 * 1000)

// create curator & curator group

const createCuratorGroupParams: CuratorGroupParams[] = [
Expand Down
1 change: 1 addition & 0 deletions utils/api-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@polkadot/util": "9.5.1",
"@polkadot/util-crypto": "9.5.1",
"@types/bn.js": "^5.1.0",
"bfj": "^8.0.0",
"bn.js": "^5.2.1"
},
"devDependencies": {
Expand Down
Loading

0 comments on commit 09fc425

Please sign in to comment.