-
Notifications
You must be signed in to change notification settings - Fork 389
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: lock token transfer and parameter module #3176
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is 📢 Thoughts on this report? Let us know! |
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.
Thank you for pushing this out 🙏
I think the direction is good, but I'd love to discuss more about some implementation details. I'm mostly worried about us having a temporary implementation detail as a permanent state of a core object (check comments).
Pinging @moul to give a review as well.
Please check the CI 🙏
id := ProposeUnlockSend() | ||
urequire.PanicsWithMessage( | ||
t, | ||
simpledao.ErrProposalNotAccepted.Error(), |
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.
Do you think we should standardize errors like these, to avoid having to import simpledao
?
It would mean that the dao package would need to know about specific implementation details like errors, so I'm not sure if this is the way to go
cc @moul
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.
Currently, GovDAO is a wrapper around the SimpleDAO. All voting and proposal functionality are implemented in SimpleDAO. I'm not sure if using the proposal errors defined in SimpleDAO will cause any issues down the line unless we decide to flatten the GovDAO implementation and stop wrapping the SimpleDAO package entirely.
On the other hand, whether GovDAO should be implemented as a SimpleDAO wrapper or not can be a separate topic.
stdout '(0 uint64)' | ||
|
||
|
||
## vote unlock proposal with unrestricted account test1 |
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.
Which accounts are going to be unrestricted in the initial version of the chain?
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.
For now, all GovDAO accounts that need to vote must be unrestricted from token transfer locking, as voting on a proposal requires sending fees to the contract.
gno.land/pkg/gnoland/app_test.go
Outdated
{key: "foo", kind: "bool", value: true}, | ||
{key: "foo", kind: "bytes", value: []byte{0x48, 0x69, 0x21}}, | ||
}, | ||
/* |
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.
Leftover?
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 is commented out since it conflicts with the alternative approach for the Params module in this PR. I believe we should avoid setting arbitrary parameter values in the genesis file without going through module validation.
We need to discuss it and agree on the approach.
// Otherwise, we cannot verify the unrestricted address in the genesis state. | ||
|
||
for _, addr := range data.Params.UnrestrictedAddrs { | ||
acc := ak.GetAccount(ctx, addr) |
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.
There is tight coupling here. The account keeper must have a previously initialized account in order for us to modify it in another func
Can't we keep the store of unrestricted accounts somewhere, instead of keeping the Unrestricted
information on the account itself?
My biggest concern is that we're coupling temporary logic (account balance transfer locks) into a structure that will be encoded and saved permanently to disk. Every time we use the account, even in 10 years, we will have to keep track of its "restricted state".
This is why I'm suggesting we go with an approach that isn't so coupled
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.
There are two reasons for implementing it this way:
-
There was a previous requirement to track and unlock token transfers on an individual account basis, not just for whitelisted accounts. That is the reason the restricted state is on the account level. We can revisit the requirement, otherwise, we will need to track the restricted state for a long time.
-
The whitelisted unrestricted accounts need to be validated to ensure they exist when we load the genesis state.
ok, err := ak.paramk.GetParams(ctx, ModuleName, "p", params) | ||
|
||
if !ok { | ||
panic("params key " + ModuleName + " does not exist") |
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.
Why panic?
tm2/pkg/sdk/auth/params.go
Outdated
TxSizeCostPerByte int64 `json:"tx_size_cost_per_byte" yaml:"tx_size_cost_per_byte"` | ||
SigVerifyCostED25519 int64 `json:"sig_verify_cost_ed25519" yaml:"sig_verify_cost_ed25519"` | ||
SigVerifyCostSecp256k1 int64 `json:"sig_verify_cost_secp256k1" yaml:"sig_verify_cost_secp256k1"` | ||
UnrestrictedAddrs []crypto.Address `json:"unrestricted_addrs" yaml:"unrestricted_addrs"` |
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.
Just a note we don't initialize this new field in DefaultParams
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.
By default, there are no unrestricted accounts since token transfer locking is off. Unrestricted accounts should be added to the genesis file when token locking is set to true. These accounts can be added manually or through a separate genesis command later in the production deployment.
🛠 PR Checks SummaryAll Automated Checks passed. ✅ Manual Checks (for Reviewers):
Read More🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers. ✅ Automated Checks (for Contributors):🟢 Maintainers must be able to edit this pull request (more info) ☑️ Contributor Actions:
☑️ Reviewer Actions:
📚 Resources:Debug
|
I was asked by Manfred to provide some feedback on the two different approaches. I don't have strong opinions one way or the other, here's what I consider:
If I was forced to choose, the "generic" approach seems to me simple to understand and to build on top of, and like I would shoot myself less frequently in the foot. But I'm not heavily swinging either way. |
@thehowl @moul The issue is not limited to key name and type validation. Allowing the creation and update of arbitrary chain parameters is unsafe and could lead to undetectable mistakes, potentially leaving the chain vulnerable to exploitation later. It's like using a map when we should be using a struct to pass parameters to the critical sections of a program. Here are some specifics:
In practice, proposals like this are difficult to verify in terms of their behavior and consequences because the behavior is implemented in the code itself.
Configurations can easily become out of sync with the code implementation without being noticed. This makes it challenging to track how these settings are linked in the code and how they impact chain behavior. This issue is especially problematic when we need to support backward-compatible features.
This constant does not match the genesis configuration, meaning changes in the genesis will never update the value of chainDomainParamPath as intended. gno/gno.land/genesis/genesis_params.toml Line 10 in 3fd5571
gno/gno.land/pkg/sdk/vm/params.go Line 7 in 3fd5571
It could get worse. Imagine if this property were created by GovDao instead of the genesis. All these small mistakes would be extremely difficult to detect. The old key could remain in the chain even after creating a new key |
Context for Locking Token Transfer
This feature allows us to lock token transfers, except for paying gas fees to add a package or call a contract. The restriction will be unlocked through GovDAO voting on a proposal.
We also want a few whitelisted, unrestricted accounts to vote on the proposal since a separate fee is required to initiate and vote on proposals.
This implementation manages the lock and unlock settings in r/sys/params, where we change the chain’s parameters. Calling lock or unlock will automatically submit a proposal to GovDAO. Once GovDAO votes and approves the proposal, the token
transfer restriction will be removed instantly.
All changes to parameters specified in r/sys/params must go through GovDAO voting.
Here are some implementation details
Main Idea Behind the Alternative Approach To implement parameter module ( Discussion)
Todo: update other params...
Contributors' checklist...