jason hwang
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee
  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 플라즈마 EVM 2.0 : 탈중앙화된 상태를 강제하는 튜링 완전한 사이드 체인 Carl Park(박주형) (Onther Inc.) Aiden Park(박정원) (Onther Inc.) Kevin Jeong(정순형) (Onther Inc.) Translated by Jason Hwang(황재승) (Onther Inc.) :::info [English Version Link](https://hackmd.io/s/HyZ2ms8EX) ::: ### Abstract 이더리움의 EVM(Ethereum Virtual Machine)은 블록체인에서 튜링 완전한 연산을 지원함으로써 스마트 컨트랙트(smart contract)라는 이름으로 잘 알려진 일반 프로그램(general program)을 동작가능하게 하였다. 플라즈마 EVM은 플라즈마 기반의 사이드 체인에서 EVM을 실행할 수 있는 새로운 버전의 플라즈마이며, go-ethereum, py-evm, parity와 같은 현재 이더리움 클라이언트에 기반을 두고있다. 이 페이퍼에서는 자식체인의 검증된 상태만이 root chain에 제출되는 것을 보장하도록 두 체인 사이의 account storage에서 enter, exit하는 방법을 제공하여 상태가 강제되는(state-enforceable) 플라즈마 구조를 제안한다. 이는 두 체인이 완전히 동일한 구조를 갖기 때문에 가능하다. 이를 이용하여 기존 이더리움 체인에 구축된 탈중앙화어플리케이션을 그대로 플라즈마 체인으로 옮겨와 댑(Dapp)의 탈중앙성, 성능, 안정성, 사용성 모두를 개선시킬 수 있다. ### Glossary - NULL_ADDRESS: 0x00 or 0xFF...FF(2^160 - 1)이고 논스와 서명이 v = r = s = 0인 계정, NA로 표기한다. - Transactor: 트랜잭션을 생성하는 계정, tx.origin. - Root chain: 이더리움 블록체인 - Child chain: 플라즈마 블록체인 - RootChain contract: ETH나 ERC20의 enter/exit 작업을 관리하는 root chain에서의 플라즈마 컨트랙트, $R$로 표기한다. - Requestable contract: Root chain과 child chain 양쪽에서 exit/enter request를 처리할 수 있는 컨트랙트이다. 2개의 같은 컨트랙트가 root chain과 child chain에 모두 배포되어야 하고, $R$을 통해 두 컨트랙트의 주소가 매핑된다. - enterRequest: Root chain에서 보유하고 있는 자산을 child chain으로 예치하거나, account storage 변수를 child chain으로 이동시키는 것 처럼 root chain에서 child chain으로 무언가를 이동시키기 위해 필요한 request를 의미한다. - exitRequest: Child chain에 예치되었던 자산이나 account storage를 다시 root chain으로 이전시키기 위해 필요한 request를 의미한다. Root chain에 대한 exit request는 child chain의 account storage의 상태를 즉시 갱신해야 하며 child chain에서의 갱신이 거절되었다면(트랜잭션이 revert 된 경우), child chain을 갱신할 때 실행되었던 연산 결과를 증거로 삼아 `exitChallenge`를 할 수 있다. - requestBlock: Root chain에 의해 상태 변화(state transition)에 대한 적용이 강제되는 블록 - nonRequestBlock: Child chain에서 계정 간에 발생하는 일반적인 트랜잭션을 포함하는 블록 - requestChallenge: `requestBlock`이 정상적인 request를 포함하지 않거나 유효하지 않은 request를 포함하는 경우에 대한 챌린지 - nullAddressChallenge: `nonRequestBlock`이 NULL_ADDRESS가 전송한 트랜잭션을 포함하는 경우에 대한 챌린지 - computationChallenge: `requestBlock`이나 `nonRequestBlock`에서 상태 변화에 대한 연산이 올바르게 이루어지지 않는 경우에 대한 챌린지. - exitChallenge: Invalid한 `exitRequest`가 child chain에서 받아들여지지 않는 경우에 대한 챌린지 (request는 `requestBlock`에 포함되어야 한다). ### Child chain 플라즈마 EVM의 클라이언트는 기존 이더리움 클라이언트에 기반했기 때문에 대부분의 기본 메커니즘은 이더리움과 동일하다. Child chain의 블록, 트랜잭션 그리고 receipt등의 자료구조는 이더리움과 같다. 다만 플라즈마 프로토콜을 적용하기 위해 아래의 정책은 기존의 이더리움과는 다르다. 1. Child chain을 사용하기 원하는 root chain의 사용자 A의 자산(ETH/ERC20)이 RootChain 컨트랙트에 예치되면, A의 enter request는`enterRequest` 대기열에 쌓이고 operator(혹은 NULL_ADDRESS)에 의해 다음 child chain의 블록에 A의 자산을 *발행*하는 트랜잭션이 생성된다. Root chain에서 child chain으로 상태 전환은 이러한 방식으로 이루어진다. 2. 사용자 A가 child chain에서 exit하기를 원한다면, 해당 증거를 포함하여 request를 하면된다. 해당 request는 `exitRequests` 대기열에 쌓이고(queued on) operator(혹은 NULL_ADDRESS)는 반드시 A의 자산을 *소각*하는 트랜잭션을 다음 child chain의 블록에 생성해야 한다. 3. Root chain의 exit request가 챌린지 없이 완료되면, child chain에는 더 이상 어떤 변화도 발생하지 않는다. 그러나 *root chain*의 컨트랙트는 **반드시** root chain에 해당 변경 사항을 적용해야 한다. 4. 다음 블록에 request와 관련된 트랜잭션이 포함되지 않는다면, 이는 챌린지에 대한 근거가 될 수 있다. 그리고 챌린지가 받아들여지면 root chain은 child chain의 상태를 request 트랜잭션이 발생하기 이전 블록으로 revert 시킨다. Operator는 `requestBlock`과 `nonRequestBlock`, 두 가지 유형의 블록을 root chain에 제출해야 한다. RootChain 컨트랙트는 이 두 종류의 블록을 유기적으로 처리하기 위해 상황에 맞게 `WaitingNonRequestBlock`, `WaitingRequestBlock`, `AcceptingRequest`인 상태로 변한다. 위 세 가지 상태와 request들이 어떤 방식으로 처리되는지 알아보도록 하자. 1. Operator는 반드시 새 블록을 제출하기 전에 `prepareToSubmit` 함수를 호출해야 한다. 그러면 root chain 컨트랙트는 `WaitingNonRequestBlock`인 상태가 된다. 그 다음 operator는 `nonRequestBlock`과 `requestBlock`을 모두 제출한다. 새로운 request들은 `WaitingNonRequestBlock`인 상태가`AcceptingRequest` 로 바뀔 때까지 펜딩된다. 2. 먼저, `nonRequestBlock`은 반드시 enter/exit request와 관련 없는 모든 트랜잭션을 담아야 한다. Child chain에서 생성된 트랜잭션이 없다면, `transactionRoot`, `postTransactionalStatesRoot`는 `emptyTrie`를 가르킨다. NULL_ADDRESS로 부터 전송되는 트랜잭션이 포함되거나 (nullAddressChallenge), 상태 전환이 잘못된 방법으로 이루어 지거나(computationChallenge), byzantine 상황으로부터 child chain을 복구해야하는 경우 챌린지 될 수 있다. - Operator가 `nonRequestBlock`을 제출한 경우, root chain은 `WaitingRequestBlock` 상태가 된다. 3. 두 번째 유형의 블록인 `requestBlock`은 request와 관련된 트랜잭션들만 담아야 한다. 그러므로 `requestBlock`은 enter&exit request의 적용, NULL_ADDRESS, 컨트랙트 주소, state-enforcing 트랜잭션만을 포함해야 한다. - `requestBlock`이 request와 관련없는 트랜잭션을 포함하거나 포함되어야 할 request를 제외하면, 챌린지가 발생하게 되고 해당 블록은 챌린지 되기 전 상태로 revert 된다. 이러한 종류의 챌린지를 `requestChallenge`라고 한다. - operator가 `requestBlock`을 제출하면, root chain은 `AcceptingRequest` 상태가 된다. Root chain은 `requestBlock`을 통해 child chain의 상태 변화를 강제한다. Operator가 이러한 상태 변화를 제대로 적용하지 않아 이에 대한 챌린지를 받는다면 현재 블록에서 상태 변화가 발생하기 이전 블록으로 revert 된다.(*requestChallenge*) ![](https://i.imgur.com/IYZYV5v.png) *<center>request 및 챌린지 다이어그램</center>* #### Epoch Epoch는 N($N>=2$)개의 블록들을 갖고 있고, N-1개의 `nonRequestBlock`과 1개의 `requestBlock`으로 이루어져 있다. 위의 예시는 N이 2인 경우에 대한 설명이다. 그러나 epoch 길이를 확장하여 `requestBlock`과 `nonRequestBlock`의 비율을 변경할 수도 있다. ## Block submission Operator는 각 블록마다 `stateRoot`, `transactionsRoot`, `postTransactionalStatesRoot`(또는 `intermediateStatesRoot`)이 세 종류의 머클 루트를 제출한다. Exit request가 받아 들여지기 위해서는 특정 블록의 계정 상태(PETH 밸런스나 account storage의 값)에 대한 머클증명이 필요하다. 상태 변화에 대한 연산이 제대로 이루어지지 않았다면 `computationChallenge`를 통해 올바른 상태를 가지고 있는 블록으로 복구 된다. 이 방식은 TrueBit의 verification game과 유사한 방식이며, pre-stateRoot 및 post-stateRoot를 사용하여 '트랜잭션 별 상태 전환 함수'를 확인하는 방식으로 해결한다. ### [Block Withholding Attack](https://hackmd.io/kXWTlmyhSP2vVSIzsenU8w?both) 사용자가 block withholding attack을 감지하면 자산 및 상태를 보호하기 위해 사용자가 플라즈마 체인의 fork를 생성할 수 있다. 사용자는 플라즈마 체인을 fork하여 자신의 자산과 상태를 안전하게 root chain으로 exit할 수 있다. 플라즈마 체인이 byzantine이 아닌 경우에는 사용자가 fork를 생성하기 위해서는 상당한 시간과 비용이 필요하다. ![](https://i.imgur.com/sxq9LrZ.png) *<center>Root chain 컨트랙트 상태 변환 다이어그램</center>* ### Finality 챌린지 기간이 지난 후에 블록에 대한 챌린지를 할 수 없는 경우에 대비하여 플라즈마 EVM은 플라즈마 XT처럼 블록의 체크포인트를 지정할 수 있다. 이러한 Finality를 바탕으로 하여 RootChain 컨트랙트를 효율적으로 구현할 수 있다. ### Account Storage Enter & Exit 플라즈마 EVM에서는 어떠한 유형의 account storage 변수도 root chain과 child chain을 자유롭게 이동 할 수 있다. Storage 변수를 enter & exit request에 사용 할 수 있는 이유는 storage는 trie 구조로 되어있고, storage 내의 모든 값에 해당 키를 사용하여 접근 할 수 있기 때문이다. Enter & exit은 계정의 **단일 storage 변수**를 한 체인에서 이에 상응하는 컨트랙트의 다른 체인으로 이동하는 것을 의미한다. #### Notation NULL_ADDRESS: $NA$ Operator: $O$ User of plasma: $U$ Challenger: $Ch$ RootChain contract: $a_R$ Root chain *Requestable contract*의 주소: $a_r$ Child chain *Requestable contract*의 주소: $a_c$ *(각 체인에는 단 하나의 컨트랙트 주소만 있다.) Root chain의 storage 변수 주소: $σ[a_r]s[k]$, 이를 간단히 하면 $A^{r}_{s}[k]$와 같이 나타낼 수 있다. child chain의 storage 변수 주소: $σ[a_c]s[k]$, 이를 간단히 하면 $A^{c}_{s}[k]$와 같이 나타낼 수 있다. (단, $k$ 는 $trieKey$이고 $A_s$는 $σ[a]s$ 일 때) Trie의 *임의의 storage 변수*는 $A_s[k]$이고 root chain과 child chain의 request 가능한 컨트랙트 주소를 $a_r$과 $a_c$라 하자. 이것들의 storage 변수는 각기 $A^{r}_{s}[k]$와 $A^{c}_{s}[k]$이다. Storage 변수의 enter & exit request는 storage 변수가 $A^{r}_{s}[k]$와 $A^{c}_{s}[k]$ 사이를 이동하는 것으로 정의한다. Enter는 $A^{r}_{s}[k]$을 바탕으로 $A^{c}_{s}[k]$가 변경되는 과정이고 exit은 $A^{c}_{s}[k]$를 바탕으로 $A^{r}_{s}[k]$가 변경되는 과정이다. 그러나, 상태를 바꾸는 구체적인 방법은 구현 방식에 따라 달라질 수 있다. Storage의 변경을 적용하기 위에서는 $a_r$과 $a_c$가 같은 바이트코드를 갖고 있어야 하며, 두 컨트랙트 주소가 같은 바이트 코드를 갖고 있다는 것은 두 컨트랙트가 같은 storage 레이아웃을 갖고 있다는 것을 의미한다.(두 컨트랙트 코드의 해시값을 비교하는 것으로도 검증 가능하다.) 그러나, 모든 변수가 requestable일 필요는 없다. Request와 관련된 기능이 필요 없는 변수도 있고, 특정 변수에 대해 어떤 사용자가 request할 수 있는지에 대한 고려도 필요하기 때문이다. 예를 들어, 누구나 타인의 토큰 밸런스에 대해 request 할 수 있어서는 안되기 때문이다. 따라서 우리는 미리 컨트랙트 함수에 이러한 문제를 해결할 수 있는 로직을 배치하고자 한다. 이러한 작업은 변수가 선언 된 순서와 trieKey를 이용하여 앞에서 제시한 문제에 대해 확인 할 수 있기에 가능하다. 자세한 내용은 아래의 의사 코드에 대해 다룬 섹션에서 살펴 볼 것이다. 우선, `Enter`와 `exit`의 구체적인 과정에 대해 살펴보도록 하겠다. #### Enter ![](https://i.imgur.com/pqGxsfT.png) 1. 사용자 $U$는 $a_r$, `trieKey` 및 `trieValue`를 독립변수로 사용하여 $a_R$의 `enter()` 함수를 호출하여 $a_c$에 해당하는 $A^{r}_{s}[k]$에 enter 한다. 2. 그 다음 `enter()` 함수에서, $a_r$의 `applyRequestInRootchain()` 함수가 호출된다. 3. 2번 과정이 revert 된다면, enter request를 처리하는 과정이 중단된다. Revert 되지 않는다면 $R$에 `enterRequest` 이벤트가 생성된다. 4. $O$는 다음`requestBlock`에 `enterRequest`를 처리하는 $NA$의 트랜잭션을 담아야한다. $O$가 `enterRequest`를 블록에 제대로 담지 않는다면 $Ch$는 이에 대해`requestChallenge`를 할 수 있다. 5. 4번 과정의 트랜잭션에서 $NA$는 $a_c$의`enterRequest`에 따라`applyRequestInChildchain()` 함수를 실행한다. 그러면 $A^{c}_{s}[k]$가 $A^{c}_{s}[k]'$로 변한다. 이러한 상태 변화 과정이 올바르게 이루어지지 않으면 $Ch$는`computedChallenge`를 할 수 있다. #### Exit ![](https://i.imgur.com/vhMVtaA.png) 1. 사용자 $U$는 $a_r$에 해당하는 $A^{c}_{s}[k]$에서 exit 하기 위해, $a_r$,`trieKey` 및`trieValue`를 독립변수로 사용하여 $a_R$에서`startExit()`을 호출한다. 2. $U$의 `exitRequest`는 $a_R$에서 생성되며 $O$에 의해 다음`requestBlock`에 포함된다. $O$가 `exitRequest`를 포함하지 않는다면 ,$Ch$는 이에 대해 `requestChallenge`를 할 수 있다. 3. 다음 `requestBlock`에는 $NA$가`exitRequest` 절차에 따라 $a_c$에서`applyRequestInChildchain()`함수를 실행하는 트랜잭션이 담겨야 한다. *3번 과정*이 제대로 실행되지 않으면 $Ch$는`computationChallenge`를 할 수 있다. 4. *3번 과정*이 제대로 실행되었음에도 트랜잭션이 revert 된다면, $Ch$는 트랜잭션의 output을 증거로 삼아 `exitChallenge`를 통해 `exitRequest`를 할 수 있다. 5. *4번 과정*에서 챌린지가 발생하지 않는다면, `exitRequest`가 `finalize` 된다고 볼 수 있다. 그러나`exitChallenge`가 타당하다는 것이 증명되면 `exitRequest`의 `finalize`는 취소된다. 6. $U$는 $a_R$에서`finalizeExit()`함수를 호출하여 `exitRequest`를 `finalize` 할 수 있다. $a_R$은 $a_r$에서`applyRequestInRootchain()` 함수를 호출한다. `applyRequestInRootchain()` 함수가 문제없이 실행 된다면 $A^{r}_{s}[k]$에서 $A^{r}_{s}[k]'$로의 변경이 이루어진다. 컨트랙트 개발자는 $a_r$의`applyRequestInRootchain ()` 함수가 throw되면 안된다는 것을 **반드시** 확인 해야한다. 이러한 변경은 반드시 이루어져야 하며, exit의 유효성은`exitChallenge`에 대한 증명으로 사용될 수 있는 $a_c$의`applyRequestInChildChain()`함수에서 확인 할 수 있다. #### RootChain and Requestable Contract Child chain의 RootChain 컨트랙트는 `RequestableRootChain` 인터페이스를 가지고 있다. Requestable 컨트랙트는`enterRequest`가 storage 변수를 $a_r$에서 $a_c$로 enter하게 할 수 있다. 사용자는`rootchain.enter`로 직접 enter request를 할 수 있다. ```solidity interface RequestableRootChain { function getExitFinalized(uint256 requestId) public returns(bool); function startExit( address contractAddress, bytes32 trieKey, bytes32 trieValue ) returns (bool); // User can directly make an enter request with trieKey and trieValue. function enter( address contractAddress, bytes32 trieKey, bytes32 trieValue ) returns (bool); // Requestable contract can initialize an enter request with proper // trieKey and trieValue. This makes user not to take care of what is exact // trieKey for `balances[requestor]`. function makeEnterRequest( address requestor, bytes32 trieKey, bytes32 trieValue ) returns (bool); // finalize exits function finalizeExit() public returns (bool); } interface Requestable { // check the request is applied or not in root chain. function setRequestApplied(uint256 requestId) internal returns (bool); function getRequestApplied(uint256 requestId) internal returns (bool); // Apply storage changes in root chain for exit and enter reuqests. // For enter request, This is called in the middle of `rootchain.enter` // or `rootchain.makeEnterRequest` to initialize an enter request. // If this returns true, the enter request is queued into `enterRequests`. // For exit request, This is called in `rootchain.finalizeExit`. function applyRequestInRootChain( bool isExit, uint256 requestId, address requestor, bytes32 trieKey, bytes32 trieValue ) external returns (bool success); function applyRequestInChildChain( bool isExit, uint256 requestId, address requestor, bytes32 trieKey, bytes32 trieValue ) external returns (bool success); } ``` 간단한 requestable 토큰 컨트랙트의 예시는 다음과 같다. ```solidity contract RequestableToken is Requestable { // 3 requestable variables. address owner; // `owner` is stored at bytes32(0). uint totalSupply; // `totalSupply` is stored at bytes32(1). // `balances[addr]` is stored at keccak256(bytes32(addr), bytes32(2)). mapping(address => uint) balances; RequestableRootChain rootchain; address NULL_ADDRESS = address(0); // or 0xFF..FF // this is only called by the RootChain contract in root chain // when i) enterRequest is initialized or // ii) exitRequest is finalized function applyRequestInRootChain( bool isExit, uint256 requestId, address requestor, bytes32 trieKey, bytes32 trieValue ) external returns (bool success) { require(msg.sender == address(rootchain)); require(!getRequestApplied(requestId)); // check double applying if (isExit) { // exit must be finalized. require(rootchain.getExitFinalized(requestId)); if(bytes32(0) == trieKey) { // only owner (in child chain) can exit `owner` variable. // but it is checked in applyRequestInChildChain and exitChallenge. // set requestor as owner in root chain. owner = requestor; } else if(bytes32(1) == trieKey) { // no one can exit `totalSupply` variable. // but do nothing to return true. } else if (keccak256(requestor, 2) == trieKey) { // this checks trie key equals to `balances[requestor]`. // only token holder can exit one's token. // exiting means moving tokens from child chain to root chain. balances[requestor] += uint(trieValue); } else { // cannot exit other variables. // but do nothing to return true. } } else { // apply enter if(bytes32(0) == trieKey) { // only owner (in root chain) can enter `owner` variable. require(owner == requestor); // do nothing in root chain } else if(bytes32(1) == trieKey) { // no one can enter `totalSupply` variable. revert(); } else if (keccak256(bytes32(requestor), bytes32(2)) == trieKey) { // this checks trie key equals to `balances[requestor]`. // only token holder can enter one's token. // entering means moving tokens from root chain to child chain. require(balances[requestor] >= uint(trieValue)); balances[requestor] -= uint(trieValue); } else { // cannot apply request on other variables. revert(); } } setRequestApplied(requestId); return true; } // this is only called by NULL_ADDRESS in child chain // when i) exitRequest is initialized by startExit() or // ii) enterRequest is initialized function applyRequestInChildChain( bool isExit, uint256 requestId, address requestor, bytes32 trieKey, bytes32 trieValue ) external returns (bool success) { require(msg.sender == NULL_ADDRESS); if (isExit) { if(bytes32(0) == trieKey) { // only owner (in child chain) can exit `owner` variable. require(requestor == owner); // do nothing when exit `owner` in child chain } else if(bytes32(1) == trieKey) { // no one can exit `totalSupply` variable. revert(); } else if (keccak256(bytes32(requestor), bytes32(2)) == trieKey) { // this checks trie key equals to `balances[tokenHolder]`. // only token holder can exit one's token. // exiting means moving tokens from child chain to root chain. // revert provides a proof for `exitChallenge`. require(balances[requestor] >= uint(trieValue)); balances[requestor] -= uint(trieValue); } else { // cannot exit other variables. revert(); } } else { // apply enter if(bytes32(0) == trieKey) { // only owner (in root chain) can make enterRequest of `owner` variable. // but it is checked in applyRequestInRootChain. owner = requestor; } else if(bytes32(1) == trieKey) { // no one can enter `totalSupply` variable. } else if (keccak256(bytes32(requestor), 2) == trieKey) { // this checks trie key equals to `balances[tokenHolder]`. // only token holder can enter one's token. // entering means moving tokens from root chain to child chain. balances[requestor] += uint(trieValue); } else { // cannot apply request on other variables. } } return true; } // make an enter request for `owner` variable. function enterOwner() external returns (bool) { require(msg.sender == owner); require(rootchain.makeEnterRequest(msg.sender, bytes32(0), owner)); return true; } // make an enter request for `balances[msg.sender]`. // If user know trieKey, one can call `rootchain.enter` directly. function enterBalance(uint amount) exernal returns (bool) { // it is also checked in applyRequestInRootChain require(balances[msg.sender] >= amount); bytes32 trieKey = keccak256(bytes32(msg.sender), bytes32(2)); // this subtracts `balances[msg.sender]` by `amount` require(rootchain.makeEnterRequest(msg.sender, trieKey, amount); return true; } // User can get the trie key of one's balance and make an enter request directly. function getBalanceTrieKey(address who) public pure returns (bytes32) { return keccak256(bytes32(who), bytes32(2)); } } ``` ### Challenge #### Request Challenge `requestChallenge`를 위하여 RootChain 컨트랙트는 request의 유효성 검증을 위한 트랜잭션 데이터를 구성할 수 있다. 트랜잭션 의 `from'`은 NULL_ADDRESS, `to`는 ChildChain 컨트랙트의 주소, `value`는 0, `data`는 request 유형과 파라미터에 의해 정의되고 `nonce`는 각 request마다 순차적으로 증가한다. 실제 트랜잭션 데이터가 RootChain 컨트랙트에 의해 구성되는 데이터와 일치하지 않는다면, `requestBlock`이 이전 `nonRequestBlock`으로 되돌릴 것이다. Request에 대한 연산은 computationChallenge에 의해 검증 된다. #### NullAdress Challenge `nonRequestBlock`에 트랜잭터가 NULL_ADDRESS인 트랜잭션이 있는지 확인한다. #### Exit Challenge `requestBlock`에 포함된 `exitRequest`가 *revert* 되었다면, 해당 `exitRequest` 는 **반드시** RootChain 컨트랙트에서 삭제되어야 한다. Invalid exitRequest에 대한 `exitChallenge` 절차는 revert 된 트랜잭션을 증거로 삼아 처리된다. 그러나 exit request에 대해 챌린지하기 전에, 처리된 request를 포함하고 있는 블록은 일단 finalize 되어야 한다. 왜냐하면, invalid한 블록에서는 트랜잭션이 revert될 수 있고, valid한 블록에서는 revert 되지 않을 것이기 때문이다. 그렇기 때문에 exit challenge는 `requestBlock`이 finalize 된 후에 시작 될 수 있다. #### Computation Challenge computationChallenge는 operator가 트랜잭션을 올바르게 실행했는지를 검증한다. 즉 상태가 미리 정의 된 방식으로 변경 되었는지를 확인하는 것이다(예: 스마트 컨트랙트 바이트 코드). Operator가 잘못된 `stateRoot`를 제출하면, 이는 상태 변환이 올바르게 이루어지지 않았다고 판단할 근거가 된다. 그러면 `txData`,`preStateRoot` 및`postStateRoot`와 함께 TrueBit의 verification game과 유사한 방법을 사용하여 챌린지 될 수 있다. $$postState = STF_{tx}(preState, TX_i)$$ $$postState = postTransactionalStates[i]$$ $$ preState=\begin{cases} postTransactionalStates[i-1] & \text{if}\ i>0 \\ previousStateRoot & \text{otherwise}\end{cases}$$ RootChain 컨트랙트에서 $STF_{tx}$를 시뮬레이션하고 output을 이미 제출 된 output과 비교하여 연산이 올바르게 이루어졌는지에 대한 여부를 확인할 수 있다. #### Verification Game TrueBit은 outsource된 연산을 검증하기 위한 방법으로 *verification game*을 제안했다. 그러나 TrueBit이 제안한 게임의 마지막 단계는 이더리움에서 연산을 한 번 수행하고 실제 output과 예상 output을 비교하는 방법을 사용한다. 하지만 우리는 Ohalo와 PARSEC에서 구현해 왔던 EVM 내부에서 EVM을 실행하는 스마트 컨트랙트인 solevm을 사용하여 연산 결과를 검증하고자 한다. ![](https://i.imgur.com/BVFY09y.png) 그러나 [수수료 위임 체인](https://hackmd.io/s/SkxNKAXU7)을 사용하려면 EVM을 통한 트랜잭션 실행을 포괄해야 한다. ### References - [Joseph Poon and Vitalik Buterin, Plasma: Scalable Autonomous Smart Contracts](https://plasma.io/) - [Minimal Viable Plasma](https://ethresear.ch/t/minimal-viable-plasma/426) - [Plasma Cash](https://ethresear.ch/t/plasma-cash-plasma-with-much-less-per-user-data-checking/1298) - [Plasma XT](https://ethresear.ch/t/plasma-xt-plasma-cash-with-much-less-per-user-data-checking/) - [Cryptoeconomic aggregated signature](https://ethresear.ch/t/cryptoeconomic-signature-aggregation/) - [PARSEC Labs, PLASMA - FROM MVP TO GENERAL COMPUTATION](https://parseclabs.org/files/plasma-computation.pdf) - [Why Smart Contracts are NOT feasible on Plasma](https://ethresear.ch/t/why-smart-contracts-are-not-feasible-on-plasma/2598) - [TrueBit, A scalable verification solution for blockchains ](https://people.cs.uchicago.edu/~teutsch/papers/truebit.pdf)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully