EOS - 개발자 일지 항성력 201707.3

in #eoskorea7 years ago

오늘 저는 개발하기 쉽고 간단하게 병렬 처리할 수 있는 스마트 컨트렉트를 만들기 위해 팀원들과 논의했습니다. 병렬 처리와 관련한 문제에 익숙하신 분들은 모든 데이터가 단일 스레드에 의해 소유 되어야 한다는 일반적인 규칙을 알고 계실겁니다. 이는 블록 체인의 관점에서 모든 계좌가 자신의 데이터를 소유 한다는 것을 뜻합니다. 데이터를 소유하는 것은 비동기 메시지 전달이 아니면 다른 실행중인 스레드의 데이터를 읽거나 쓰지 못한다는 사실을 의미합니다.

현재의 잔고 문제

다른 컨트렉트 내 있는 현재 잔액을 읽고 싶다고 가정해봅시다.(사소한 것처럼 보이는 일이죠.) 다른 계좌가 잔액을 소유하고 있는 통화 컨트렉트에서 여러분의 컨트렉트는 그 잔액을 읽을 수 없습니다. 비동기 통신으로 질의 요청을 보낼 수 있지만, 이는 은행에 잔액 변경을 위한 메일을 보내고 응답 메일이 돌아올 때까지 기다리고 있는 것과 다를 바가 없습니다. 심지어 응답을 받았을 때의 잔액 데이터는 너무 오래되어 적절하지 못할 수도 있습니다.

다행히도 EOS는 한 계좌 내의 모든 예출금을 쉽게 감시할 수 있도록 만듭니다. 이 경우 읽기 작업을 수행하는 컨트렉트는 통화 컨트렉트의 잔액 계산과 저장을 담당하는 자체 로직을 복사하여 관리합니다. 이 접근법 역시 작은 행위의 변화가 통화 컨트렉트 내 잔액 계산 결과의 차이를 만들 수 있다는 점에서 오류가 발생하기 쉬운 문제가 남아 있습니다.

또 다른 대안은 오라클을 이용해 여러분의 컨트렉트 잔액을 알리는 동시에 통화 컨트렉트로 메시지를 전달하는 것입니다. 오라클이 거짓말한다면 통화 컨트렉트는 거래를 거부할 수 있기에 상대방이 보고한 잔액을 신뢰할 수 있습니다. 이 방법으로 거래가 적용되는 순간의 잔액을 알 수 있으나, 다른 사용자가 같은 순간에 잔액을 수정한다면 거래를 무효화 할 수 있는 문제가 있습니다.

이 난제의 근본 원인은 잔액 데이터가 다른 스레드에 의해 소유되고 있으면 필요할 때 안정적으로 읽고 쓸 수 없다는 사실로부터 기인합니다.

문제 재정의

위 모델에서 모든 데이터는 단일 계정과 코드가 소유했습니다. 이런 구조에서는 각 계정이 자체 블록체인, 타 계정들과 통신을 하기 까다로웠습니다. 다행히 GPU 개발자들은 다른 병렬화 전략인 SMID(단일 명령, 다중 데이터)를 사용했습니다. 일반적으로 말하자면, GPU는 독립적인 데이터 인스턴스에서 동일한 코드를 실행하고 모든 픽셀과 정점은 동일한 명령어 세트로 수정됩니다.

모든 계정의 잔액이 이미지의 픽셀로 표현되는 순간을 상상해보세요. 스마트 컨트렉트가 쉐이더(셰이더는 3차원 모델링에서 광원과 그림자를 만드는데 일반적으로 사용됩니다, 옮긴이 부연 설명)처럼 정의되었다고 상상해보세요. 픽셀 셰이더는 단일 픽셀에만 쓸 수 있지만 다른 읽기 전용 소스를 얼마든지 읽어낼 수 있습니다.

이 모델 하에서 통화 컨트렉트는 계정명과 잔액을 맵핑하는 코드로 정의되는 것이 아니라 단일 계정에 속한 단일 잔액에서 동작하는 코드로 정의됩니다. 통화 컨트렉트는 다른 계좌의 잔액을 읽을 수 없지만 모든 계좌가 동일한 코드로 실행되고 있다는 사실을 확실하게 알 수 있습니다.

컨트렉트는 어떻게 생겼을까요?

void apply_simplecoin_transfer() {
   static Transfer message;
   static uint64_t balance = 0;
   load( thisContract(), “balance”, balance );
   
   readMessage( message  );
   requireNotify( {message.from, message.to} );
   
   if( thisAccount() == message.to ) {
      balance += message.amount;
   } else if ( thisAccount() == message.from ) {
      assert( message.amount < balance, "insufficient funds" )
      balance -= message.amount;
   }
   
   if( balance ) store( “balance”, balance );
   else remove( “balance”, balance );
}

미묘한 차이점들을 주목해 보세요.

  1. apply method(적용 함수)는 오직 단일 잔액만 수정합니다.
  2. 컨트렉트의 행위는 오직 thisAccount() 값에 의존합니다.
  3. load()는 현 컨트렉트를 지칭하는 매개 변수만 추가로 취할 수 있습니다.
  4. store()와 remove()는 항상 계정 키가 아닌 잔액 키를 사용합니다.

모든 계좌가 개인 정보에 대해 완벽하게 동일한 코드를 사용한다고 가정하면, 이중 지출이 일어나지 않는다는 사실을 보장할 수 있게 됩니다. 이는 모든 계정에서 발신자와 수신자 모두가 메시지를 통보받지 않으면 컨트렉트이 거부되기 때문에 가능합니다.(두 당사자가 동시에 통지 받습니다.)

