-
Notifications
You must be signed in to change notification settings - Fork 1k
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
SmartContract: use executing contract state to check permissions #3290
Conversation
Isn't this by design? I mean, it also makes sense to me to use the new state right after the its updated. Can you explain a little bit more about what problem can this cause that makes it a bug? |
354d7b1
to
a148dd8
Compare
I doubt so. This is a quite severe bug that may lead to unwanted consequences. Besides, all other similar places use executing contract state, for example:
Sure, one of possible problems is described in nspcc-dev/neo-go#3471. The contract is being prohibited from updating (by buggy NeoGo node) because new manifest does not allow the notification that old contract code emits after update. Another unwanted consequence of this bug is: consider the contract being destroyed and calling another contract after that. Without this fix the destroy transaction will be FAULTed. In general, every contract call after update/destroy is affected by this bug. Also, Jimmy, I'm kindly asking not to modify the PR (this or others). You may leave the comments, and I'm always here to give a response and fix something. But I think we need to come to an agreement before modifying the code (to avoid situations like #3209 (comment)). |
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 understand the change,
However, I see that it would need a HF, otherwise we could fall in the same problem and discussion we recently have had.
I understand, but: mainnet/testnet check is in progress (I'll write once it's finished) and this change likely did not affect the mainnet's state since it's hard to meet the trigger criteria. And if no one pushes such transaction to the chain in the nearest future, then it will be safe to update without hardfork. Thus, @roman-khimov's suggestion was to try to avoid introducing hardfork for this change. |
Unfortunately, this expectation can not guide our decision, @AnnaShaleva . |
We can have it HF-dependent, no problem with that. |
Good, then I'll update the code. |
Ok, that is a first point. Now it is time to discuss the issue itself...aheuaheua |
It's not correct to use an updated contract state got from native Management to check for the allowed method call. We need to use manifest from the currently executing context for that. It may be critical for cases when executing contract is being updated firstly, and after that it calls another contract. So we need an old (executing) contract manifest for this check. This change is moved under D hardfork to avoid state diff issues on nodes update. Although it should be noted that it's hard to meet the trigger criteria. A port of nspcc-dev/neo-go#3473. This bug was discovered during the similar problem described in nspcc-dev/neo-go#3471 and fixed in nspcc-dev/neo-go#3472. I've checked all other similar usages and the rest of them use proper contract state (executing one, not the Management's one). Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
a148dd8
to
407c7d5
Compare
Done, ready for review. |
@@ -15,6 +15,7 @@ public enum Hardfork : byte | |||
{ | |||
HF_Aspidochelone, | |||
HF_Basilisk, | |||
HF_Cockatrice | |||
HF_Cockatrice, | |||
HF_Domovoi |
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.
Suggestions on name are welcomed.
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 am not familier with any of them, LOL, LGTM
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.
Same as Jimmy
i think now it's okay to merge |
but the necessity of this PR is worth discussing again i don't think there's any FAULT in the original design. it's just which impl is better |
It's using wrong manifest for permission checks after the update. And can't work at all after destroy. Contracts can have any code after update/destroy (not supposed to, but can), so either it works correctly or fails in unpredictable manner. |
Maybe it's by design. And they're actually predictable if they can understand what will happen under current implementation. Running new What is more curious is how many |
Mainnet is checked and confirmed not to be affected by this bug up to 5484582 height (ref. nspcc-dev/neo-go#3473 (comment)). However, it can be changed at any moment if a suitable transaction will be pushed to mainnet (see #3290 (comment)). And since we decide not to allow state changes anymore, we'd better move it under hardfork.
There's one more explicit call to the executing contract state (see the #3290 (comment)) and a wide set of calls to other executing context-bound things like call flags.
Yes, they do, that's why I've created this PR. |
It's better to show an example here for developers to decide which is good. Let's say. There is an old contract on chain whose code are as follows.
** Notice that
For problem 2, it seems that we should follow From what I understand, what this PR is trying to change is for problem 1's external call control (the notification control already follows 1.a). The old implementation is 1.b and the new implementation is 1.a. Please correct me if I'm wrong here @AnnaShaleva @roman-khimov . |
Execution context must be consistent. Contract is NEF+manifest. If we have a contract loaded into VM it must use appropriate manifest that is was deployed with. We're not changing contract's code (NEF, effectively) on the invocation stack after update, right? We're not aborting its execution after destroy. So, we must not change its manifest. Checking permissions against some new version (or failing if contract is destroyed) when we have old bytecode executing is just wrong. |
After playing with those examples, I stand with @AnnaShaleva if my understanding on that example is right. |
okay i'm convinced and let's merge |
There is another external-call method called |
Although simple I stand with @lingyido in his example, I just worry about the change in the logic as in comment #3290 (comment) Devs should be aware of this change |
It's not correct to use an updated contract state got from Management to check for the allowed method call. We need to use manifest from the currently executing context for that. It may be critical for cases when executing contract is being updated firstly, and after that calls another contract. So we need an old (executing) contract manifest for this check. This change likely does not affect the mainnet's state since it's hard to meet the trigger criteria, but I'd put it under the hardfork anyway. Ref. neo-project/neo#3290. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
* [Neo Core Bug]fix 3300 (#3301) * fix 3300 * update format * add state subitems to ref counter, with suggestion from DuSmart * apply hardfork * format * my mistake * fix hardfork * remove negative check * add unit test * apply anna's suggestion --------- Co-authored-by: Shargon <shargon@gmail.com> Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> * SmartContract: use executing contract state to check permissions (#3290) It's not correct to use an updated contract state got from native Management to check for the allowed method call. We need to use manifest from the currently executing context for that. It may be critical for cases when executing contract is being updated firstly, and after that it calls another contract. So we need an old (executing) contract manifest for this check. This change is moved under D hardfork to avoid state diff issues on nodes update. Although it should be noted that it's hard to meet the trigger criteria. A port of nspcc-dev/neo-go#3473. This bug was discovered during the similar problem described in nspcc-dev/neo-go#3471 and fixed in nspcc-dev/neo-go#3472. I've checked all other similar usages and the rest of them use proper contract state (executing one, not the Management's one). Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru> Co-authored-by: Shargon <shargon@gmail.com> Co-authored-by: Jimmy <jinghui@wayne.edu> Co-authored-by: Vitor Nazário Coelho <vncoelho@gmail.com> * v3.7.5 * Neo.CLI: enable hardforks for NeoFS mainnet (#3240) Otherwise this configuration file is broken. Port changes from nspcc-dev/neo-go#3446. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru> * fix workflow & FS config * remove hardfork for fs testnet --------- Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru> Co-authored-by: Jimmy <jinghui@wayne.edu> Co-authored-by: Shargon <shargon@gmail.com> Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> Co-authored-by: Anna Shaleva <shaleva.ann@nspcc.ru> Co-authored-by: Vitor Nazário Coelho <vncoelho@gmail.com>
Description
It's not correct to use an updated contract state got from native Management to check for the allowed method call. We need to use manifest from the currently executing context for that. It may be critical for cases when executing contract is being updated firstly, and after that it calls another contract. So we need an old (executing) contract manifest for this check.
This change likely does not affect the mainnet's state since it's hard to meet the trigger criteria, thus we suggest not to use a hardfok.
A port of nspcc-dev/neo-go#3473. This bug was discovered during the similar problem fix in nspcc-dev/neo-go#3471 and nspcc-dev/neo-go#3472. I've checked all other similar usages and the rest of them use proper contract state (executing one, not the Management's one).
Type of change
How Has This Been Tested?
TestSystem_Contract_Call_Permissions
unit testIn progress: check mainnet states for compatibilityMoved under D hardfork.Checklist: