블록체인2017. 7. 7. 13:34

https://www.facebook.com/groups/1429149120539506/



이 글은 https://ethereum.org/token 의 발번역입니다.

참고용으로만...


이글은 비트코인과 이더리움에 대한 이해가 있다는것을 가정합니다. 이더리움으로 만들 수 있는 여러가지 유형의 애플리케이션중에 토큰베이스에 대해서 설명합니다.


우리는 디지털토큰을 만들것이다. 이더리움 생태계에서 토큰은 모든 대체가능한 상품(동전, 누적포인트, 금인증서, 게임아이템등)을 나타낼수 있다. 모든 토큰들은 표준방식으로 몇가지 기본기능을 구현하기 때문에 이더리움 지갑, 다른 클라이언트 또는 동일한 표준을 사용하는 계약과 바로 호환될 수 있습니다.


아래 코드를 복붙해서 바로 사용 가능하다


pragma solidity ^0.4.8;

contract tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData); }


contract MyToken {

    /* Public variables of the token */

    string public standard = 'Token 0.1';

    string public name;

    string public symbol;

    uint8 public decimals;

    uint256 public totalSupply;


    /* This creates an array with all balances */

    mapping (address => uint256) public balanceOf;

    mapping (address => mapping (address => uint256)) public allowance;


    /* This generates a public event on the blockchain that will notify clients */

    event Transfer(address indexed from, address indexed to, uint256 value);


    /* This notifies clients about the amount burnt */

    event Burn(address indexed from, uint256 value);


    /* Initializes contract with initial supply tokens to the creator of the contract */

    function MyToken(

        uint256 initialSupply,

        string tokenName,

        uint8 decimalUnits,

        string tokenSymbol

        ) {

        balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens

        totalSupply = initialSupply;                        // Update total supply

        name = tokenName;                                   // Set the name for display purposes

        symbol = tokenSymbol;                               // Set the symbol for display purposes

        decimals = decimalUnits;                            // Amount of decimals for display purposes

    }


    /* Send coins */

    function transfer(address _to, uint256 _value) {

        if (_to == 0x0) throw;                               // Prevent transfer to 0x0 address. Use burn() instead

        if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough

        if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows

        balanceOf[msg.sender] -= _value;                     // Subtract from the sender

        balanceOf[_to] += _value;                            // Add the same to the recipient

        Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place

    }


    /* Allow another contract to spend some tokens in your behalf */

    function approve(address _spender, uint256 _value)

        returns (bool success) {

        allowance[msg.sender][_spender] = _value;

        return true;

    }


    /* Approve and then communicate the approved contract in a single tx */

    function approveAndCall(address _spender, uint256 _value, bytes _extraData)

        returns (bool success) {

        tokenRecipient spender = tokenRecipient(_spender);

        if (approve(_spender, _value)) {

            spender.receiveApproval(msg.sender, _value, this, _extraData);

            return true;

        }

    }        


    /* A contract attempts to get the coins */

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {

        if (_to == 0x0) throw;                                // Prevent transfer to 0x0 address. Use burn() instead

        if (balanceOf[_from] < _value) throw;                 // Check if the sender has enough

        if (balanceOf[_to] + _value < balanceOf[_to]) throw;  // Check for overflows

        if (_value > allowance[_from][msg.sender]) throw;     // Check allowance

        balanceOf[_from] -= _value;                           // Subtract from the sender

        balanceOf[_to] += _value;                             // Add the same to the recipient

        allowance[_from][msg.sender] -= _value;

        Transfer(_from, _to, _value);

        return true;

    }


    function burn(uint256 _value) returns (bool success) {

        if (balanceOf[msg.sender] < _value) throw;            // Check if the sender has enough

        balanceOf[msg.sender] -= _value;                      // Subtract from the sender

        totalSupply -= _value;                                // Updates totalSupply

        Burn(msg.sender, _value);

        return true;

    }


    function burnFrom(address _from, uint256 _value) returns (bool success) {

        if (balanceOf[_from] < _value) throw;                // Check if the sender has enough

        if (_value > allowance[_from][msg.sender]) throw;    // Check allowance

        balanceOf[_from] -= _value;                          // Subtract from the sender

        totalSupply -= _value;                               // Updates totalSupply

        Burn(_from, _value);

        return true;

    }

}


토큰 컨트랙트는 상당히 복잡하다. 다음은 토큰을 구현하기 위한 최소의 코드이다.


contract MyToken {

    /* This creates an array with all balances */

    mapping (address => uint256) public balanceOf;


    /* Initializes contract with initial supply tokens to the creator of the contract */

    function MyToken(

        uint256 initialSupply

        ) {

        balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens

    }


    /* Send coins */

    function transfer(address _to, uint256 _value) {

        if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough

        if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows

        balanceOf[msg.sender] -= _value;                     // Subtract from the sender

        balanceOf[_to] += _value;                            // Add the same to the recipient

    }

}


코드를 이해해 보자



지갑앱을 실행 > Contract탭 > Deploy New Contract 선택

Solidity Contract Source code 입력필드에 아래 코드 입력


contract MyToken {

    /* This creates an array with all balances */

    mapping (address => uint256) public balanceOf;

}


매핑이란 주소를 잔액과 연결하는 연관 배열을 의미한다. 주소는 16진수 이더리움 포맷이며 잔액은 0에서 115*1027 범위의 정수이다 얼마나 큰수인지 상상이 안간다면 네가 계획산 전체 토큰수보다 많을거다. public 키워드는 블록체인에서 어디서든 접근 가능하게 한다. 즉 모든 잔액이 공개되어야 한다(클라이언트가 표시해야 하는 경우).


컨트랙트를 발행 했다면 효과가 있지만 유용하지는 않다. 즉 토큰의 잔액을 주소로 조회할 수 있는 컨트랙트가 될수 있으나 토큰 하나를 만들지 않았기 때문에 모두가 0을 반환한다. 그래서 시작할때 몇개의 토큰을 만들것이다. mapping... 바로 아래 코드를 추가하라.


contract MyToken {

    /* This creates an array with all balances */

    mapping (address => uint256) public balanceOf;

    

    function MyToken() {

        balanceOf[msg.sender] = 21000000;

    }

}


function MyToken과 contract MyToken이 동일한것을 눈여겨 보아야 한다. 하나를 변경하면 나머지 하나도 변경해야 한다. 생성자 역할을 하며 네트워크에 컨트랙트가 업로드될때 한번만 호출된다. 이 함수는 컨트랙트를 전개한 사용자인 msg.sender의 잔액을 2100만 잔고로 설정한다.

이 값은 이렇게 고정된 수가 아니라 파라메터로 초기화를 하는것이 좋다.


function MyToken(uint256 initialSupply) {

    balanceOf[msg.sender] = initialSupply;

}


컨트랙트 옆에 오른쪽에 보면 드롭다운에서 "My Token"을 선택하면 Constructor parameters를 볼수 있다. 변경가능한 파라메터로 같은코드를 재사용하여 변수를 변경할 수 있다.


지금은 토큰의 잔액을 만든 계약을 가지고 있지만 아무런 변화가 없기 때문에 이제 이동에 대해 구현하겠다.


/* Send coins */

function transfer(address _to, uint256 _value) {

    /* Add and subtract new balances */

    balanceOf[msg.sender] -= _value;

    balanceOf[_to] += _value;

}


이것은 매우 직관적인 기능이다.  수신자와 값을 파라메터로 갖고 호출될때마다 해당 값을 잔액에서 차감하고 수신자의 잔액은 증가시킨다. 여기에는 명백한 문제가 있다. 잔액이 부족할 경우 어떤일이 일어날까? 이 계약에 대해 부체를 처리할것이 아니기 때문에 빠르게 확인하고 송금자의 자금이 충분치 않으면 계약 실행이 중지된다. 또한 오버플로가 있는지 확인하여 0이 되게 하는 너무 큰숫자를 피한다.


계약의 실행을 중간에 정지하려면 return 이나 throw를 호출한다. 전자는 가스비용은 적은 반면 계약의 실행에 의한 변경사항이 적용되면서 더 머리가 아파질수 있다. 반면에 throw는 모든 계약실행을 취소하고 모든 변경을 원상복구하고 가스비용으로 사용된 이더를 잃게된다. 하지만 지갑이 throw를 예측하고 경고를 함으로써 더이상 이더를 소모하는것을 막아준다.


 이 글 작성 이후 2017년 8월 현재 throw는 deprecated되었다. revert(), require(), assert()의 사용이 권장된다.


function transfer(address _to, uint256 _value) {

    /* Check if sender has balance and for overflows */

    if (balanceOf[msg.sender] < _value || balanceOf[_to] + _value < balanceOf[_to])

        throw;


    /* Add and subtract new balances */

    balanceOf[msg.sender] -= _value;

    balanceOf[_to] += _value;

}


이제 남은것은 계약에 대한 기본정보에 대한 것이다. 이 정보는 추후 토큰의 등록으로 조작이 가능하겠지만 우리는 계약에 직접 추가할것이다


string public name;

string public symbol;

