-
Notifications
You must be signed in to change notification settings - Fork 10
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(storage): check and clean for pallet smart contract #659
feat(storage): check and clean for pallet smart contract #659
Conversation
To run the "migration" live against Devnet do: cargo run --release --features=try-runtime try-runtime --runtime target/release/wbuild/tfchain-runtime/tfchain_runtime.compact.wasm --chain chainspecs/main/chainSpecRaw.json on-runtime-upgrade live --uri ws://10.10.0.151:9944 Note that the process consists in: |
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.
Where is the new storage version actually set?
|
||
impl<T: Config> OnRuntimeUpgrade for CheckStorageStateV9<T> { | ||
fn on_runtime_upgrade() -> Weight { | ||
if PalletVersion::<T>::get() == types::StorageVersion::V9 { |
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.
This won't work on all networks, since the version on qa/test/main is v8
It is not set because there is no modification of the structure, and this check/clean is valid for
Indeed but the purpose of this check/clean is related to a specific version.
cargo run --release --features=try-runtime try-runtime --runtime target/release/wbuild/tfchain-runtime/tfchain_runtime.compact.wasm --chain chainspecs/main/chainSpecRaw.json on-runtime-upgrade live --uri ws://10.10.0.151:9944 I wanted to integrate them by using |
@@ -25,7 +25,7 @@ pub enum StorageVersion { | |||
|
|||
impl Default for StorageVersion { | |||
fn default() -> StorageVersion { | |||
StorageVersion::V9 | |||
StorageVersion::V8 |
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.
Since we are going to V9, default is now V9
I added the weights and made it compatible with Run on:
And no remaining warnings after cleaning |
if !ContractLock::<T>::contains_key(contract_id) { | ||
let now = <timestamp::Pallet<T>>::get().saturated_into::<u64>() / 1000; | ||
r += 1; | ||
let mut contract_lock = types::ContractLock::default(); | ||
contract_lock.lock_updated = now; | ||
ContractLock::<T>::insert(contract_id, contract_lock); | ||
w += 1; | ||
} |
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.
Not sure it is the right thing to do here, in case there is no contract lock associated to a contract
Current weight is above the block threshold:
|
@renauter I refactored the logging, and set all logs to debug. You can now see all the logs from your migration like:
Because logging in production also takes up compute time. I also put back the Post/Pre checks. I know why they were not firing, see: tfchain/substrate-node/runtime/src/lib.rs Line 989 in fba8109
|
Now that we know that the storage migration takes 123% of a total blocks weight we need to think about execution strategy. Either we optimize the migration code OR we do a rolling migration that is triggered by an extrinsic? |
Nice! So I guess I can remove the weights from the checking process |
I just re-checked and as the checking process is now done on pre/post checks, as it should be (because never meant to be executed on-chain but is meant to be used by testing tools), the
Which corresponds to the cleaning process alone that would be performed on-chain. |
@renauter on which network did you execute to get a 30% blockweight execution time? It's crucial this is measured against mainnet (which is the biggest chain in terms of data) |
Indeed, was on devnet... my bad
So for the strategies:
There is no other way to run the migration in 2 steps? |
@DylanVerstraete out of reach in Telegram |
Oh damn, that some hard censorship right there |
Indeed, It s the second time in 1 year ... |
I adapted the strategy of the migration code to be able to simulate the rolling migration and check if storage was effectively cleaned by executing the following steps: (1) run a local node with the actual (forked) chain_specs of dev/test/mainnet (2) run a
(3) do a runtime upgrade using (4) when migration ended, repeat step (2) to check storage AFTER cleaning |
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.
Great work. Some comments:
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
contract_id, contract.contract_id | ||
); | ||
} | ||
if !contract_id_range.contains(&contract_id) { |
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.
I'm not sure I get why you are checking if the id is in the range. It's always the case no? And if it would not be the case why not do:
let current_contract_id = ContractID::<T>::get();
to then replace this if by:
if contract_id >= current_contract_id
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.
I'm not sure I get why you are checking if the id is in the range. It's always the case no?
Indeed, it should always be the case that s why I am checking it to identify bad cases that could result from old code.
We never know, I have seen some unexpected cases investigating the storage.
And if it would not be the case why not do: ...
Because I also want to check contract_id > 0
so using the range I check both at the same time with same complexity I guess
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.
But ContractID is u64 so it can never be < 0... It will always be >= 0
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.
Indeed we still want to identify contract_id == 0
case
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.
Yes but that simplifies the check to
if contract_id == 0 {
// log
}
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.
Yes, I could have done
if contract_id == 0 || contract_id > ContractID::<T>::get() {
// log
}
but I found it more elegant to do
let contract_id_range = 1..=ContractID::<T>::get();
if !contract_id_range.contains(&contract_id) {
// log
}
I think complexity is same, correct?
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
substrate-node/pallets/pallet-smart-contract/src/storage_state/v9.rs
Outdated
Show resolved
Hide resolved
// ✅ ContractsToBillAt | ||
// ✅ Contracts | ||
// ✅ ActiveNodeContracts | ||
// ✅ ActiveRentContractForNode | ||
// ✅ ContractIDByNodeIDAndHash | ||
// ✅ ContractIDByNameRegistration | ||
// ✅ ContractLock | ||
// ✅ SolutionProviders | ||
// ✅ ContractBillingInformationByID | ||
// ✅ NodeContractResources |
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.
Remove commented code
"🔎 CleanBillingLoop pre migration: Number of existing billing loop indexes {:?}", | ||
contracts_to_bill_count | ||
fn check_node_contract<T: Config>(node_id: u32, contract_id: u64, deployment_hash: HexHash) { | ||
if let Some(_) = pallet_tfgrid::Nodes::<T>::get(node_id) { |
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.
The contained value of the Some variant is not used, so this check only cares if the key exists at all, which according to the docs can be checked as:
if let Some(_) = pallet_tfgrid::Nodes::<T>::get(node_id) { | |
if pallet_tfgrid::Nodes::<T>::contains_key(node_id) { |
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.
indeed
which is also equivalent to:
if pallet_tfgrid::Nodes::<T>::get(node_id).is_some() {
correct?
pre_contracts_to_bill_count, | ||
"Number of billing loop indexes migrated does not match" | ||
fn check_rent_contract<T: Config>(node_id: u32, contract: &types::Contract<T>) { | ||
if let Some(_) = pallet_tfgrid::Nodes::<T>::get(node_id) { |
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.
if let Some(_) = pallet_tfgrid::Nodes::<T>::get(node_id) { | |
if pallet_tfgrid::Nodes::<T>::contains_key(node_id) { |
Related to: