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

Feat/childkey take #699

Merged
merged 46 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c179c8e
Update localnet.sh to include a flag for fast_blocks for E2E testing
opendansor Jun 7, 2024
54d186c
Merge pull request #515 from opendansor/patch-1
opendansor Jun 11, 2024
09c146b
Merge pull request #585 from opentensor/devnet
distributedstatemachine Jun 26, 2024
50fa9ad
Merge pull request #668 from opentensor/merge_hot_swap
unconst Jul 22, 2024
59d9cbd
chore: update spec version
Jul 22, 2024
ce8e91b
Merge pull request #670 from opentensor/testnet_rebase
unconst Jul 22, 2024
42f7dfa
Merge pull request #678 from opentensor/devnet-ready
unconst Jul 23, 2024
4f016d2
Merge pull request #682 from opentensor/devnet-ready
unconst Jul 23, 2024
efdce2e
Merge branch 'testnet' into devnet
Jul 26, 2024
c5566a7
Merge remote-tracking branch 'origin/testnet' into devnet
Jul 26, 2024
8d8a668
Merge branch 'devnet' into devnet_conflcit
Jul 26, 2024
62c1527
clippy
Jul 26, 2024
cd23ac2
chore: clippy
Jul 29, 2024
6843cc7
Merge pull request #695 from opentensor/devnet_conflcit
distributedstatemachine Jul 29, 2024
4a0eada
Merge pull request #694 from opentensor/devnet
sam0x17 Jul 29, 2024
8ce0d69
feat: child key takes
Jul 30, 2024
9917c03
chore: lints
Jul 30, 2024
b656a58
feat: benchmarks
Jul 30, 2024
ee8aa6b
chore: remove todos
Jul 30, 2024
c1dbc59
chore: remove more comments
Jul 30, 2024
01cabbd
chore: multiple network child key takes
Jul 30, 2024
f7f243c
chore: clippy
Jul 30, 2024
06f1b9d
bump spec version
Jul 30, 2024
d8acb8b
feat: isabella question
Jul 30, 2024
5d48fae
chore: PR review comments
Jul 31, 2024
b1037ab
chore: clippy
Jul 31, 2024
531417a
chore: bump spec
Jul 31, 2024
06013f8
chore: remove childkey take removal
Aug 2, 2024
1a88e73
Merge remote-tracking branch 'origin/devnet-ready' into feat/childkey…
Aug 5, 2024
9b557c4
feat: fix child take tests
Aug 5, 2024
6764633
feat: add more childkey tests
Aug 7, 2024
3de5b03
Update run_coinbase.rs
JohnReedV Aug 7, 2024
037b76d
add test_blocks_since_last_step
JohnReedV Aug 7, 2024
a6d13f6
Add short default tempo to fast-blocks feature
gztensor Aug 8, 2024
1011425
Add short InitialTxChildkeyTakeRateLimit to fast-blocks feature
gztensor Aug 8, 2024
68ec4c6
feat: bump network max stake
Aug 9, 2024
ae40d0f
chore: add sudo calls for setting min/max childkey takes
Aug 9, 2024
8f9e841
Merge pull request #725 from opentensor/feat/fast_tempo_for_fast_blocks
distributedstatemachine Aug 9, 2024
ce0dfa7
Fix rate limit for setting children
gztensor Aug 14, 2024
d6790a3
Use passes_rate_limit_on_subnet for setting children
gztensor Aug 16, 2024
cb35762
Merge pull request #733 from opentensor/fix/childkey-rate-limits
distributedstatemachine Aug 16, 2024
41fd2f6
Merge pull request #722 from opentensor/increment-blocks-since-last-step
unconst Aug 16, 2024
f1866df
draft take tests
Aug 9, 2024
aa19201
chore: make rate limit prettier
Aug 19, 2024
c68f4e4
chore: remove commented test
Aug 19, 2024
dc67f8f
chore: fmt
Aug 19, 2024
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
14 changes: 10 additions & 4 deletions pallets/admin-utils/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,15 @@ parameter_types! {
pub const InitialBondsMovingAverage: u64 = 900_000;
pub const InitialStakePruningMin: u16 = 0;
pub const InitialFoundationDistribution: u64 = 0;
pub const InitialDefaultTake: u16 = 11_796; // 18% honest number.
pub const InitialMinTake: u16 = 5_898; // 9%;
pub const InitialDefaultDelegateTake: u16 = 11_796; // 18% honest number.
pub const InitialMinDelegateTake: u16 = 5_898; // 9%;
pub const InitialDefaultChildKeyTake: u16 = 0; // Allow 0 %
pub const InitialMinChildKeyTake: u16 = 0; // Allow 0 %
pub const InitialWeightsVersionKey: u16 = 0;
pub const InitialServingRateLimit: u64 = 0; // No limit.
pub const InitialTxRateLimit: u64 = 0; // Disable rate limit for testing
pub const InitialTxDelegateTakeRateLimit: u64 = 0; // Disable rate limit for testing
pub const InitialTxChildKeyTakeRateLimit: u64 = 0; // Disable rate limit for testing
pub const InitialBurn: u64 = 0;
pub const InitialMinBurn: u64 = 0;
pub const InitialMaxBurn: u64 = 1_000_000_000;
Expand Down Expand Up @@ -146,14 +149,17 @@ impl pallet_subtensor::Config for Test {
type InitialPruningScore = InitialPruningScore;
type InitialBondsMovingAverage = InitialBondsMovingAverage;
type InitialMaxAllowedValidators = InitialMaxAllowedValidators;
type InitialDefaultTake = InitialDefaultTake;
type InitialMinTake = InitialMinTake;
type InitialDefaultDelegateTake = InitialDefaultDelegateTake;
type InitialMinDelegateTake = InitialMinDelegateTake;
type InitialDefaultChildKeyTake = InitialDefaultChildKeyTake;
type InitialMinChildKeyTake = InitialMinChildKeyTake;
type InitialWeightsVersionKey = InitialWeightsVersionKey;
type InitialMaxDifficulty = InitialMaxDifficulty;
type InitialMinDifficulty = InitialMinDifficulty;
type InitialServingRateLimit = InitialServingRateLimit;
type InitialTxRateLimit = InitialTxRateLimit;
type InitialTxDelegateTakeRateLimit = InitialTxDelegateTakeRateLimit;
type InitialTxChildKeyTakeRateLimit = InitialTxChildKeyTakeRateLimit;
type InitialBurn = InitialBurn;
type InitialMaxBurn = InitialMaxBurn;
type InitialMinBurn = InitialMinBurn;
Expand Down
6 changes: 3 additions & 3 deletions pallets/admin-utils/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ use mock::*;
fn test_sudo_set_default_take() {
new_test_ext().execute_with(|| {
let to_be_set: u16 = 10;
let init_value: u16 = SubtensorModule::get_default_take();
let init_value: u16 = SubtensorModule::get_default_delegate_take();
assert_eq!(
AdminUtils::sudo_set_default_take(
<<Test as Config>::RuntimeOrigin>::signed(U256::from(0)),
to_be_set
),
Err(DispatchError::BadOrigin)
);
assert_eq!(SubtensorModule::get_default_take(), init_value);
assert_eq!(SubtensorModule::get_default_delegate_take(), init_value);
assert_ok!(AdminUtils::sudo_set_default_take(
<<Test as Config>::RuntimeOrigin>::root(),
to_be_set
));
assert_eq!(SubtensorModule::get_default_take(), to_be_set);
assert_eq!(SubtensorModule::get_default_delegate_take(), to_be_set);
});
}

Expand Down
6 changes: 3 additions & 3 deletions pallets/collective/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,9 +951,9 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
///
/// If not `approved`:
/// - one event deposited.
/// Two removals, one mutation.
/// Computation and i/o `O(P)` where:
/// - `P` is number of active proposals
/// - two removals, one mutation.
/// - computation and i/o `O(P)` where:
/// - `P` is number of active proposals
fn do_approve_proposal(
seats: MemberCount,
yes_votes: MemberCount,
Expand Down
26 changes: 25 additions & 1 deletion pallets/subtensor/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ benchmarks! {
Subtensor::<T>::add_balance_to_coldkey_account(&coldkey.clone(), wallet_bal);

assert_ok!(Subtensor::<T>::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone()));
assert_ok!(Subtensor::<T>::do_become_delegate(RawOrigin::Signed(coldkey.clone()).into(), hotkey.clone(), Subtensor::<T>::get_default_take()));
assert_ok!(Subtensor::<T>::do_become_delegate(RawOrigin::Signed(coldkey.clone()).into(), hotkey.clone(), Subtensor::<T>::get_default_delegate_take()));

// Stake 10% of our current total staked TAO
let u64_staked_amt = 100_000_000_000;
Expand Down Expand Up @@ -429,4 +429,28 @@ reveal_weights {

}: reveal_weights(RawOrigin::Signed(hotkey.clone()), netuid, uids, weight_values, salt, version_key)

benchmark_sudo_set_tx_childkey_take_rate_limit {
// We don't need to set up any initial state for this benchmark
// as it's a simple setter function that only requires root origin
let new_rate_limit: u64 = 100;
}: sudo_set_tx_childkey_take_rate_limit(RawOrigin::Root, new_rate_limit)

benchmark_set_childkey_take {
// Setup
let netuid: u16 = 1;
let tempo: u16 = 1;
let seed: u32 = 1;
let coldkey: T::AccountId = account("Cold", 0, seed);
let hotkey: T::AccountId = account("Hot", 0, seed);
let take: u16 = 1000; // 10% in basis points

// Initialize the network
Subtensor::<T>::init_new_network(netuid, tempo);

// Register the hotkey
Subtensor::<T>::set_burn(netuid, 1);
let amount_to_be_staked = 1_000_000u32.into();
Subtensor::<T>::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked);
assert_ok!(Subtensor::<T>::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone()));
}: set_childkey_take(RawOrigin::Signed(coldkey), hotkey, netuid, take)
}
2 changes: 1 addition & 1 deletion pallets/subtensor/src/coinbase/run_coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl<T: Config> Pallet<T> {
mining_emission: u64,
) {
// --- 1. First, calculate the hotkey's share of the emission.
let take_proportion: I64F64 = I64F64::from_num(Delegates::<T>::get(hotkey))
let take_proportion: I64F64 = I64F64::from_num(Self::get_childkey_take(hotkey, netuid))
.saturating_div(I64F64::from_num(u16::MAX));
let hotkey_take: u64 = take_proportion
.saturating_mul(I64F64::from_num(validating_emission))
Expand Down
62 changes: 50 additions & 12 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,27 @@ pub mod pallet {
21_000_000_000_000_000
}
#[pallet::type_value]
/// Default total stake.
pub fn DefaultDefaultTake<T: Config>() -> u16 {
T::InitialDefaultTake::get()
/// Default Delegate Take.
pub fn DefaultDelegateTake<T: Config>() -> u16 {
T::InitialDefaultDelegateTake::get()
}

#[pallet::type_value]
/// Default childkey take.
pub fn DefaultChildKeyTake<T: Config>() -> u16 {
T::InitialDefaultChildKeyTake::get()
}
#[pallet::type_value]
/// Default minimum take.
pub fn DefaultMinTake<T: Config>() -> u16 {
T::InitialMinTake::get()
/// Default minimum delegate take.
pub fn DefaultMinDelegateTake<T: Config>() -> u16 {
T::InitialMinDelegateTake::get()
}
#[pallet::type_value]
/// Default minimum childkey take.
pub fn DefaultMinChildKeyTake<T: Config>() -> u16 {
T::InitialMinChildKeyTake::get()
}

#[pallet::type_value]
/// Default account take.
pub fn DefaultAccountTake<T: Config>() -> u64 {
Expand Down Expand Up @@ -516,6 +528,11 @@ pub mod pallet {
T::InitialTxDelegateTakeRateLimit::get()
}
#[pallet::type_value]
/// Default value for chidlkey take rate limiting
pub fn DefaultTxChildKeyTakeRateLimit<T: Config>() -> u64 {
T::InitialTxChildKeyTakeRateLimit::get()
}
#[pallet::type_value]
/// Default value for last extrinsic block.
pub fn DefaultLastTxBlock<T: Config>() -> u64 {
0
Expand Down Expand Up @@ -567,10 +584,15 @@ pub mod pallet {
pub type TotalIssuance<T> = StorageValue<_, u64, ValueQuery, DefaultTotalIssuance<T>>;
#[pallet::storage] // --- ITEM ( total_stake )
pub type TotalStake<T> = StorageValue<_, u64, ValueQuery>;
#[pallet::storage] // --- ITEM ( default_take )
pub type MaxTake<T> = StorageValue<_, u16, ValueQuery, DefaultDefaultTake<T>>;
#[pallet::storage] // --- ITEM ( min_take )
pub type MinTake<T> = StorageValue<_, u16, ValueQuery, DefaultMinTake<T>>;
#[pallet::storage] // --- ITEM ( default_delegate_take )
pub type MaxDelegateTake<T> = StorageValue<_, u16, ValueQuery, DefaultDelegateTake<T>>;
#[pallet::storage] // --- ITEM ( min_delegate_take )
pub type MinDelegateTake<T> = StorageValue<_, u16, ValueQuery, DefaultMinDelegateTake<T>>;
#[pallet::storage] // --- ITEM ( default_childkey_take )
pub type MaxChildkeyTake<T> = StorageValue<_, u16, ValueQuery, DefaultChildKeyTake<T>>;
#[pallet::storage] // --- ITEM ( min_childkey_take )
pub type MinChildkeyTake<T> = StorageValue<_, u16, ValueQuery, DefaultMinChildKeyTake<T>>;

#[pallet::storage] // --- ITEM ( global_block_emission )
pub type BlockEmission<T> = StorageValue<_, u64, ValueQuery, DefaultBlockEmission<T>>;
#[pallet::storage] // --- ITEM (target_stakes_per_interval)
Expand Down Expand Up @@ -603,7 +625,19 @@ pub mod pallet {
#[pallet::storage]
/// MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation.
pub type Delegates<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDefaultTake<T>>;
StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDelegateTake<T>>;
#[pallet::storage]
/// DMAP ( hot, netuid ) --> take | Returns the hotkey childkey take for a specific subnet
pub type ChildkeyTake<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
T::AccountId, // First key: hotkey
Identity,
u16, // Second key: netuid
u16, // Value: take
ValueQuery,
>;

#[pallet::storage]
/// DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey.
pub type Stake<T: Config> = StorageDoubleMap<
Expand Down Expand Up @@ -921,10 +955,14 @@ pub mod pallet {
/// --- ITEM ( tx_rate_limit )
pub type TxRateLimit<T> = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit<T>>;
#[pallet::storage]
/// --- ITEM ( tx_rate_limit )
/// --- ITEM ( tx_delegate_take_rate_limit )
pub type TxDelegateTakeRateLimit<T> =
StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit<T>>;
#[pallet::storage]
/// --- ITEM ( tx_childkey_take_rate_limit )
pub type TxChildkeyTakeRateLimit<T> =
StorageValue<_, u64, ValueQuery, DefaultTxChildKeyTakeRateLimit<T>>;
#[pallet::storage]
/// --- MAP ( netuid ) --> Whether or not Liquid Alpha is enabled
pub type LiquidAlphaOn<T> =
StorageMap<_, Blake2_128Concat, u16, bool, ValueQuery, DefaultLiquidAlpha<T>>;
Expand Down
13 changes: 11 additions & 2 deletions pallets/subtensor/src/macros/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,16 @@ mod config {
type InitialMaxAllowedValidators: Get<u16>;
/// Initial default delegation take.
#[pallet::constant]
type InitialDefaultTake: Get<u16>;
type InitialDefaultDelegateTake: Get<u16>;
/// Initial minimum delegation take.
#[pallet::constant]
type InitialMinTake: Get<u16>;
type InitialMinDelegateTake: Get<u16>;
/// Initial default childkey take.
#[pallet::constant]
type InitialDefaultChildKeyTake: Get<u16>;
/// Initial minimum childkey take.
#[pallet::constant]
type InitialMinChildKeyTake: Get<u16>;
/// Initial weights version key.
#[pallet::constant]
type InitialWeightsVersionKey: Get<u64>;
Expand All @@ -128,6 +134,9 @@ mod config {
/// Initial delegate take transaction rate limit.
#[pallet::constant]
type InitialTxDelegateTakeRateLimit: Get<u64>;
/// Initial childkey take transaction rate limit.
#[pallet::constant]
type InitialTxChildKeyTakeRateLimit: Get<u64>;
/// Initial percentage of total stake required to join senate.
#[pallet::constant]
type InitialSenateRequiredStakePercentage: Get<u64>;
Expand Down
78 changes: 77 additions & 1 deletion pallets/subtensor/src/macros/dispatches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ mod dispatches {
.saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))]
pub fn become_delegate(origin: OriginFor<T>, hotkey: T::AccountId) -> DispatchResult {
Self::do_become_delegate(origin, hotkey, Self::get_default_take())
Self::do_become_delegate(origin, hotkey, Self::get_default_delegate_take())
}

/// --- Allows delegates to decrease its take value.
Expand Down Expand Up @@ -708,8 +708,84 @@ mod dispatches {
Ok(())
}

/// Sets the childkey take for a given hotkey.
///
/// This function allows a coldkey to set the childkey take for a given hotkey.
/// The childkey take determines the proportion of stake that the hotkey keeps for itself
/// when distributing stake to its children.
///
/// # Arguments:
/// * `origin` (<T as frame_system::Config>::RuntimeOrigin):
/// - The signature of the calling coldkey. Setting childkey take can only be done by the coldkey.
///
/// * `hotkey` (T::AccountId):
/// - The hotkey for which the childkey take will be set.
///
/// * `take` (u16):
/// - The new childkey take value. This is a percentage represented as a value between 0 and 10000,
/// where 10000 represents 100%.
///
/// # Events:
/// * `ChildkeyTakeSet`:
/// - On successfully setting the childkey take for a hotkey.
///
/// # Errors:
/// * `NonAssociatedColdKey`:
/// - The coldkey does not own the hotkey.
/// * `InvalidChildkeyTake`:
/// - The provided take value is invalid (greater than the maximum allowed take).
/// * `TxChildkeyTakeRateLimitExceeded`:
/// - The rate limit for changing childkey take has been exceeded.
///
#[pallet::call_index(68)]
#[pallet::weight((
Weight::from_parts(34_000, 0)
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2)),
DispatchClass::Normal,
Pays::Yes
))]
pub fn set_childkey_take(
origin: OriginFor<T>,
hotkey: T::AccountId,
netuid: u16,
take: u16,
) -> DispatchResult {
let coldkey = ensure_signed(origin)?;

// Call the utility function to set the childkey take
Self::do_set_childkey_take(coldkey, hotkey, netuid, take)
}

// ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------

/// Sets the transaction rate limit for changing childkey take.
///
/// This function can only be called by the root origin.
///
/// # Arguments:
/// * `origin` - The origin of the call, must be root.
/// * `tx_rate_limit` - The new rate limit in blocks.
///
/// # Errors:
/// * `BadOrigin` - If the origin is not root.
///
#[pallet::call_index(69)]
#[pallet::weight((
Weight::from_parts(6_000, 0)
.saturating_add(T::DbWeight::get().writes(1)),
DispatchClass::Operational,
Pays::No
))]
pub fn sudo_set_tx_childkey_take_rate_limit(
origin: OriginFor<T>,
tx_rate_limit: u64,
) -> DispatchResult {
ensure_root(origin)?;
Self::set_tx_childkey_take_rate_limit(tx_rate_limit);
Ok(())
}