uint8 public decimals;


그리고 생성자 함수를 시작할 때 업데이트한다.


/* Initializes contract with initial supply tokens to the creator of the contract */

function MyToken(uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol) {

    balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens

    name = tokenName;                                   // Set the name for display purposes

    symbol = tokenSymbol;                               // Set the symbol for display purposes

    decimals = decimalUnits;                            // Amount of decimals for display purposes

}


마지막으로 Events로 불리는 것이 필요하다. 이더이움 지갑같은 클라이언트가 계약에서 일어나는 활동을 추적할수 있도록 도와준다. Events는 대문자로 시작해야 하고 다음과 같이 이벤트를 선언하라.


event Transfer(address indexed from, address indexed to, uint256 value);


이제 transfer 함수내에서 호출해주면 된다.


    /* Notify anyone listening that this transfer took place */

    Transfer(msg.sender, _to, _value);


자 이제 토근이 준비가 다 되었다.



배포방법


이더리움지값을 열어서 컨트랙트탭의 "deploy new contract"를 선택하라.

Solidity source filed에 위에서 작성한 소스코드를 복사 및 붙여넣기를 하라. 코드 컴파일이 문제가 없다면 "pick a contract"를 볼수 있을것이고 "MyToken"를 드롭박스에서 선택하라. 그러면 파라메터를 입력할 수 있는 컬럼이 보일것이다.  원하는대로 조정할 수 있지만 튜터리얼의 목적에 따라 공급 매개변수 10000개 기호는 %, 소수자릿수 2개를 선택한다. 아래 처럼.

페이지 끝으로 스크롤하면 해당 계약의 계산 비용이 대략적으로 표시되며 이더비용을 지불할 의사가 있는 요금을 선택할 수 있다. 쓰지 않는 초과 이더는 돌려 보내질 것이므로 원한다면 기본 설정을 그대로 둘 수 있다. "배포"를 누르고 계정 암호를 입력 한 후 거래가 시작될 때까지 몇 초 기다린다.


그러면  첫페이지로 이동하여 거래 확인을 기다리는 것을 볼 수 있다. Etherbase(당신의 주계정)을 클릭하면 1분이 지나면 방금 만든 공유의 100%를 계정에 표시한다. 일부를 친구에게 보내려면 친구의 주소를 복사하여 "to"필드에 집어넣고 "send"를 눌러라.


친구에게 보내면 아직 지갑에는 아무것도 표시되지 않는다. 지갑이 알고 있는 토큰만 추적하기 때문에 지갑을 수동으로 추가해야 한다. 이제 '컨트랙트'탭으로 이동하면 새로 생성 된 컨트랙트 링크가 표시된다. 해당 페이지로 이동하려면 클릭한다. 이것은 매우 간단한 컨트랙트 페이지이므로 여기서 할 일이 많지 않다. "주소 복사"를 클릭하고 컨트랙트 주소를 텍스트 편집기에 붙여 넣는다.

확인하고자하는 토큰을 추가하려면 컨트랙트 페이지로 이동 한 다음 "Watch Token"을 클릭하라. 팝업 창이 나타나면 계약서 주소 만 붙여넣는다. 토큰 이름, 기호 및 십진수는 자동으로 채워 져야하지만 그렇지 않은 경우 원하는 것을 넣을 수 있다 (지갑에 표시되는 방식에만 영향을 미침). 이렇게하면 토큰의 잔액이 자동으로 표시되어 다른 사람에게 보낼 수 있다.


이제 당신만의 암호화된 토큰을 가지게 되었다. 토큰은 로컬커뮤니티내에서 가치교환에 유용하게 사용될수 있고, 근무시간 또는 다른 로열티프로그램을 추적할 수 있다. 하지만 통화를 만들어서 본질적인 가치를 만들 수 있는가?






Posted by 삼스
블록체인2017. 7. 6. 14:58


1. 이더리움


분산어플리케이션을 만들기위한 프로토콜

- 빠른 개발

- 보안

- 타앱과 상호작용

튜링완전언어를 통해서 구현하려고 함.


2. 튜링완전언어


스마트 컨트렉트, 분선애플리케이션을 작성 가능, 소유권에 대한 규칙, 트랜잭션포맷, 상태변환함수등을 생성 가능.


3. 스마트컨트랙트


어떤 가치를 가지고 있고 특정 조건을 만족해야함 그 가치를 얻을 수 있도록 함.

튜링완전, 가치인지, 블록체인인지, 상태등의 개념이 포함된다.


4. 이더리움 어카운트


이더리움상태를 가지고 있다.


- 20바이트주소

- 상태변환

