Skip to content
This repository has been archived by the owner on Aug 13, 2024. It is now read-only.

Commit

Permalink
Add contents and details throughout
Browse files Browse the repository at this point in the history
  • Loading branch information
Lewis committed Oct 4, 2023
1 parent 88393ef commit 1c4b25c
Showing 1 changed file with 14 additions and 12 deletions.
26 changes: 14 additions & 12 deletions KIPs/kip-149.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The smart contract will have the following features:

#### 1. Registry

The registry should have data for the pre-deployed system contracts as soon as it is deployed. It will be done by state injection, which injects data into the Registry directly using the `state.SetState`. The implementation for this is discussed in more detail [here](#backward-compatibility).
The registry should have data for the pre-deployed system contracts as soon as it is deployed. It will be done by state injection, which injects data into the Registry directly using the `state.SetState`. A reference implementation is introduce in [Implementation](#implementation).

#### Interface of Registry

Expand Down Expand Up @@ -110,7 +110,7 @@ interface Registry {
function register(string memory name, address addr, uint256 activation)
```

Registers a new system contract. It will be activated at `activation`. It overwrites the predecessor if a predecessor system contract exists and is not yet active. Passing `addr == address(0)` means deprecation for the name since `getActiveAddr` function will return a zero address after its activation.
Registers a new system contract. It will be activated at `activation`. It overwrites the predecessor if a predecessor system contract exists and is not yet active. Passing `addr == address(0)` is an implicit deprecation for the `name`, meaning the `name` will no longer be used.

The function validates the following requirements:

Expand All @@ -126,7 +126,7 @@ The function emits a `Registered` event.
function getActiveAddr(string memory name) view returns (address)
```

Returns the address of the active system contract with the `name`. It returns a zero address if no active contract with a name exists.
Returns the address of the active system contract with the `name`. It returns a zero address if there’s no registered system contract with the `name` or the `name` has been deprecated by registering a zero address.

#### 2. Proxy

Expand All @@ -152,7 +152,7 @@ When upgrading system contracts, its logic contract will be changed by governanc

#### Replace System Contracts

If current system contract updates can’t be done by upgrading the logic contract, it must be replaced with the newly deployed system contract. The predecessor doesn’t need to be explicitly deprecated since a new system contract will implicitly replace and deprecate it.
If current system contract updates can’t be done by upgrading the logic contract, it must be replaced with the newly deployed system contract. The predecessor doesn’t need to be explicitly deprecated since a new system contract will implicitly replace and deprecate it. The replacement process is the same as the initial registration for the system contract except for having a predecessor.

![](../assets/kip-149/ReplacementProcess.png)

Expand All @@ -168,13 +168,12 @@ In the Chain Config, the following field is introduced. All node operators in a

#### Execution

The Registry deployment is executed at the `Finalize` function, which means the end of the block processing process. It reads the reserved address and runtime bytecode and deploys the Registry by the bytecode injection. Also, it injects the state for pre-deployed system contracts here.

The Registry deployment is executed at the `Finalize` function, which means the end of the block generation. It reads the reserved address and runtime bytecode and deploys the Registry by the bytecode injection. Also, it injects the state for pre-deployed system contracts here.

```go
// Deploy the registry contract if the block is the kip-149 fork block
if chain.Config().IsKIP149ForkBlock(header.Number) {
// Set the registry contract code to the stateDB
// Inject the bytecode for the Registry contract and the state for pre-deployed system contracts
err := registry.InstallRegistry(state)
if err != nil {
logger.Error("failed to set the registry contract code", "err", err)
Expand All @@ -196,13 +195,15 @@ In the future, all system contracts will be registered in the Registry, and a Kl

### State Injection for Pre-deployed System Contracts

The Registry should hold data for pre-deployed system contracts as soon as it is deployed. However, pre-deployed system contracts have been deployed and managed differently by networks. (e.g., the Voting contract on the Klaytn cypress network is currently not used on the Klaytn baobab network.) To handle this, there are two main approaches:
The Registry should hold data for pre-deployed system contracts as soon as it is deployed. However, pre-deployed system contracts have been deployed and managed differently by networks. (e.g., the Voting contract on the Klaytn cypress network is currently not used on the Klaytn baobab network.) To handle this, there are three main approaches:

1. Send multiple register transactions after deploying the Registry.

1. Use a fallback logic in the getter to return the state of pre-deployed system contracts.
2. Use a fallback logic in the getter to return the state of pre-deployed system contracts.

2. Use state injection, which injects state for pre-deployed system contracts by the `state.SetState`.
3. Use state injection, which injects state for pre-deployed system contracts by the `state.SetState`.

In the first approach, the Registry contract should have different codes by the network, requiring direct code modification in the getter(e.g., add/remove hard-coded system contracts and modify if-else statements). It can cause potential security vulnerabilities and increase costs for getter calls permanently. On the other hand, the second approach is much safer because it's more structured and doesnt require modifying any code. It can also set the necessary configuration without working with the additional contract's constructor.
The first approach seems straightforward. However, the Registry will be set in the `engine.Finalize`, which is the last part of the block generation. It means the transaction cannot be processed in the same block and must be entered in the first order of the next block. This requires additional implementation and can't be applied when `KIP149CompatibleBlock == 0`. In the second approach, the Registry contract should have different codes by the network, requiring direct code modification in the getter(e.g., add/remove hard-coded system contracts and modify if-else statements). It can cause potential security vulnerabilities and increase costs for getter calls permanently. On the other hand, the last approach is much safer because it's more structured and doesn't require modifying any code. It can also set the necessary configuration without working with the additional contract's constructor.

### Separate Data and Logic Contract

Expand All @@ -216,7 +217,8 @@ It needs to calculate storage slots for variables in the Registry contract for s

## Implementation

A reference implementation and its test code for KIP-149: [Implementation](https://github.com/klaytn/system-contracts/tree/registry)
- A reference implementation for the Registry contract: [Implementation](https://github.com/klaytn/system-contracts/tree/registry)
- A reference implementation for core logic: [Implementation](https://github.com/klaytn/klaytn/pull/1968)

## References

Expand Down

0 comments on commit 1c4b25c

Please sign in to comment.