수신자는 발신자에게 충분한 자금이 있는 지 확인한 후 불충분하다면 메시지 수신을 거부할 수 있습니다. 따라서 수신자는 안전하게 자신의 잔액을 증가시킬 수 있습니다. 마찬가지로 발신자는 수신자가 잔액을 늘린 것을 확인하고 자신의 잔액을 줄일 수 있습니다.

무엇을 할 수 있나요?

이제 우리는 병렬화 관점에서 코드와 데이터를 분리한 디자인 패턴을 가지고 있습니다. 이제 단일 계좌는 다른 계정에서 제공하는 코드를 실행하고 다른 계정에서 공급 받은 코드는 계정에 속한 데이터를 모두 읽어들일 수 있습니다.

보팅 웨이트가 현재 잔액에 비례하는 소셜 미디어 플랫폼을 만든다고 가정해 봅시다. 이 SNS는 소셜 미디어 계정의 잔액을 읽고 다른 게시물 보팅의 합계를 수정할 수 있어야 합니다. 이상적인 세계에서 @alice@bob에게 보팅하고 @sam@bill에게 보팅한다고 생각해봅시다. 과정은 다음과 같습니다.

void apply_social_vote() {
   readMessage( vote );
   if( vote.for == thisContract() ) {
      load( thisContract(), vote.postid, post );
      post.totalvotes += vote.weight;
      store( vote.postid, post );
   } 
   
   if( vote.voter == thisAccount() ) {
      static uint64_t balance = 0;
      load( "simplecoin", "balance", balance );
      assert( balance >= vote.weight, “insufficient balance for vote weight” );
   }
}

컨트렉트 코드는 실행중인 데이터에 따라 두 가지 다른 작업을 수행합니다. 코드는 보팅 받는 이의 총 보팅 수를 증가시키는 일을 수행합니다. 보팅한 이에게는 보팅파워가 현재 잔액보다 작거나 같은지 확인합니다.

보팅 받는 이는 보팅한 이의 잔액을 읽을 수 없다는 점을 유의합시다. 이 모델에서는 보팅한 이의 보팅 웨이트가 올바른 경우만 2개의 보팅이 4개의 서로 다른 계좌에서 병렬 처리되도록 동작합니다.

다른 사람의 잔액을 읽어들이는 동시에 자신의 상태를 수정하는 것은 불가능할 수 있지만, ‘사회적’ 컨트렉트 내 ‘simplecoin’ 컨트렉트로부터 자신의 잔고를 읽어들이는 것은 가능합니다.

왜 이렇게 복잡한가요?

우리는 프로그래머로서 우리가 원하는 것을 읽고, 필요한 것이 생길때마다 이를 컴퓨터로 동작하도록 구현하는 일을 사랑합니다. 단순 접근법은 데이터에 락을 거는 것이었습니다. 두 사람이 동시에 데이터를 읽으려하면 한 사람은 다른 사람의 작업이 끝날 때까지 기다려야 했습니다. 불행히도 블록체인 개발자에게 이러한 경쟁 조건의 결과는 결정적이지도 않고 합의를 깨뜨릴 수 있기에 만족스럽지 못했습니다.

새로운 희망

한 계정이 다른 계정의 잔액을 읽어들이는 과정을 설명하겠습니다. 먼저, 트렌젝션은 읽기 권한이 필요하다고 선언합니다. 그리고 블록체인의 트렌젝션 스케쥴러는 쓰기 권한을 필요로 하는 어떤 사용자도 동시에 코드를 실행하지 못하도록 막습니다. Simplecoin에 대한 예전 접근법(하나의 컨트렉트가 모든 데이터를 소유함)으로는 사용자들이 읽기 명령을 요청할 때마다 쓰기를 원하는 사용자의 동작이 차단되었기 때문에 하나의 컨트렉트만으로도 병목현상이 발생하고 혼잡도가 증가했습니다.

하지만 저희가 소개하는 새로운 접근법을 simplecoin에 적용하면, 동일한 계정 데이터에 두 컨트렉트가 동시에 접근하게 되는 확률이 훨씬 낮아집니다. 따라서 교착 상태에 빠지는 상황이 발생하는 것을 줄이고 처리량을 극대화할 수 있게되었습니다.

결론

병렬 처리는 어렵고, 공유 데이터에 동시에 접근하면서 예측한 결과가 제대로 수행될 수 있도록 만드는 것은 특히 어려운 작업입니다. 그러나 우리는 감사하게도 GPU와 컴퓨터 그래픽 알고리즘 개발자들이 증명한 해결방안과 디자인 패턴을 알고 있습니다.

주의 블로그에 어떠한 게시물도 EOS.IO 소프트웨어의 세부적인 특징이나 기능을 암시하는 것으로 해석되어서는 안됩니다. 모든 소프트웨어 디자인은 필요에 따라 변경될 수 있습니다.


원문: https://steemit.com/eos/@dan/eos-developer-s-log-starday-201707-3
@yguhan 님께서 번역해주신 글입니다. 번역자를 위한 투표는 이 링크에서 하실 수 있습니다.

Sort:  

Again very informative and useful for my research of EOS. An investor and believer in EOS . I believe EOS will be big in the near future. Good post. Follow me for content. Thnx.

좋은 포스트 감사합니다

Coin Marketplace

STEEM 0.16
TRX 0.13
JST 0.027
BTC 58167.06
ETH 2592.42
USDT 1.00
SBD 2.44