- nonce

- 잔고(ETH) : eth는 트랜잭션수수료를 지불하는데 사용된다.

- 계약코드(존재시)

- 저장공간


외부소유어카운트 : 개인키로 통제된다. 메세지전송시 트랜잭션을 만들고 서명한다.

컨트랙트어카운트 : 컨트랙트키로 통제된다. 메세지수신시 코드활성화하여 읽거나 저정하고, 메세지 전송 또는 컨트랙트들을 생성한다.


컨트랙트 : 이더리움 실행환경안에서 살아있는 일종의 자율에이전트로 메세지나 트랜잭션이 도착하면 특정코드를 실행하고 이더잔고와 영속적인 변수들을 추적하기 위해 저장소를 통제한다.


5. 트랜잭션


외부소유어카운트가 보내고자 하는 메세지를 가지고 있는 서명된 데이터 패키지를 말한다.


- 메세지 수신처

- 발신처를 확인할 수 있는 서명

- 발신처가 수신처로 보내는 이더의 양

- 추가 옵션 데이터 필드

- STARTGAS 값 : 트랜잭션 실행 허용 최대 계산 단계수

- GASPRICE 값 : 매 계산단계마다 발신처가 지불하는 수수료


데이터필드는 도메인등록서비스를 예를 들면 등록하고자 하는 도메인과 IP주소가 될것이다. 따라서 컨트렉트는 데이터로부터 이 값들을 읽어서 저장소 내 적당한 위치에 저장한다.


STARTGAS와 GASPRICE는 DDoS공격을 막기 위한 중요한 역할을 한다. 계산량, 네트웍 밴드위스, 저장소등에 비례하여 비용을 지불하게 하여 악의적인 공격을 막는다. 


6. 메세지


트랜잭션과 별개로 컨트랙트가 다른 컨트랙트에게 메세지를 전달할 수 있다. 이 메세지는 별도로 저장할 필요가 없는 실행환경에서만 존재하는 가상의 오브젝트이다.


- (암묵적인) 메세지 발신처

- 메세지 수신처

- 이더

- 추가 옵션 데이터 필드

- STARTGAS 값


임의 컨트랙트가 실행중에 CALL opcode를 만나게 되면 메세지를 생성하고 트랜잭션과 동일하게 해당 코드를 실행하는 수신자 어카운트에 도달하게 된다. 따라서 컨트랙트는 외부 실행자를 통하지 않고 동일하게 다른 컨트랙트와 관계를 맺을 수 있다.



Posted by 삼스
블록체인2017. 7. 4. 10:44


중앙서버 없이 분산시스템인 P2P기반의 비가역적 데이터베이스라고 정의할 수 있다.


P2P상의 노드(클라이언트)들은 블록을 생성하고 검증한다.


일정한 규칙에 따라 데이터를 담은 블록을 경쟁을 통해서 만들어낸다. 이렇게 만들어진 블록데이터는 되돌릴수 없게 된다.


P2P기반으로 중앙화 되어 있지 않기 때문에 중앙만 공격하면 뚤리게 되는 보안상의 취약성이 원천적으로 제거된다. 모든 참여자가 사용자들로만 이루어지게 되며 비가역적인데다 모든 사용자들이 데이터를 검증하기 때문에 조작이나 통제가 불가능한 시스템이 갖추어졌다.


최초에 생성된 블록을 탄생블록(Genesis Block)이라 하며 이 후 경쟁을 통해서 블록이 계속 생겨나게 된다. 경쟁에서 최초로 블록은 만들어낸 사용자의 블럭이 블록체인에 등록되고 나머지는 연결되지 못한다. 이긴 블록들로 이루어진 체인을 주체인이라하고 주체인에 들지 못한 블록을 탈락블록이라 칭한다. 주체인에 포함된 블록만이 유효한것으로 인정된다.


각 블록은 해시를 가지고 있고 이전블록의 개인키로 사인이 되어 있다. 따라서 이전블럭의 공개키가 있어야만 복호화가 가능하다. 이로써 해당 블록의 히스토리를 역산해나갈수 있다.


각 노드들이 하는 일은 작업증명 과 해시값 추적을 통한 블록을 생성하는 일이다.

해시값을 먼저 찾은 노드는 자신이 생성한 블록을 먼저 공표할 수 있다. 뒤늦게 하는 공표는 주체인이 될 수 었기에 탈락블록이 된다.

해시값을 빨리 찾기 위한 조건은 연산능력이 탁월한 하드웨어, 전기세, 관리비들이 되겠다. 따라서 돈이 많으면 더 많은 확보가 가능하다.


Posted by 삼스