Skip to content
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

Protocol Initalization Handler Facet documentation #538

Merged
merged 12 commits into from
Jan 25, 2023
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docs/local-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ To perform the upgrade you then
- Update `version` in `package.json`. If the version in `package.json` matches the existing version in addresses file, you will have to explicitly confirm that you want to proceed.
- Run `npm run upgrade-facets:local`. This will deploy new facets and make all necessary diamond cuts. It also updates the existing addresses file `addresses/<chain-id>-<environment>.json` (for example `addresses/31337-localhost.json` if you are using a default local hardhat node) and outputs the upgrade log to the console.

Protocol initialization facet is explained in more detail in separate page: [Protocol initialization handler facet](protocol-initialization-facet.md).
mischat marked this conversation as resolved.
Show resolved Hide resolved

### Upgrade clients
To test the upgrade functionality, you first need to setup upgrader account as described in section [Manage roles](local-development.md#optional-manage-roles)
mischat marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
57 changes: 57 additions & 0 deletions docs/protocol-initialization-facet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[![banner](images/banner.png)](https://bosonprotocol.io)

<h1 align="center">Boson Protocol V2</h1>

### [Intro](../README.md) | [Audits](audits.md) | [Setup](setup.md) | [Tasks](tasks.md) | [Architecture](architecture.md) | [Domain Model](domain.md) | [State Machines](state-machines.md) | [Sequences](sequences.md)

## Protocol initialization handler facet

Protocol initialization handler facet has a special role in the whole [architecture](architecture.md). On one side we have Diamond specific facets - Loupe and Cut - which enable lookups and facet management. On the other hand we have Protocol specific facets which implements all features needed for protocol to work. Most of these facets needs to be initialized at the time when cuts are done, which among other includes registering its interface in the diamond. However in some cases initialization of a facet if different depending on whether whole protocol is deployed for the first time or it is just upgraded. Moreover, some upgrades might introduce a logic that relies on data that was not produced in old versions of the protocol. For that purpose we introduce Protocol initialization handler facet, which conceptually belongs between Diamond specific and Protocol specific facets. Its role is to enable smooth atomic upgrades and if necessary populate some of contract storage.
zajck marked this conversation as resolved.
Show resolved Hide resolved

Protocol initialization handler facets responsibilities are:
mischat marked this conversation as resolved.
Show resolved Hide resolved
- store version of the protocol,
mischat marked this conversation as resolved.
Show resolved Hide resolved
- forward initialization calls to individual facets,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... to the appropriate facets.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

- if called during an upgrade, properly handle initialization data,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

properly handle the initialization of data when called during an upgrade.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

- remove supported interfaces,
- add supported interfaces.

Two biggest benefits of the Protocol initialization handler are:
- It allows atomic cuts of multiple facets, so there is generally no need to pause the protocol during the upgrade.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It allows for atomic cuts of multiple facets, this can at times alleviate the need to pause the protocol to perform an upgrade.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

- It allows custom storage manipulation, so if any back filling is needed, we have a way to do it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It allows for custom storage manipulation, enabling the upgrades to backfill data as needed.

backfilling is one word.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.


### Versioning

Initialize accepts version encoded in bytes32. Every time upgrade takes place, an unique version must be supplied, otherwise initialization reverts. Depending on version, some additional checks can be done, for example upgrade to certain versions can only be done if current protocol version is exactly one version lower. This kind of restriction is planned to be used on every upgrade. This means that skipping versions during the upgrade will not be possible. If the latest version of protocol code is more than one version higher that current deployed protocol, all intermediate upgrades need to be done to upgrade to the lates version.
zajck marked this conversation as resolved.
Show resolved Hide resolved

Facets allows to query the current version by calling `getVersion`.

### Facet initialization

Each Protocol facet should have initialization function (even if no-op) to ensure consistency across codebase and different version. Initialization function should be written as if protocol is deployed for the first time (i.e. not taking into account potential effects on the upgrade).
anajuliabit marked this conversation as resolved.
Show resolved Hide resolved

When protocol is deployed for the first time, `initialize` on Protocol initialization handler should get list of all facet implementation addresses together with corresponding initialization data. This data is passed directly on individual facets where whole initialization takes place.
mischat marked this conversation as resolved.
Show resolved Hide resolved

However, before upgrade is done, effects of facet initializers should carefully be considered before passing data to initialization handler. If facet's initialization function does not affect the protocol state in a harmful way, it should be passed to initialization handler in the same way as for the initial deployment. However, when initialize affects the storage (for example Config handler sets all counters to 1), facet should be omitted from initialization call and approach from next section should be followed.
zajck marked this conversation as resolved.
Show resolved Hide resolved

### Data initialization

When facet initializers are clashing with existing data or simply a specific storage must be populated, initializer facet must be updated to cater for these kind of change. Suppose new version is X.Y.Z and there is a need to modify the storage during the update, a new internal function should be prepared, called `initVX_Y_Z`. This function can make additional version checks and can accept arbitrary data which can be handled in any desired way. This allows to populate custom storage slot during the upgrade or mimic actions of the facet initializers that would otherwise be harmful. For example if another limit is added to the Config handler, `initVX_Y_Z` could simply store new value to desired location, without the need to overwrite other config values and at the same time leaves counters intact.
zajck marked this conversation as resolved.
Show resolved Hide resolved
Initialization data is passed in as bytes, so `initVX_Y_Z` must be decoded into correct types if needed.
mischat marked this conversation as resolved.
Show resolved Hide resolved

### Managing supported interfaces

Although most facets initializers automatically register their EIP165 interfaces, old interfaces are not automatically removed during upgrade/removal. Protocol initialization handler therefore allows upgrader to supply list of interfaces to remove or add, which happens atomically during the upgrade.


### Initialization diagram
Diagram below represents a simple upgrade with two upgraded facets:
mischat marked this conversation as resolved.
Show resolved Hide resolved
- Facet 1 has an initializer that writes to two slots, one of which is already populated.
- Facet 2 has an initializer that writes to an empty slot.

During the upgrade, the following happens:
- diamondCut is invoked externally. After it performs cut actions, it calls initialize on Protocol Initialization Facet.
- Since Facet 2 has upgrade-safe initializer, it is invoked directly on Facet itself.
- On the other hand, calling `initialize` on Facet 1 would affect already populated storage slot #102 and another empty slot #104. To avoid undesired effects, `initialize` cannot be called directly. Instead, `initVX_Y_Z` updates slot #104 and leaves #102 untouched.
- Additionally `initVX_Y_Z` also touches slot #106, not because some initializer would otherwise do it, but for example because some updated method from Facet 1 needs to read from that slot.

![Protocol Initialization Handler](images/Boson_Protocol_V2_-_Protocol_Initialization_Hander.png)