-
Notifications
You must be signed in to change notification settings - Fork 23
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
FLIP 198: Authorized Call #198
base: main
Are you sure you want to change the base?
Conversation
Thank you for opening this FLIP Thuận! From what I understand, the FLIP proposes to introduce a "capability-based Such a mechanism was previously proposed in a slightly different form: onflow/cadence#423 proposed adding an The FLIP for that future, onflow/flow#945, was eventually rejected. |
In addition to Bastian's feedback, any changes to access control need to account for the upcoming Entitlements feature, which is outline in https://github.com/onflow/flips/blob/main/cadence/20221214-auth-remodel.md and https://github.com/onflow/flips/blob/main/cadence/20230623-entitlement-improvements.md. The old access control model will be obsolete within a matter of months, so there is little point in changing it unless those changes also translate to the new entitlement-based model. |
Thank you for the responses. Firstly, I think this FLIP is more powerful in some aspects. At least, one of the implementations mentioned in the FLIP would be helpful. To me, if a contract is dominated by Capabilities, it is also dominated (dependent) by accounts (because Capabilities and Resources are obtained from them). This is the main difference, while this mechanism aims to release part of the contract from such things (related to accounts). Anyway, this is just an alternative option. Combining both would have given a good result, and developers will know which is most suitable for their projects. I have read that FLIP just now, but I'm still confused that it was rejected because there are problems in that FLIP or Cadence is sensitive to this mechanism. After all, since my FLIP is quite different, I would love to know the reasons why this should not be done. |
Thank you for your thoughts! First, I want to reply to some of them and go into "why capabilities" and "why not identity-based access control".
In what aspects is the proposed feature more powerful than the current access control API based on capabilities and entitlements, and in what way are these APIs annoying or even counterproductive? Do you have some examples? The capability-based access control API was just recently improved by introducing Capability Controllers, after a long discussion with lots of input from the community, and entitlements are also an improvement over the previous feature of refining access using interfaces based on restricted types. It would be great to hear how these improvements are not working out for you, especially given you mentioned a "scalability issue" for larger / more complex contracts.
Can you elaborate on that? The motivating example, granting access to a function, seems to be about "account access" by nature. What do you mean with "release part of the contract"?
The goal of Cadence is to provide a language to developers that is useful and safe. By design, it omits many features that are known to be unsafe (e.g. raw memory access) and provides features that allow developers to write safe programs (e.g. static type system). For any feature, there is always a trade-off between safety and convenience. Given that access control is a critical part of a smart contract, adding a feature that is potentially more convenient, but also leads to more bugs, does not align with Cadence's values. Often it is also the case that developers are not necessarily familiar with all security nuances of an aspect of smart contract development (e.g. here, access control, but also e.g. random number generation): They might be unaware of the short-comings of identity-based access control, or the issues with reverting random numbers. But neither should they! Cadence's goal is to provide tools to write useful programs, but also safe developers from mistakes. By providing safe features and guiding developers into using them, even inexperienced developers are able to write useful and safe contracts. Adding alternatives which appear more convenient, will attract developers, likely making the "power user" feature the first stop. To many developers the convenient solution may appear as the better solution, and they are likely unaware of the short-comings. In addition, having multiple features to achieve the same goal adds complexity. It will be hard for developers to reason about how the proposed functionality interacts with the existing functionality.
The FLIP was rejected, because the access-control model that the functionality in that FLIP and in this FLIP is based on, identity-based access control has many short comings and is known for many security issues for decades. For example, see: Security aside, Cadence encourages composability, but identity-based access control kills composability. Regarding the FLIP in particular:
Thank you again for your contributions into making Cadence better 👍 |
I think the question is; what is the practical use case to prefer identity to capability ? |
Hey @SnowyField1906! I know it's been a while since you wrote this suggestion up, and the team was very busy with the existing work for Cadence 1.0 (which has now shipped!). I'd love to dig into better understand the proposal again. For context: Cadence (with the 1.0 upgrade) currently has five levels of access control for calling methods on resources:
By default, the What I take from your proposal is that you would like a mechanism for limiting access to who can call a method that is distinct from all of these, and which works like
The reason I separate out the second from the first is that if your concern was just to have a more robust "friend" mechanism, we could introduce something like If you want to change access control dynamically, I'm left trying to find a scenario where this would be desirable. I think it comes down to a disagreement about the appropriate balance of power between the issuer of an asset (the entity that deployed the smart contract that defined the object) and the owner of the asset (the entity that currently stores and controls the object). Cadence was designed with the mindset that the issuer should have absolute control over deciding what an object "is" and how it behaves. However, once ownership of a specific instance is transferred to a user, we don't consider it desirable for the issuer to have the power to change how it can be used or transferred. If the issuer retains control, that doesn't feel like true ownership. I fear your proposal would make all of the following true:
I apologize if I sound a little preachy, but a lot of time and effort has gone into Flow and Cadence in the name of true ownership, so I thought it would be helpful to be very explicit as to why myself and others might be skeptical about a proposal that might undermine that. As an aside, access problems is easily solved with Entitlements, provided you are willing and able to give the owner of the object the power to decide who (if anyone) is allowed to access the protected functionality. If you still see a compelling case for functionality similar to what you've proposed, please provide it below. I encourage you to focus on giving an example of where it would be useful and how Cadence currently blocks that use case, instead of describing how you think Cadence should work. It could be that there are (or should be) alternative mechanisms that can solve your particular problem that fit better with the rest of the language. Thank you for your efforts on this suggestion, and my apologies again for the delayed response. |
To everything I have thought and experienced, Resource is awesome, honestly, I really loved to utilize this, because it is simply powerful and safe. You are right that my proposal is an extension of In my proposal, I also described the this accessibility behaves like Capabilities (Contracts will be like Resources) because the whole Contract can even be unaccessable for others, as long as they reveal their Address / Public Account for the Contract to work. And Capabilities between Contracts now are managed and indicated by the Cadence's sugar syntax itself, not messy by lines of codes anymore. (As far as I can remember) the thing I hate the most is using Factory in Cadence. Because I can't pass Resource from parent Contract into init scope of created Contract. And I can't send it via For simple logic, it destroys the integrity of the Contract, because the Contract now depends too much on the deployer accounts to send and receive Capabilities/Resources. Besides Factory, DAO also has some examples for this problem, it's been too long since I remember what Cadence can do so I can't think of a clever example, but for example a DAO with dynamic Custodians indexed in an array. We can't create And what do we lose here? 1 global Resource variable, whenever there is a change in Custodian, we have to remove each Capabilities and add each new Capabilities. The code will be bigger and more complex when the pattern is more complex. (Can users also falsify the Contract's integrity by sending/manipulating these Capabilities to others by themselves in order to make it unmatched with Contract data? I forgot). \ With my proposal, we can bury the verification part deep under the Interface or somewhere, and this verification depends automatically on the contract, no longer depends on the user. This kind of proposal will be for some system-level code that cannot address by Resources or simply when Resource becomes rebundant. I remember I encountered this problem when coding an OrderBook with many nested Contracts. The common point of all the problems I mentioned is the interaction and processing automatically and on-chain. Separate from the dependence on accounts and shorten a lot of unnecessary repetitive logic. And in some cases, using Resources becomes impossible, I think you will be able to find many better examples yourself. But maybe I'm wrong, I think Flow won't tend to do such things and Cadence won't like such complex Contracts, my grant MAMAEx#165 has not received any response after more than a year and we don't even want to deploy them even though everything from FE to Contracts is done and ready. Thank you very much for really working hard for Cadence and caring of proposals and developers. This is always my favourite chain, sadly I don't have chance to work on this anymore and I'm always looking forward to work on this chain again. And it is already too late for me to remember things for our discussion. |
@SnowyField1906: Thanks so much for taking the time to write this up, even though the specifics are hard for you to remember. We will be closing this proposal, but I want to assure you that the examples you've shared are very helpful, and I'll work through them to see if we can't make Cadence work better for those use cases. It's worth noting that Flow did release EVM support this year, and the best part is that the EVM is embedded inside Cadence, so you can mix Cadence and EVM code as needed for your use case. You should be able to use Cadence for the parts its best at while dropping down into EVM whenever you need to. I'm going to want to think about your examples more, but let me share my preliminary thoughts about how I'd handle the problems you presented, if only for your curiosity!
I have to admit the Factory use case isn't one I think about a lot, but I think that there's a key feature of Flow that isn't available in EVM that would make this use case a lot easier to think about. When you create an new Account object in Flow, you aren't just "creating an Account over there somewhere", the object you are creating is the actual Account object, and the code that created that Account can act as the account owner in every way. A feature that was added to Flow before Cadence 1.0, but perhaps after you were working on Flow, is the ability to create Capabilities on Accounts themselves. So, the way I'd imagine the Factory use case working in Flow is as follows:
Cadence 1.0 has definitely improved this with the introduction of Capability Controllers, which make it easier to manage additional Capability objects including revoking them. However, I wouldn't suggest that in this case. Instead, I'd have two main classes for the DAO, a main DAOManagement singleton Resource, with all of the important logic in there, and then I'd have a array Custodian Resource objects, each which had a copy of a single Capability referencing the DAOManagement singleton. You'd ask the DAOManagement object to create new instances of Custodian, which would get a new copy of the Capability. The Custodian object would just have a bunch of wrapper functions (annoying to create, but relatively easily to generate automatically) that would call through the Capability to the main singleton that would contain the code. If the Custodian object would first check to see if it had revoked for each call, you could even allow the Custodian objects to be moved into the user's accounts. They could even move the Custodian between accounts if needed for organizational or security reasons.
Well, the goal of Cadence is to make it easier to manage more complexity, not harder. Obviously, as someone with a lot of input into Cadence's design, I find it easiest to think of examples where Cadence provides improvements! If you think of more examples of scenarios where the Resource oriented design feels limiting, please let us know. Perhaps the language needs to change, or perhaps we can offer suggestions like the above for how Cadence can make it work. I'm sorry to hear that you weren't able to keep working in the Flow ecosystem; it sucks that you put a lot of work into a proposal at the same time as we were reworking our grants program. I hope you'll get a chance to join us again! |
Objective
The objective of this FLIP is to introduce the "Authorized Call" feature, which allows functions to be marked as private unless they are called with a specific prefix.
This feature aims to enhance access control in Contracts, providing developers with more flexibility and fine-grained control over function visibility based on caller Contracts.
Motivation
Flow introduced Cadence, a Resource-Oriented Programming Language which works towards the Capability system, it replaced
msg.sender
and proved to be effective for small projects.However, as projects grow in size and complexity, the efficiency of the Capability system decreases compared to the use of
msg.sender
.Besides, The existing access control mechanisms is relatively simple, they have limitations when it comes to defining private functions that can only be accessed under specific circumstances. This can make it challenging for developers to enforce strict access control rules in complex projects.