Closed sameh-farouk closed 1 month ago
Looks like this PR is quite big and contains many things.
Is it possible to split the PR into smaller things? Smaller PR will make it easier to test and review.
Looks like this PR is quite big and contains many things.
Is it possible to split the PR into smaller things? Smaller PR will make it easier to test and review.
Hi @iwanbk Thank you for your feedback. I understand the concern about the size of the PR. However, this PR is a comprehensive refactor of a large function, which includes modified structure, function names, and numerous fixes. Splitting it into smaller PRs would complicate the process for several reasons:
I believe keeping the PR as a single unit will ensure a smoother review and testing process. I am, of course, open to any specific suggestions you might have to improve the PR.
Thank you @renauter for your review! I have either addressed or replied to your notes. Please review and let me know if you have any further comments.
[2024-08-25T23:16:53Z INFO pallet_smart_contract::migrations::v12] >>> Unused Smart Contract pallet V12 migration
[2024-08-25T23:16:53Z INFO try-runtime::cli] PoV size (zstd-compressed compact proof): 579.5 KB. For parachains, it's your responsibility to verify that a PoV of this size fits within any relaychain constraints.
[2024-08-25T23:16:53Z INFO try-runtime::cli] Consumed ref_time: 1.464225s (73.21% of max 2s)
[2024-08-25T23:16:53Z INFO try-runtime::cli] ā
No weight safety issues detected. Please note this does not guarantee a successful runtime upgrade. Always test your runtime upgrade with recent state, and ensure that the weight usage of your migrations will not drastically differ between testing and actual on-chain execution.
Storage migration tested on Mainnet with try-runtime
Before starting to distribute rewards (which funds should come from previously reserved amounts) I feel a lack of extra check similar to ensure( account_reserved >= standard_rewards + additional_rewards)
.
Maybe located here: https://github.com/threefoldtech/tfchain/blob/b4431147e74987f9a1119f61910855973eae2f71/substrate-node/pallets/pallet-smart-contract/src/billing.rs#L507
With some comment like // At this point we don't expect any distribution failure since every fund to transfer should have been accumulated in account reserve along previous billing cycles
It would prevent some failure in billing logic, since funds reservation is at different phase in code (after some cycles of reseration everything reserved is transfered), and add better readability to code.
What do you think ?
Before starting to distribute rewards (which funds should come from previously reserved amounts) I feel a lack of extra check similar to
ensure( account_reserved >= standard_rewards + additional_rewards)
.Maybe located here:
With some comment like
// At this point we don't expect any distribution failure since every fund to transfer should have been accumulated in account reserve along previous billing cycles
It would prevent some failure in billing logic, since funds reservation is at different phase in code (after some cycles of reseration everything reserved is transfered), and add better readability to code.What do you think ?
I added the comment for clarity.
One last change
I switched from using ValueQuery
to OptionQuery
for the ContractPaymentState
. It is more prone to error since it always returns a default value from storage.
Although we ensure that every contract has a payment state, the default value does not make sense here.
Imagine calculating the cost for a contract where the last updated time in the payment state is 0!
I prefer to have a None returned and fail gracefully, rather than having a default value.
I switched from using ValueQuery to OptionQuery for the ContractPaymentState. It is more prone to error since it always returns a default value from storage.
Indeed, if we don't make a specific usage of a default value it is more convenient to use OptionQuery
.
@renauter Thank you so much for reviewing! It was really helpful.
@sameh-farouk Thank you for your tremendous work!! This refactoring was a very hard task šš»šš»šš»
Description
This PR addresses several issues and introduces significant changes to the billing in the pallet-smart-contract module. Here are the key changes and the issues they resolve:
High-Level Changes:
Find below more details
Key Changes and Improvements:
Refactoring Billing Logic:
The billing logic has been refactored to improve the billing feature for smart contracts. This includes more precise tracking of contract payments, handling of overdrafts, and fund reservations.
Improved off-chain worker logic
Updated off-chain worker logic to handle billing more effectively.
is_next_block_author
function was removed and the verification is now happening at runtime, ensuring that transaction fees are reliably waived for validators and still preventing duplicate transactions. It also implements a guaranteed execution layer for OCWs by enabling redundancy.Benefits:
Additionally, the improved logging ensures that the off-chain worker function works correctly without silent failures.
Introduction of ContractPaymentState:
Introducing ContractPaymentState aligns with the need to track and manage contract payment states accurately, especially during grace periods and when handling overdue payments. It fixes the issue where the amount tracked in the contract lock is incorrectly divergent from the lock on the user balance, leading to illiquidity issues when it's time to distribute rewards.
Improved Error Handling:
Enhanced error-handling mechanisms have been introduced to ensure that errors during billing are logged and appropriately managed, reducing the likelihood of contracts entering a dirty state.
Also, New error types were added
RewardDistributionError
andContractPaymentStateNotExists
.Enhanced Events:
New events have been added, ContractGracePeriodElapsed, ContractPaymentOverdrafted, and RewardDistributed, to provide better visibility into the billing and payment processes.
ContractPaymentOverdrawn
: This event is closely related to the ContractBilled event. Both events provide information about the amount due for the previous billing period. The ContractBilled event indicates that the due amount was successfully charged to the user's account. In contrast, the ContractPaymentOverdrawn event signifies that the due amount was not fully covered and has been added to the contract's overdraft. This distinction helps in accurately tracking the financial state of contracts.RewardDistributed
: This event signifies the successful distribution of rewards after the billing cycle, providing transparency and traceability for reward payouts.ContractGracePeriodElapsed
: This event is triggered when a contract has exceeded its grace period without sufficient funds, leading to its transition to a deleted state.Other Events changes:
Locked
: It have been replaced with Reserved event.TokenBurned
: The TokenBurned event is no longer emitted, reflecting the removal of TFT burning from TFChain.Unlocked
andTransfer
Events: Both the Unlocked and Transfer events have been replaced with theReserveRepatriated
event.Issues Addressed:
Issue #996
Issue #991:
Issue #990:
Issue #979:
Issue #969 :
Issue #932 :
Issue #834:
Issue #994:
Overall, this PR enhances the billing capabilities of the pallet-smart-contract module, making it more robust and reliable.
TODO
Some reconsideration might be needed, such as:
Using the newer hold in the fungible trait instead of reserves in reservableCurrency, as the latter is marked for deprecation in future versions.Checklist: