I am back with a new design proposal for the next stage of the service nervous systems (SNSs). Let’s use this thread to discuss how SNSs should be deployed and upgraded. This is our proposal:
Similarly to how the Network Nervous System (NNS) is the open tokenized governance system that controls the Internet Computer blockchain (IC), service nervous systems (SNSs) are algorithmic DAOs that will allow developers to create decentralized, token-based governance systems for their dapps.
Decentralized control and tokenization enables the introduction of new incentive systems and use cases that have the potential to set dapps apart from traditional applications. We refer to this article for more background on how SNSs will empower dapps to leverage the full potential of the IC.
The goal of this discussion is to introduce a concrete first design for how SNSs can be deployed and upgraded.
We presented the first proposed SNS design in October 2021. The community’s feedback was that they wish for a less complex SNS design that also leaves more freedom for developers and SNS communities to configure a DAO to their needs. Moreover, some developers mentioned that they have a particular DAO or use case in mind and are only interested in a ledger or governance canister implementation, which they plan to integrate with existing canisters / dapps.
The goal of SNSs is also to eventually provide an open governance solution “on the press of a button”, where even users that are not experienced developers can get an SNS as a system functionality that is automatically upgraded and maintained as part of the IC.
Motivated by this, we proposed to release smaller SNS features in stages, such that the different parts or canisters can be used by the community early. This new overall approach has been adopted in a motion proposal in December 2021.
So far, the following stages have already started:
- Improve the NNS ledger canister so that it can be used for any tokens, e.g., in SNSs. This is scheduled for the Titanium release on the roadmap.
- Implement a governance canister. The proposed design for the governance canister has been presented and discussed in this forum thread and been approved by the community in this motion proposal. In addition, this stage will also deliver a root canister that is needed for governance upgrades. This implementation has started and is ongoing.
The design presented here is the next proposed stage:
- Tooling and support for the deployment and upgrade of SNSs. At a high level, in this design, a SNS consists of a ledger canister, a governance canisters, and a root canister that are mostly from the previous two stages but may require small changes. In addition, this stage entails changes to the NNS canisters and a new canister that helps with deploying SNSs.
Other SNS features that we envision going forward are frontend support, support for initial token distribution, integration with the community fund, etc.
We propose that in this initial design an SNS consists of three canisters:
- the governance canister which enables decentralized decision making,
- the ledger canister which determines for a SNS-specific governance token the balances and transactions, and
- the root canister which is responsible for upgrading the other SNS canisters and the dapp that the SNS controls.
One of the key features of the IC is that it can continuously be upgraded by proposals through the NNS. The same is true for the NNS canisters themselves, which have been upgraded many times since genesis. Similarly, we propose to start with one version of each of the SNS canisters, which can then be continuously evolved.
As with the NNS, the code of all SNS canisters will be public. That is, anyone can deploy any version of the canisters at any point in time. However, it may be that not all canister versions can be upgraded to all other canister versions without breaking some functionality, e.g., due to incompatibility during state migration. For example, it is possible that the governance canister can be upgraded from version v1 to version v2 and from version v2 to version v3, but that it cannot be upgraded from version v1 to version v3 directly. Moreover, it is possible that newer versions of one canister may not be compatible with some older versions of a different canister, e.g., a new ledger version is not compatible with an old version of the governance canister.
Therefore, we propose to have blessed SNS deployments in the NNS registry. These new entries in the NNS registry then define
- which versions of the SNS canisters are compatible and
- from which deployment one can safely upgrade to which next deployment.
The IC community would thoroughly test these facts for some releases and “bless” this information in the registry by proposal. SNSs can then just follow the suggested path of upgrades and know that all the relevant upgrades along the way have been well-tested.
With the suggested design, there are at least two possibilities for how to deploy and continuously upgrade a SNS:
- A SNS that is a system functionality, which is automatically maintained by the IC and where the SNS canisters are hosted on a new SNS subnet. To deploy an SNS, a user sends a command to the IC that defines the initial settings of the SNS. Afterwards, the IC will ensure that the SNS is kept on the latest available version. This has the advantage that the SNS community does not need to take any actions to keep the SNS canisters up to date (e.g., when bugs are fixed) nor do they need to understand the details of the canisters’ implementation. Especially, the SNS canisters are automatically upgraded following the blessed deployment path. To achieve better security guarantees through higher replications, the new SNS subnet will have more nodes than application subnets currently do.
- A SNS that is self-deployed, manually upgraded, and hosted on an application subnet. Any SNS community can choose to deploy the SNS code, which is open source, on an application subnet. They can then choose to follow the blessed upgrade path or deviate from this path, e.g., leaving out some versions, or even modify the canisters’ code in a completely different way. In this option, canister upgrades require active actions of the SNS community (i.e., the submission of a proposal) and the SNS community has to ensure that the upgrades are secure. This includes ensuring that alternative canister versions are compatible and that upgrades to newer versions do not break any functionality. Application subnets currently have less nodes than the SNS subnet and are therefore less secure.
These two possibilities allow SNS communities to choose between using SNSs that are provided as a service by the IC, where maintenance is as automated as possible, and SNSs that have full flexibility of how they can be evolved. Because of the fact that the possibilities for Option 2 are unbounded and that it is likely that this option will mainly be used by those who want to explore new designs themselves, we focus on Option 1 in the remainder of this design proposal.
The following canisters, on three different subnets, are involved in the proposed design:
- On the NNS subnet, the registry canister holds the blessed deployment path, as described above, which includes the hash of the SNS canisters’ wasm modules.
- On a new SNS subnet, a new SNS wasm module canister holds the actual SNS canisters’ wasm modules.
- On an application subnet, there is a cycles wallet controlled by a developer that wants to initialize a SNS.
The following protocol describes the steps to initialize a SNS:
- Using the cycles wallet, the developer calls the SNS wasm module canister to deploy an SNS. They specify the initial parameters that the SNS should have (e.g., initial accounts on the ledger and initial neurons, token name etc). Also, along with the call, they send an initial cycle amount to pay for the SNS.
- Upon receiving this call, the SNS Wasm module canister checks if the chosen initial parameters are well-formed (e.g., there are ledger accounts for all neurons etc) and if there is still space for more SNSs on the subnet.
- If all these checks are successful, the SNS wasm module canister initiates the deployment of the three SNS canisters governance, ledger, and root.
The following describes how the IC automatically maintains SNSs as part of the system:
The NNS community can at any time bless new SNS deployments.
a) To do so, anyone can make a proposal in the NNS which, upon adoption, adds a new blessed SNS deployment to the registry. As mentioned above, this registry entry refers to the SNS canisters by specifying the hash of their wasm modules.
b) Anyone can then upload the actual canister wasm modules to the SNS wasm module canister on the SNS subnet. The SNS wasm module canister will only accept wasm modules for which the hash is mentioned in a blessed deployment on the registry.
The SNSs on the SNS subnet regularly query the registry to learn if there are new blessed deployments. If this is the case, they pull the respective wasm modules from the SNS wasm module canister and initialize an upgrade to this new version.
We propose to integrate the necessary calls that a user is expected to make to initialize an SNS into dfx. As many developers are already familiar with the tool, we think this is a good solution for the first version.
While we envision a frontend that makes this functionality available to an even wider range of users, we propose to solve this in a separate design proposal.
We propose that the SNS wasm module canister is controlled by the NNS root canister, similarly to the canisters on the NNS.
Within each SNS, we propose that the root canister controls the governance and ledger canister and that the governance canister controls the root canister. This means that whenever an update is triggered, the respective controlling canisters are responsible for upgrading the controlled canisters.
The main motivation for SNSs is of course that they can control dapps in a decentralized manner. We deliberately did not include the dapp in the above design to allow for different use cases. At any point after the SNS exists, the dapp’s control can be changed to the SNS.
In particular, this allows for the following use cases:
- Developers who control an existing dapp can initialize an SNS and when it exists, they can add the SNS as the dapp’s controller and remove themselves from the set of controllers.
- Developers may choose to add a SNS as the dapp’s controller but, in the beginning, also remain controllers themselves until they gain sufficient confidence that the SNS works, at which point they can remove themselves as controllers.
- Developers can set up an SNS without an existing dapp. They can then, for example, use the SNS to get initial funding, vote on what the dapp should look like etc, and then at a later point in time create the dapp and assign the control to the SNS.
As stated above, we propose that the SNS canisters are deployed on a new subnet. We next present more details regarding the design of this subnet.
Currently, there are system subnets (e.g., the NNS) and application subnets. We propose to introduce a third subnet type for the SNSs.
The reason for this is that while we propose similar configurations for the SNS subnet as for the system subnets, the canisters on the SNS subnet should pay cycles (which the NNS canister do not).
As SNSs are security critical applications and as there are dependencies between the SNS subnet and the NNS (the NNS controls the SNS wasm module canister), we propose that the new subnet should have 34 nodes.
While we are still working on a concrete proposal, the high level idea is that it should be more expensive to have canisters running on the SNS subnet than on an application subnet.
The main reason for this is that the subnet has a larger number of nodes than the application subnets.
We propose to start with one SNS subnet that can host around 10-15 SNSs according to initial estimations. If there is more demand, a new SNS subnet can be created the same way as other new subnets can be added to the IC, by proposals over the NNS. On this new subnet, the NNS can then deploy a new SNS wasm canister, and the same protocols as described above can be done. Following the same process, more and more SNS subnets can be created.
We consider this to be a security critical feature, as the upgrades of dapps and the value of associated governance tokens are at risk if there are vulnerabilities. We thus already initiated a design review by DFINITY’s security team and plan to also have thorough security code reviews.
Some different approaches that we could have taken and why we decided against them.
- Why not hold off on releasing until we have all SNS features, including initial token distribution etc., implemented?
As argued above, we decided against this as it seemed to be a wish from the community to be able to use and experiment with the individual components as soon as possible.
- Why not omit the root canister and just have two canisters?
The reason for this is that the governance canister cannot upgrade itself. Upgrading a canister involves stopping the canister, installing the new code, and starting it again. This cannot be triggered by a canister itself. Moreover, we don’t believe it is a good idea to make the ledger canister more complex by adding this functionality to the ledger canister. Therefore, similarly to the NNS, we propose to have a root canister.
- Why is the root canister not only controlling the governance canister and the governance canister controls all other canisters?
There seems to be no strong reasons for not choosing this alternative. As both options seemed equally good, we preferred the above proposed control hierarchy as this is closest to what we have in the NNS and thus closer to what we have already tested and used extensively.
- Why not place the SNS wasm module canister on the NNS?
The reason for this is that currently the crossnet message limit is smaller than the size of the canister wasms that we need to communicate from the SNS wasm module canister to the SNS canisters when they are upgraded. While we are planning a feature to compress canisters, we are not sure when this feature will be finished and therefore propose to go with this solution for now.
- Why not have the SNS wasm module canister control all SNS canisters and notify them or start upgrades when new canister upgrades are available (i.e., implement a “push” rather than a “pull” mechanism for upgrades)?
For any canister that controls another canister that can either be on a malicious subnet or have bugs, there is the risk that the controlling canister cannot be stopped and thus not be upgraded. This is the case both for a canister that directly controls a buggy canister and for a canister that controls such a canister via a longer chain of control (i.e., A controls B, B controls C, and C is buggy). As we absolutely want to avoid that we cannot upgrade the NNS canisters anymore, we propose to avoid any control chain from the NNS to the SNS canisters as the latter necessarily need to call out to dapp canisters on less secure application subnets. Again, we are working on a more general solution for this problem, but suggest a design that is not dependent on this solution for efficiency reasons.
This feature involves many different layers of the IC stack. It requires changes to existing canisters, the implementation of new canisters, the realisation of a new subnet type, and new communications between canisters on different subnets.
To avoid incompatibilities between the different components and to mitigate the risks specific to different components, we included experts from many different teams in the design phase.
Furthermore, we mitigate the risk of unforeseen findings by involving the testing and security experts early in the process.
We propose the following approach to discuss the design of this feature:
- Feb 10th-15th: Design discussion on this forum thread
- Feb 15th: Community conversation about the topic
- Afterwards: start implementation of the design, potentially adjusted with feedback from Steps 1 & 2
There has already been a motion proposal on the general idea of SNSs that has been adopted on Dec 21, 2021. We consider this design as a concrete, detailed suggestion on how to realize parts of this larger design / idea. Therefore, we propose not to submit a separate motion proposal for this design and rather discuss it in the forum here and in the community conversation. Apart from feedback on the design, we are also happy to get feedback on and discuss this approach.