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

Commit

Permalink
Reflect updated spec
Browse files Browse the repository at this point in the history
  • Loading branch information
hyeonLewis committed Dec 6, 2023
1 parent a3cb885 commit bf3daef
Showing 1 changed file with 9 additions and 10 deletions.
19 changes: 9 additions & 10 deletions KIPs/kip-149.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The smart contract will have the following features:

#### 1. Registry

The registry should have data for system contracts as soon as it is deployed. Note that it only records system contracts developed based on KIP-149. It will be done by state injection, which injects data into the Registry directly using the `state.SetState`. A reference implementation is introduced in [Implementation](#implementation).
The registry must have data for system contracts at a specific block. It will be done by state injection, which injects data into the Registry directly using the `state.SetState`. A reference implementation is introduced in [Implementation](#implementation). Note that it only records system contracts developed based on KIP-149.

#### Interface of Registry

Expand Down Expand Up @@ -176,7 +176,7 @@ In the Chain Config, the following field is introduced. All node operators in a

- `RegistryAddress`: the reserved address for the Registry contract, which is `0x0000000000000000000000000000000000000401`.

- `Kip149CompatibleBlock`: the target block number that the Registry starts to be used.
- `Kip149CompatibleBlock`: the target block number that the Registry will be deployed.

- `RegistryConfig`: the initial data config for the Registry. It is used when injecting the initial state after deploying the Registry.

Expand Down Expand Up @@ -205,11 +205,10 @@ var ChainConfig = &ChainConfig{

#### Execution

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 initial state provided by `RegistryConfig` for the Registry here. Note that the Registry contract will be deployed at th parent block of the `Kip149CompatibleBlock` since it needs to be ready at the `Kip149CompatibleBlock`. When `kip149CompatibleBlock == 0`, the Registry will be allocated at the genesis block.
The Registry deployment is executed at the `engine.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 initial state provided by `RegistryConfig` for the Registry here. When `kip149CompatibleBlock == 0`, the Registry will be allocated at the genesis block.

```go
// Note that it is deployed at the parent block of the kip-149 fork block
if chain.Config().IsKIP149ForkBlockParent(header.Number) {
if chain.Config().IsKIP149ForkBlock(header.Number) {
// Inject the bytecode and states for the Registry
err := registry.InstallRegistry(state, chain.Config().RegistryInit)
if err != nil {
Expand All @@ -222,10 +221,10 @@ if chain.Config().IsKIP149ForkBlockParent(header.Number) {

#### Resolver

A Klaytn node will have a resolver to read the active addresses of system contracts from the Registry.
A Klaytn node will have a resolver to read the active addresses of system contracts from the Registry. But the system contracts deployed by state injection (e.g., `KIP113`) will be directly read from `chain.Config().RegistryInit` at the `Kip149CompatibleBlock` since the Registry will be deployed in the `engine.Finalize` function, which is the last part of the block generation. In other words, the resolver will be used starting in the `Kip149CompatibleBlock + 1`.

```go
// Note that it will be executed after the kip-149 fork block
// Note that it will be used starting in the next of kip-149 fork block
func ReadRegistryActiveAddr(backend bind.ContractCaller, name string, num *big.Int) (common.Address, error) {
code, err := backend.CodeAt(context.Background(), RegistryAddr, num)
if err != nil {
Expand Down Expand Up @@ -257,15 +256,15 @@ The Registry holds all system contracts for Klaytn, affecting the protocol direc

### State Injection for System Contracts

The Registry should hold data for system contracts as soon as it is deployed. To handle this, there are three main approaches:
The Registry must hold data for system contracts at a specific block. To handle this, there are three main approaches:

1. Send multiple register transactions after deploying the Registry.

2. Use a fallback logic in the getter to return the state of system contracts.

3. Use state injection, which injects state for system contracts by the `state.SetState`.

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.
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. Note that the state injection for system contracts will follow the [solidity layout rule](https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html).

### Separate Data and Logic Contract

Expand All @@ -275,7 +274,7 @@ This proxy pattern simplifies the process of system contract update because the

### Deployed System Contracts

It needs to calculate storage slots for variables in the Registry contract for state injection. It will follow the [solidity layout rule](https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html).
The existing system contracts will not be registered in the Registry, since they are not developed based on KIP-149. They will be used in a Klaytn node same way as before.

## Implementation

Expand Down

0 comments on commit bf3daef

Please sign in to comment.