// ==================================
// ==== Parameter Sudo calls ========
// ==================================
Expand Down
4 changes: 4 additions & 0 deletions pallets/subtensor/src/macros/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,9 @@ mod errors {
TooManyChildren,
/// Default transaction rate limit exceeded.
TxRateLimitExceeded,
/// Childkey take is invalid.
InvalidChildkeyTake,
/// Childkey take rate limit exceeded.
TxChildkeyTakeRateLimitExceeded,
}
}
8 changes: 8 additions & 0 deletions pallets/subtensor/src/macros/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ mod events {
TxRateLimitSet(u64),
/// setting the delegate take transaction rate limit.
TxDelegateTakeRateLimitSet(u64),
/// setting the childkey take transaction rate limit.
TxChildKeyTakeRateLimitSet(u64),
/// minimum childkey take set
MinChildKeyTakeSet(u16),
/// maximum childkey take set
MaxChildKeyTakeSet(u16),
/// childkey take set
ChildKeyTakeSet(T::AccountId, u16),
/// a sudo call is done.
Sudid(DispatchResult),
/// registration is allowed/disallowed for a subnet.
Expand Down
6 changes: 3 additions & 3 deletions pallets/subtensor/src/staking/become_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ impl<T: Config> Pallet<T> {
Error::<T>::DelegateTxRateLimitExceeded
);

// --- 5.1 Ensure take is within the min ..= InitialDefaultTake (18%) range
let min_take = MinTake::<T>::get();
let max_take = MaxTake::<T>::get();
// --- 5.1 Ensure take is within the min ..= InitialDefaultDelegateTake (18%) range
let min_take = MinDelegateTake::<T>::get();
let max_take = MaxDelegateTake::<T>::get();
ensure!(take >= min_take, Error::<T>::DelegateTakeTooLow);
ensure!(take <= max_take, Error::<T>::DelegateTakeTooHigh);

Expand Down
4 changes: 2 additions & 2 deletions pallets/subtensor/src/staking/decrease_take.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ impl<T: Config> Pallet<T> {
ensure!(take < current_take, Error::<T>::DelegateTakeTooLow);
}

// --- 3.1 Ensure take is within the min ..= InitialDefaultTake (18%) range
let min_take = MinTake::<T>::get();
// --- 3.1 Ensure take is within the min ..= InitialDefaultDelegateTake (18%) range
let min_take = MinDelegateTake::<T>::get();
ensure!(take >= min_take, Error::<T>::DelegateTakeTooLow);

// --- 4. Set the new take value.
Expand Down
Loading
Loading