-
Notifications
You must be signed in to change notification settings - Fork 302
Update transaction_payment_wrapper: charge fees for hotkey from its coldkey #2570
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
evgeny-s
wants to merge
9
commits into
devnet-ready
Choose a base branch
from
coldkey-pays-tx-fees-if-hotkey-origin
base: devnet-ready
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
f5ce6d8
- Coldkey pays tx fees for its hotkey
evgeny-s fc1a548
- `set_weight` is changed to paid extrinsic
evgeny-s 385dd03
- rename acc
evgeny-s c4915c6
- Added test - no ownership
evgeny-s c1a5111
- clippy fix
evgeny-s 19dfc69
- Added filter for specific transactions
evgeny-s 1c4fbb0
- Added e2e tests
evgeny-s 4fda83b
- lint
evgeny-s 01113d4
- added type generation to run scripts
evgeny-s File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| #![allow(clippy::arithmetic_side_effects, clippy::unwrap_used)] | ||
|
|
||
| use { | ||
| frame_support::assert_ok, | ||
| node_subtensor_runtime::ExistentialDeposit, | ||
| node_subtensor_runtime::{BuildStorage, Runtime, RuntimeGenesisConfig, System}, | ||
| pallet_subtensor::{ | ||
| BurnHalfLife, BurnIncreaseMult, Error, FirstEmissionBlockNumber, Pallet as SubtensorPallet, | ||
| SubnetAlphaIn, SubnetAlphaInProvided, SubnetTAO, SubtokenEnabled, | ||
| }, | ||
| substrate_fixed::types::U64F64, | ||
| subtensor_runtime_common::{AccountId, AlphaBalance, NetUid, TaoBalance}, | ||
| }; | ||
|
|
||
| pub const ONE: [u8; 32] = [1_u8; 32]; | ||
| pub const TWO: [u8; 32] = [2_u8; 32]; | ||
| pub const THREE: [u8; 32] = [3_u8; 32]; | ||
| pub const FOUR_NO_BALANCE: [u8; 32] = [4_u8; 32]; | ||
|
|
||
| pub fn new_test_ext() -> sp_io::TestExternalities { | ||
| sp_tracing::try_init_simple(); | ||
| let amount = TaoBalance::from(1_000_000_000_000_u64); | ||
| let mut ext: sp_io::TestExternalities = RuntimeGenesisConfig { | ||
| balances: pallet_balances::GenesisConfig { | ||
| balances: vec![ | ||
| (AccountId::from(ONE), amount), | ||
| (AccountId::from(TWO), amount), | ||
| (AccountId::from(THREE), amount), | ||
| ], | ||
| dev_accounts: None, | ||
| }, | ||
| ..Default::default() | ||
| } | ||
| .build_storage() | ||
| .unwrap() | ||
| .into(); | ||
| ext.execute_with(|| System::set_block_number(1)); | ||
| ext | ||
| } | ||
|
|
||
| pub fn add_network_disable_commit_reveal(netuid: NetUid, tempo: u16, _modality: u16) { | ||
| add_network(netuid, tempo, _modality); | ||
| SubtensorPallet::<Runtime>::set_commit_reveal_weights_enabled(netuid, false); | ||
| SubtensorPallet::<Runtime>::set_yuma3_enabled(netuid, false); | ||
| } | ||
|
|
||
| pub fn add_network(netuid: NetUid, tempo: u16, _modality: u16) { | ||
| SubtensorPallet::<Runtime>::init_new_network(netuid, tempo); | ||
| SubtensorPallet::<Runtime>::set_network_registration_allowed(netuid, true); | ||
| FirstEmissionBlockNumber::<Runtime>::insert(netuid, 1); | ||
| SubtokenEnabled::<Runtime>::insert(netuid, true); | ||
|
|
||
| // make interval 1 block so tests can register by stepping 1 block. | ||
| BurnHalfLife::<Runtime>::insert(netuid, 1); | ||
| BurnIncreaseMult::<Runtime>::insert(netuid, U64F64::from_num(1)); | ||
| } | ||
|
|
||
| pub(crate) fn setup_reserves(netuid: NetUid, tao: TaoBalance, alpha: AlphaBalance) { | ||
| SubnetTAO::<Runtime>::set(netuid, tao); | ||
| SubnetAlphaIn::<Runtime>::set(netuid, alpha); | ||
| } | ||
|
|
||
| pub fn register_ok_neuron( | ||
| netuid: NetUid, | ||
| hotkey_account_id: AccountId, | ||
| coldkey_account_id: AccountId, | ||
| _start_nonce: u64, | ||
| ) { | ||
| SubtensorPallet::<Runtime>::set_burn(netuid, TaoBalance::from(0)); | ||
| let reserve: u64 = 1_000_000_000_000; | ||
| let tao_reserve = SubnetTAO::<Runtime>::get(netuid); | ||
| let alpha_reserve = | ||
| SubnetAlphaIn::<Runtime>::get(netuid) + SubnetAlphaInProvided::<Runtime>::get(netuid); | ||
|
|
||
| if tao_reserve == 0.into() && alpha_reserve == 0.into() { | ||
| setup_reserves(netuid, reserve.into(), reserve.into()); | ||
| } | ||
|
|
||
| // Ensure coldkey has enough to pay the current burn AND is not fully drained to zero. | ||
| // This avoids ZeroBalanceAfterWithdrawn in burned_register. | ||
| let top_up_for_burn = |netuid: NetUid, cold: AccountId| { | ||
| let burn: TaoBalance = SubtensorPallet::<Runtime>::get_burn(netuid); | ||
| let burn_u64: TaoBalance = burn; | ||
|
|
||
| // Make sure something remains after withdrawal even if ED is 0 in tests. | ||
| let ed: TaoBalance = ExistentialDeposit::get(); | ||
| let min_remaining: TaoBalance = ed.max(1.into()); | ||
|
|
||
| // Small buffer for safety (fees / rounding / future changes). | ||
| let buffer: TaoBalance = 10.into(); | ||
|
|
||
| let min_balance_needed: TaoBalance = burn_u64 + min_remaining + buffer; | ||
|
|
||
| let bal: TaoBalance = SubtensorPallet::<Runtime>::get_coldkey_balance(&cold); | ||
| if bal < min_balance_needed { | ||
| SubtensorPallet::<Runtime>::add_balance_to_coldkey_account( | ||
| &cold, | ||
| min_balance_needed - bal, | ||
| ); | ||
| } | ||
| }; | ||
|
|
||
| top_up_for_burn(netuid, coldkey_account_id.clone()); | ||
|
|
||
| let origin = | ||
| <<Runtime as frame_system::Config>::RuntimeOrigin>::signed(coldkey_account_id.clone()); | ||
| let result = SubtensorPallet::<Runtime>::burned_register( | ||
| origin.clone(), | ||
| netuid, | ||
| hotkey_account_id.clone(), | ||
| ); | ||
|
|
||
| match result { | ||
| Ok(()) => { | ||
| // success | ||
| } | ||
| Err(e) | ||
| if e == Error::<Runtime>::TooManyRegistrationsThisInterval.into() | ||
| || e == Error::<Runtime>::NotEnoughBalanceToStake.into() | ||
| || e == Error::<Runtime>::ZeroBalanceAfterWithdrawn.into() => | ||
| { | ||
| // Re-top-up and retry once (burn can be state-dependent). | ||
| top_up_for_burn(netuid, coldkey_account_id.clone()); | ||
|
|
||
| assert_ok!(SubtensorPallet::<Runtime>::burned_register( | ||
| origin, | ||
| netuid, | ||
| hotkey_account_id.clone() | ||
| )); | ||
| } | ||
| Err(e) => { | ||
| panic!("Expected Ok(_). Got Err({e:?})"); | ||
| } | ||
| } | ||
| SubtensorPallet::<Runtime>::set_burn(netuid, TaoBalance::from(0)); | ||
| log::info!( | ||
| "Register ok neuron: netuid: {netuid:?}, coldkey: {coldkey_account_id:?}, hotkey: {hotkey_account_id:?}" | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| mod common; | ||
| use common::new_test_ext; | ||
| use common::*; | ||
| use frame_support::assert_ok; | ||
| use frame_support::dispatch::GetDispatchInfo; | ||
| use frame_support::sp_runtime::traits::DispatchTransaction; | ||
| use node_subtensor_runtime::{ | ||
| Runtime, RuntimeCall, RuntimeOrigin, | ||
| transaction_payment_wrapper::ChargeTransactionPaymentWrapper, | ||
| }; | ||
| use pallet_subtensor::Pallet as SubtensorPallet; | ||
| use subtensor_runtime_common::{AccountId, NetUid}; | ||
|
|
||
| // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package node-subtensor-runtime --test subtensor_weights -- set_weights_fees_payed_by_coldkey --exact --nocapture | ||
| #[test] | ||
| fn set_weights_fees_payed_by_coldkey() { | ||
| new_test_ext().execute_with(|| { | ||
| let hotkey = AccountId::from(common::FOUR_NO_BALANCE); | ||
| let coldkey = AccountId::from(common::TWO); | ||
| let netuid0 = NetUid::from(1); | ||
| let netuid1 = NetUid::from(2); | ||
|
|
||
| SubtensorPallet::<Runtime>::set_weights_set_rate_limit(netuid0, 0); | ||
|
|
||
| add_network_disable_commit_reveal(netuid0, 1, 0); | ||
| add_network_disable_commit_reveal(netuid1, 1, 0); | ||
| register_ok_neuron(netuid0, hotkey.clone(), coldkey.clone(), 2143124); | ||
| register_ok_neuron(netuid1, hotkey.clone(), coldkey.clone(), 3124124); | ||
|
|
||
| let hotkey_balance_before = pallet_balances::Pallet::<Runtime>::free_balance(&hotkey); | ||
| let coldkey_balance_before = pallet_balances::Pallet::<Runtime>::free_balance(&coldkey); | ||
|
|
||
| let weights_keys: Vec<u16> = vec![0]; | ||
| let weight_values: Vec<u16> = vec![1]; | ||
|
|
||
| let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::set_weights { | ||
| netuid: netuid0, | ||
| dests: weights_keys, | ||
| weights: weight_values, | ||
| version_key: 0, | ||
| }); | ||
|
|
||
| let info = call.get_dispatch_info(); | ||
| let ext = ChargeTransactionPaymentWrapper::<Runtime>::new(0.into()); | ||
| assert_ok!(ext.dispatch_transaction( | ||
| RuntimeOrigin::signed(hotkey.clone()).into(), | ||
| call, | ||
| &info, | ||
| 0, | ||
| 0, | ||
| )); | ||
|
|
||
| let hotkey_balance_after = pallet_balances::Pallet::<Runtime>::free_balance(&hotkey); | ||
| let coldkey_balance_after = pallet_balances::Pallet::<Runtime>::free_balance(&coldkey); | ||
|
|
||
| assert_eq!(hotkey_balance_before, hotkey_balance_after); | ||
| assert!(coldkey_balance_after < coldkey_balance_before); // Fee paid by coldkey | ||
| }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
...s/suites/dev/subtensor/transaction-payment-wrapper/00-transaction-payment-wrapper.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { beforeAll, expect } from "vitest"; | ||
| import { describeSuite } from "@moonwall/cli"; | ||
| import { generateKeyringPair, tao } from "../../../../utils"; | ||
| import type { ApiPromise } from "@polkadot/api"; | ||
| import { devForceSetBalance, devSetWeightsTx, devTryAssociateHotkey } from "../../../../utils/dev-helpers.ts"; | ||
|
|
||
| describeSuite({ | ||
| id: "00_transaction_payment_wrapper_dev", | ||
| title: "Transaction payment wrapper", | ||
| foundationMethods: "dev", | ||
| testCases: ({ it, context, log }) => { | ||
| let api: ApiPromise; | ||
|
|
||
| beforeAll(() => { | ||
| api = context.polkadotJs(); | ||
| }); | ||
|
|
||
| it({ | ||
| id: "T01", | ||
| title: "Check set_weights", | ||
| test: async () => { | ||
| const coldkey = generateKeyringPair("sr25519"); | ||
| const hotkey = generateKeyringPair("sr25519"); | ||
|
|
||
| log(`coldkey: ${coldkey.address}`); | ||
| log(`hotkey: ${hotkey.address}`); | ||
|
|
||
| const initialBalance = tao(1e10); | ||
|
|
||
| log("Set Up"); | ||
| await devForceSetBalance(api, context, coldkey.address, initialBalance); | ||
| await devForceSetBalance(api, context, hotkey.address, initialBalance); | ||
| await devTryAssociateHotkey(api, context, coldkey, hotkey.address); | ||
|
|
||
| const coldkeyBalanceBefore = (await api.query.system.account(coldkey.address)).data.free.toBigInt(); | ||
|
|
||
| log("Execute the tx from hotkey, but coldkey will pay"); | ||
| await devSetWeightsTx(api, context, hotkey, 0, [], [], 0n); | ||
|
|
||
| const events = await api.query.system.events(); | ||
| const feeEvent = events.filter((a) => { | ||
| return a.event.method.toString() === "TransactionFeePaid"; | ||
| }); | ||
|
|
||
| const hotkeyBalance = (await api.query.system.account(hotkey.address)).data.free.toBigInt(); | ||
| const coldkeyBalanceAfter = (await api.query.system.account(coldkey.address)).data.free.toBigInt(); | ||
| // Fees paid by the hotkey | ||
| const txFee = feeEvent[0].event.data.actualFee.toBigInt(); | ||
| expect(txFee).toBeGreaterThan(0n); | ||
| expect(coldkeyBalanceAfter).toEqual(coldkeyBalanceBefore - txFee); | ||
| expect(hotkeyBalance).toEqual(initialBalance); | ||
| }, | ||
| }); | ||
| }, | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@l0r1s , added the additional validation for the list of extrinsics we want to apply this to.