我们做到了第二周而没有忘记博客!接招吧,讨厌的人!🙌
你好!我叫Josh。我叫Josh,是Dapper Labs的Flow团队的一名智能合约工程师。
如果你是新来的,欢迎!这是一篇关于Cadence的每周博客,Cadence是Flow用于智能合约的新的最先进的语言。我建议在阅读本篇之前,先从我的第一篇关于初学者材料的文章开始,因为我将假设读者已经对Cadence有了基本了解,或者只是非常喜欢我的写作风格。(我受宠若惊!)
什么是访问控制?
访问控制是指将字段、函数和类型限制在某些范围内和用户。对于开发者来说,这是一个极其重要的问题,以确保他们的代码免受潜在漏洞的影响。区块链技术当然有其公平份额的错误和漏洞,其中许多是可以通过更好地管理访问控制来防止的。
我相信每个开发者在考虑将他们的项目部署到主网上之前,都应该对Cadence的访问控制有一个全面的了解。我知道标准很高,但我们在这里处理的是具有实际价值的东西(而且你们中的大多数人可能不会听我的,只是不假思索地复制Top Shot的代码)。
与大多数语言不同,Cadence提供了两个不同的访问控制层,它们都是内置于语言中的。
我建议在阅读这篇文章的更多内容之前,先看看这些内容。
在这篇文章中,我不打算对不同种类的访问控制进行详细的解释,但我要谈一谈利用这些的一些理由,以及一些如何在智能合约中有效使用它们的例子。
Cadence中的两种访问控制
关键字访问控制
Cadence中的第一种访问控制是你们大多数人可能都熟悉的那种。使用关键字来指定一个特定字段的访问级别。
Cadence提供四个不同的关键字来指定访问级别。每个字段、功能和类型都需要指定一个访问级别。
pub或access(all)意味着该声明在所有作用域中都是可访问/可见的。它们各自做同样的事情,但pub更短,所以推荐使用。
例如,一个类型中的公共字段可以使用访问语法(`object.field`)在外层作用域中的类型实例上被访问。但这并不允许声明是公开可写的。
因此,如果我有这个合同部署在我的账户上。
In a transaction or script, anyone who imports the contract from my account could read the greeting field, greetingsByLanguage dictionary, or call the returnGreeting function, but they can’t overwrite the whole value in those fields, with one exception.
If there is a public dictionary or array field, then even though it can’t be overwritten by anyone like this,
an element of it can still be modified by anyone like this.
Because of things like this, we strongly recommend to make all fields in contracts and composite types private, access(self), by default. You can then define setters and getters for your fields. Lets see what that looks like in the previous contract.
This uses access(self), which means the declaration is only accessible/visible in the current and inner scopes. For example, an access(self) field can only be accessed by functions of the type is part of, not by code in an outer scope. This allows the developer to be able to explicitly define how their fields are accessed by getters and setters.
The other two access keywords are somewhat unique to Cadence.
access(contract) means the declaration is only accessible/visible in the scope of the contract that defined it. This means that other types and functions that are defined in the same contract can access it, but not other contracts in the same account.
You could have something like this:
In this situation, if you had an instance of the Hello struct, you would not be able to directly get the greeting field by using Hello.greeting, but since the returnGreeting function is defined in the same contract, you can give it your Hello struct and get the greeting field that way:
This is just a simple example, but I’m sure you can imagine more sophisticated utilization of this ability.
access(account) means the declaration is only accessible/visible in the scope of the entire account where it is defined. Flow accounts can have any number of Cadence contracts deployed to them, so this keyword means that any other contracts in the same account are able to access it.
With this field, you could declare fields in contracts as access(account) , knowing that you want them to be “private” for the time being, but keeping open the possibility that you could deploy a new contract later that can interact with the first contract in new ways. You also might want to keep your contracts simpler by only grouping similar functionality within a contract, but having related contracts still in the same account that can share some information with each other.
This keyword is the one that I have the least experience using, but recently I have been thinking about more ways to use it. If you have any examples where you have used it, please leave a comment and let me know!
Capability-based Access Control
The other main form of access control in Cadence utilizes Capability-based security, a security model that is not used very often. Most security models (and most other smart contract programming languages) restrict access based on who you are, but capability security is more about what you own.
Lets look at an analogy:
Image that you are designing a physical device for a government to use to manage access to important internal functionality, like printing money, declaring war, paying taxes, etc. Everyone in the country needs to have access to some subset of that functionality, but each person’s access specification is different than many of the other people. For example, everyone needs access to the “pay taxes” functionality, but only elected government officials need to have access to “declare war”, and so on and so forth.
If we were designing this system in the way that most smart contracts manage access, with a list that indicates who has access to what, then this physical device would resemble a giant control board in a public place with thousands of different buttons on it for each and every functionality that the government has some control over. Anyone on Earth would be able to walk up to this board and press any of the buttons, but the button would perform some sort of biometric scan (like an iris scan or fingerprint) to verify that this person has the authority to perform the action. If they pass the scan, then the functionality would happen. There is even a public button for changing the access rules!
This is a contrived example, but I am sure you can see the problems with this. If any one of the buttons wasn’t designed properly or is malfunctioning, then anyone on Earth would be able to exploit the broken button to do things they aren’t supposed to!
A more effective solution to this problem would be to give each citizen a device that only contains the buttons for functionality they are permitted to access. Then each citizen stores that device in a secure place in their home or safe that only they can access. Now, if there is a vulnerability in one of the buttons, an attacker has the difficult task of breaking into each participants house and safe individually, which is much harder and time-consuming.
This is what capabilities accomplish in Cadence. Instead of building a special access control list with opaque and complex rules, access control is built into the fundamentals of the Cadence type-system. Users get special resource objects that they store in their account that define which functionality they are allowed to access.
Using the example above, we’d create a HelloAdmin resource that allows the owner of it to update the greeting field:
Attackers wouldn’t even have the opportunity to exploit many potential bugs because the code isn’t even accessible to them to even try to exploit in the first place!
Capabilities are a complex subject, and I am planning on doing a blog post in the future that is completely dedicated to them. For now, I would recommend checking out this blog post about generic capabilities and the Cadence Capability documentation.
Conclusion
Hopefully I’ve made some of the access control features of Cadence a little more clear for you.
Please share any interesting uses of Cadence’s access control features that you have done or seen others implement!
If you have any questions, the entire Flow team and community is here to support you! Please do not hesitate to reach out via our Discord server, the Flow Forum, or via an issue in the Flow Github repo.
Are there any other topics or interesting projects that you know would useful to newcomers or that you would like me to write a blog post about? Feel free to comment with your ideas and I might include them in a future post!
Flow Discord: https://discord.gg/flow
Flow Forum: https://forum.onflow.org
Flow Github: https://github.com/onflow/flow
See you next week! 👋