블록체인2017. 9. 1. 11:14


https://medium.com/@codeAMT/how-to-launch-swarm-for-dapp-testing-8003e55380e2


이더리움은 최근에 web3.0 기반 기술의 에코시스템에 포함되기 위해 쭈욱 개발되어져 왔다. 브라우저내장의 Mist지갑, dapp messaging package인 Whisper, 탈중앙화된 데이터스토리지인 Swarm등이 있다.


다음은 web3.0에서 dapp개발을 위한 거룩한 삼위일체를 보여준다.



Swarm이 무엇이고 어떻게 동작하는가?


Peer to peer, low latency, 네트웍 데이터 공유를 가능하게 하는 서버같은 노드이고  해시주소로 최종사용자가 리소스에 접근가능하게 해준다.

실서버는 불필요.

파일공유나 데이터자장소를 투명하고 비용효율이 좋은 서비스를 만들 수 있는 잠재력을 가지고 있다. 분산은 피어간의 연결을 통해서 중단없는 서비스가 가능하다.

최종사용자는 새로운 리소스를 배포하는데 비용을 지불한다.

개발자는 이 경로에 게시하는 데이터에 대한 민감도를 고려해야 한다. 데이터는 해시주소에 저장되면 삭제할 수 없다.

비트코인처럼 테스트넷에서 테스트가 가능하며 테스트넷에 swarm을 적재하고 web 3.0dapp으로 게이트웨이를 사용하는 법을 안내할것이다.


TestNet에 Swarm처음 적재하기


1 : go-ethereum 설치


go언어를 설치해야 한다. 다음 링크를 참조하라.


* Go workspace 폴더 생성

* $GOPATH환경변수에 등록

* .bash_profile에 추가

* 작업폴더 생성 (src/github.com/ethereum)

* 작업폴더로 이동 하여 go-ethereum clone

* cd go-ethereum, grab 프로젝트 의존성




2. geth 와 swarm 패키지 컴파일


geth는 노드를 적재하기 위해 swarm은 파일공유를 하기 위해 컴파일 한다.


* run "go install -v ./cmd/geth"

* run "go install -v ./cmd/swarm"



백그라운드에서 go isntall명령이 geth와 swarm 바이너리를 만든다. 



3. 데이터 폴더와 Swarm TestNet계정 만들기


* 폴더를 만들고 testnet 모드로 노드를 시작

* 계정 생성

* 비밀번호 입력



계정이 생성되면 새로 생성된 계정주소를 반환한다.


4. geth node 적재


여기서 geth에 fast 옵션을 추가로 시작하였으며 이는 fast 동기화 다운로드를 수행한다는 뜻이다.



잠시후에 테스트넷 폴더가 데이터 폴더에 자동으로 생성된것을 알 수 있다. 


5. Swarm testnet 시작

새로운 터미널탭에서 swarm을 시작한다. 3가지 옵션이 필요하다

* bzzaccount : geth 계정 주소
* 데이터폴더 경로
* ethapi(테스트넷 폴더내의 geth.ipc로 불리는 파일의 경로)

실행후 계정 비밀번호를 입력한다. 



p2p 네트웍이기 때문에 피러들과 연결되려면 조금 기다려야 한다. 연결이 완료되면 아래와 같은 화면을 볼수 있다.






이제 데이터 폴더에 블랙체인을 모두 다운받아야 한다. 그러면 브라우져를 실행할 준비가 완료된다.


6. 로컬호스트에 억세스하기 위해 브라우저 실행


브라우저를 열고 8500포트에 접속하면 다음화면을 볼수 있다.




이제 서버가 동작하고 있다.


"bzz:/"프록시로 해시나 도메인주소를 입력하면 웹컨텐츠를 볼수 있다.




web3.0브라우저를 사용하면 bzz 스키마로 바로 접근이 가능하다.


7. Web 3.0 서핑하기


swarm 개발자들의 샘플 dapp을 방문해 보아라. http://swarm-gateways.net/bzz:/photoalbum.eth/


로컬에서 swarm홈페이지의 dapp같은 것을 볼 수 있다.



이 앱으로 사용자가 새로 게시하거나 재배치하고 삭제할 수 있다. 오픈소스 앨범이고 개인적 용도로 공유할 수도 있다.


dapp을 수정하게 되면 해시값도 변경된다. swarm은 모든 애플리케이션이 유일한 해시값을 갖기 때문이다.


앱위에 마우스를 갖다 대면 팝업으로 뜨는 메뉴가 있다. dapp의 삭제, 게시, put, get제어가 가능하다.

따라서 이미지를 아래로 이동시키면 아래처럼 새로운  dapp 주소가 생성된다.




애플리케이션 공유하기


일반 웹에서 dapp을 보려면 일반게이트웨이를 통해서 해당 고유 해시를 보아야 한다.


1. 해시 복사

2. 새브라우저 열기

3. 게이트웨이에 bzz 프로토콜 추가

4. 붙여넣기



내 노드에서 시험하기


홈스테드 버전의 Mist지갑에 Swarm이 포함되어 있으며 지갑앱을 통해서 테스트가 가능하다.


Mist지갑 > 계정 > Upload to Swarm을 선택 후 이미지 파일을 선택한다.



로컬호스트 주소에 bzz://로 생성된 해시코드를 주소로 집너 넣는다.

그러면 아래와 같이 내가 업로드한 이미지 파일을 볼 수 있다.







Posted by 삼스
블록체인2017. 7. 11. 15:06


코인 사용하기


토큰을 배포하면 토큰 목록에 추가되고 총 잔액이 계정에 표시된다. 토큰을 보내려면 보내기 탭으로 이동하여 토큰이 포함 된 계정을 선택하라. 계정에있는 토큰은 이더 아래에 나열된다. 그들을 선택하고 보내려는 토큰의 양을 입력하라.

다른 사람의 토큰을 추가하려면 계약 탭으로 이동하여 토큰보기를 클릭하라. 예를 들어, 감시 목록에 Unicorn (🦄) 토큰을 추가하려면 주소 0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7을 추가하기 만하면 나머지 정보가 자동으로로드된다. 확인을 클릭하면 토큰이 추가된다.

유니콘 토큰은 Ethereum Foundation이 관리하는 주소 0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359에 기부 한 사람들을 위해 독점적으로 만들어지는 기념품이다. 이에 대해 더 알고 싶다면 여기를 읽어보아라.


이더리움으로 토큰을 발행하는 방법을 배웠다. 원하는 토큰을 만들 수 있다. 하지만 토큰으로 무엇을 할 수 있을까? 회사의 주식이 가능합니다. 또한 중앙위원회를 사용하여 인플레이션을 제어하기 위해 새로운 동전을 ㅂ라행 할 시기에 투표할 수 있다. 또한 crowdsale을 통해 어떤문제를 위해 돈을 모으기 위해 사용가능 하다. 다음엔 무엇을 만들래?

Posted by 삼스
블록체인2017. 7. 11. 14:54

전체 코드


pragma solidity ^0.4.2;

contract owned {

    address public owner;


    function owned() {

        owner = msg.sender;

    }


    modifier onlyOwner {

        if (msg.sender != owner) throw;

        _;

    }


    function transferOwnership(address newOwner) onlyOwner {

        owner = newOwner;

    }

}


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


contract token {

    /* 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);


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

    function token(

        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 (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 (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;

    }


    /* This unnamed function is called whenever someone tries to send ether to it */

    function () {

        throw;     // Prevents accidental sending of ether

    }

}


contract MyAdvancedToken is owned, token {


    uint256 public sellPrice;

    uint256 public buyPrice;


    mapping (address => bool) public frozenAccount;


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

    event FrozenFunds(address target, bool frozen);


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

    function MyAdvancedToken(

        uint256 initialSupply,

        string tokenName,

        uint8 decimalUnits,

        string tokenSymbol

    ) token (initialSupply, tokenName, decimalUnits, tokenSymbol) {}


    /* 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

        if (frozenAccount[msg.sender]) throw;                // Check if frozen

        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

    }



    /* A contract attempts to get the coins */

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

        if (frozenAccount[_from]) throw;                        // Check if frozen            

        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 mintToken(address target, uint256 mintedAmount) onlyOwner {

        balanceOf[target] += mintedAmount;

        totalSupply += mintedAmount;

        Transfer(0, this, mintedAmount);

        Transfer(this, target, mintedAmount);

    }


    function freezeAccount(address target, bool freeze) onlyOwner {

        frozenAccount[target] = freeze;

        FrozenFunds(target, freeze);

    }


    function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {

        sellPrice = newSellPrice;

        buyPrice = newBuyPrice;

    }


    function buy() payable {

        uint amount = msg.value / buyPrice;                // calculates the amount

        if (balanceOf[this] < amount) throw;               // checks if it has enough to sell

        balanceOf[msg.sender] += amount;                   // adds the amount to buyer's balance

        balanceOf[this] -= amount;                         // subtracts amount from seller's balance

        Transfer(this, msg.sender, amount);                // execute an event reflecting the change

    }


    function sell(uint256 amount) {

        if (balanceOf[msg.sender] < amount ) throw;        // checks if the sender has enough to sell

        balanceOf[this] += amount;                         // adds the amount to owner's balance

        balanceOf[msg.sender] -= amount;                   // subtracts the amount from seller's balance

        if (!msg.sender.send(amount * sellPrice)) {        // sends ether to the seller. It's important

            throw;                                         // to do this last to avoid recursion attacks

        } else {

            Transfer(msg.sender, this, amount);            // executes an event reflecting on the change

        }               

    }

}


배포


아래로 스크롤하면 배포에 드는 예상 비용이 표시된다. 원한다면 작은 수수료를 설정하도록 슬라이더를 변경할 수 있지만 가격이 평균 시장 가격보다 너무 낮으면 거래가 성사되는데 더 오래 걸릴 수 있다. 배포를 클릭하고 암호를 입력한다. 몇 초 후에 대시 보드로 리디렉션되고 최신 트랜잭션에 "계약 생성"이라고 표시된다. 누군가가 거래를 선택하기까지 잠깐 기다리면 얼마나 많은 다른 노드가 거래를보고 확인했는지 나타내는 푸른 색 직사각형이 보일 것이다. 확인 사항이 많을수록 코드가 배포되었음을 확신 할 수 있다. 



Admin 페이지 링크를 클릭하면 새로 만든 통화로 원하는 모든 것을 할 수있는 세계에서 가장 간단한 중앙 은행 대시 보드를 이용할 수 있다.

계약서 읽기 아래 왼쪽에는 무료로 계약 정보를 읽을 수있는 모든 옵션과 기능이 있다. 토큰에 소유자가 있으면 여기에 주소가 표시된다. 해당 주소를 복사하여 잔액에 붙여 넣으면 모든 계정의 잔액이 표시된다 (잔액은 토큰이있는 계정 페이지에도 자동으로 표시됨).

오른쪽 계약서에 쓰기에서 어떤 방식으로든 블록 체인을 변경하거나 변경할 수있는 모든 기능을 볼 수 있다. 이것들은 가스를 소비 할 것이다. 새로운 동전을 만들 수있는 계약을 만든 경우 "민트 토큰"이라는 기능이 있어야한다. 그것을 선택한다.



새 통화가 생성 될 주소를 선택한 다음 금액을 입력한다 (소숫점이 2로 설정된 경우 금액 뒤에 2 개의 숫자를 추가하여 정확한 수량을 생성한다). 선택에서 소유자로 설정된 계정을 실행하고 이더 금액을 0으로두고 실행을 누른다.

몇 가지 확인 후 수취인 잔액은 새로운 금액을 반영하도록 업데이트된다. 그러나 수령인 지갑에 자동으로 표시되지 않을 수 있다. 사용자 정의 토큰을 인식하려면 지갑을 수동으로 감시 목록에 추가해야 한다. 토큰 주소를 복사한다 (관리자 페이지에서 사본 주소를 누르면된다). 아직 계약 탭으로 이동하지 않았다면 시계 토큰을 누른 다음 주소를 추가한다. 표시되는 이름, 기호 및 십진수는 최종 사용자가 사용자 정의 할 수 있다. 특히 비슷한 (또는 동일한) 이름을 가진 다른 토큰이있는 경우에 유용합니다. 기본 아이콘은 변경 가능하지 않으므로 토큰을 보내고받을 때 주의해야 한다. 토큰을 모방하지 않으면 실제 거래를 처리 할 수 있습니다.



Posted by 삼스
블록체인2017. 7. 7. 17:49


토큰 기능 개선


암호화토큰은 코드를 만지지도 않고 바로 만들어 배포할 수 있다. 하지만 진짜 마술은 커스터마이징하면서 발생한다. 이번 장에서는 토큰에 추가 할 수있는 함수에 대한 제안을 제공하여 사용자의 필요에 더 적합하게 만든다.


중앙화된 관리자


dapp이 기본적으로 분산되어 있지만 원한다면 중앙화된 관리자를 가질수 없다는것을 의미하지는 않는다. 중앙에서 어떤 제약조건을 강제하고 싶을 수 있다. 이런 기능을 추가할 수 있으며 시작시에 추가할 수 있다 이는 모든 토큰 소유자는 게임을 소유하기로 결정하기전에 게임의 규칙을 정확하게 알 수 있다.


그러려면 화폐에 대한 중안컨트롤러가 필요하다. 이는 단순한 계정이 될수 있지만 또 한 컨트랙트로 가능하며 토큰을 생성하는데 이 컨트랙트에 따라서 결정이 되게 된다. 투표권을 부여할 수 있는 민주적단체이거나 토큰 주인에게 제한적인 능력만을 부여 할 수 있다.



contract owned {

    address public owner;


    function owned() {

        owner = msg.sender;

    }


    modifier onlyOwner {

        if (msg.sender != owner) throw;

        _;

    }


    function transferOwnership(address newOwner) onlyOwner {

        owner = newOwner;

    }

}


이것은 소유할 수 있는 계약에 대한 아주 기본적인 코드이가. 다음 단계로 컨트렉트에 추가한다.


contract MyToken is owned {

    /* the rest of the contract as usual */


이는 MyToken의 내부 어디에서든 owner와 modifier onlyOwner에 접근이 가능하다는 것을 의미한다. transferOwnership이라는 함수를 가지고 있다. 이 정보가 아주 중요하기 때문에 컨트랙트 시작시 셋업할 수 있다.


function MyToken(

    uint256 initialSupply,

    string tokenName,

    uint8 decimalUnits,

    string tokenSymbol,

    address centralMinter

    ) {

    if(centralMinter != 0 ) owner = centralMinter;


CENTERAL MINT


회전되고 있는 동전의 양이 바뀌길 원한다고 가정하자. 이것은 실제로 금괴인증서나 정부통화같은 블록체인이 아닌 자산(off blockchain asset)를 나타내며 가상 재고가 실제 재고를 반영하도록 하려는 경우이다.이는 통화보유자가 토큰 가격을 통제하기를 원하고 회전되고 있는 통화를 더 발행하거나 제거하려는 경우도 해당된다.


먼저 해야할것은 totalSuplly를 추가하고 초기화하는것이다.


contract MyToken {

    uint256 public totalSupply;


    function MyToken(...) {

        totalSupply = initialSupply;

        ...

    }

    ...

}


이제 새함수를 추가하여 소유자가 새로운 토큰을 만들수 있게 한다.


function mintToken(address target, uint256 mintedAmount) onlyOwner {

    balanceOf[target] += mintedAmount;

    totalSupply += mintedAmount;

    Transfer(0, owner, mintedAmount);

    Transfer(owner, target, mintedAmount);

}


함수명 뒤에 onlyOwner를 주의깊게 봐야한다. 이는 앞서 정의한 mofifier onlyOwner에서 상속되어 컴파일되어 재작성될것이라는것을 의미한다. 이 함수의 코드는 mofifier함수의 밑줄 부분에 삽입될것이다. 이는 이 함수가 해당 계정에 의해서만 호출되고 owner로 셋팅될것을 의미한다. 이 코드만 추가하면 더 많은 코인을 생성할 수 있다.


자산의 동결


토큰의 사용유형에 따라 사용할 수 있는 사람과 할수 없는 사람에 대한 규칙적인 제한이 필요할 수 있다. 그러려면 자산을 동결하거나 해재하는 파라메터를 컨트랙트에 추가해야 한다.


아래 변수와 함수를 아무데나 컨트랙트내에 추가한다. 아무데나 가능하지만 다른 이벤트나 매핑과 함께 배치하는게 좋다.


mapping (address => bool) public frozenAccount;

event FrozenFunds(address target, bool frozen);


function freezeAccount(address target, bool freeze) onlyOwner {

    frozenAccount[target] = freeze;

    FrozenFunds(target, freeze);

}


이 코드로 기본적으로 미동결상태인 모든 계좌를 Freeze Account를 호출함으로써 동결할 수 있다. 불행히도 동결은 아무런 효과가 없다. 왜냐하면 transfer함수에 아무것도 추가하지 않았기 때문에, 그래서 다음과 같이 해야 한다.


function transfer(address _to, uint256 _value) {

    if (frozenAccount[msg.sender]) throw;


이제 동결된 계좌는 자금은 있지만 송금은 할  수 없다. 디폴트는 미동결계좌이나 원한다면 화이트리스트를 관리하면서 원할 때 계좌를 동결할 수 있다. frozenAccount를 approvedAccount로 변경하여 적용이 가능하다.


if (!approvedAccount[msg.sender]) throw;


자동 구매 및 판매


지금까지 토큰을 평가하기 위해 유틸리티와 신뢰에 의존했다. 하지만 원한다면 자동으로 시장의 가치를 기준으로 구입하는 펀드를 만들어 토큰의 가치를 이더(또는 다른 토큰)로 뒷받침 할 수 있다.


먼저 구매와 판매가격을 셋팅한다.


uint256 public sellPrice;

uint256 public buyPrice;


function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {

    sellPrice = newSellPrice;

    buyPrice = newBuyPrice;

}


이것은 가격에 접근가능하게 하며 자주 변하지 않는다. 이를 변경하려면 트랜잭션을 싱행하면서 이더를 소비하게 되기 때문이다. 변동가격을 일정하게 유지하려면 표준데이터피드를 참고하라.


다음은 구매와 판매함수를 작성한다.


// 살때

// msg.sender => 구매자

function buy() payable returns (uint amount){

    amount = msg.value / buyPrice;                     // msg.value는 구매금액(eth), 구매금액을 토큰가격으로 나눠서 토큰개수 계산

    if (balanceOf[this] < amount) throw;               // 현재 토큰잔액 확인

    balanceOf[msg.sender] += amount;                   // 구매자 토큰개수 추가

    balanceOf[this] -= amount;                         // 판매자 토큰개수 차감

    Transfer(this, msg.sender, amount);                // 전송 수행

    return amount;                                     // 토큰개수 반환

}


// 팔때

// msg.sender => 판매자

function sell(uint amount) returns (uint revenue){

    if (balanceOf[msg.sender] < amount ) throw;   // 판매자 토큰 잔액 확인

    balanceOf[this] += amount;                              // 구매자 토큰잔액 추가

    balanceOf[msg.sender] -= amount;                   // 판매자 토큰 잔액 차감 subtracts the amount from seller's balance

    revenue = amount * sellPrice;                // 판매금액 계산(eth)

    if (!msg.sender.send(revenue)) {                   // 판매자에게 이더 전송, 아주 중요함

        throw;                                         // to do this last to prevent recursion attacks

    } else {

        Transfer(msg.sender, this, amount);             // 전송 수행

        return revenue;                                 // 판매금액 반환

    }

}


이게 새로운 토큰을 생성하지 않고 컨트렉트 주체의 잔액을 변경한다는것을 주의깊게 보아야 한다. 컨트랙트는 토큰과 이더 모두 그리고 컨트랙트 소유자를 보유할 수 있으나 가격을 설정하거나 유효한경우 일부 토큰을 생성한다. 이는 은행의 토큰이나 이더를 건드릴수는 없다. 이 컨트랙트에서 펀드를 이동시킬수 있는 유일한 방법은 구매나 판매을 하는것 뿐이다.


가치를 구매 및 판매하는것은 이더내에서 설정되지 않고 유로나 달라의 cent나 비트코인의 satoshi같은 단위인 wei가 있다. 1 이더는 1000000000000000000 wei(10경)이다. 따라서 이더로 토큰을 설정할때 18개의 0을 넣어야 한다. 무쟈게 많다. 10경이니..


컨트랙트를 생성할 때 시장에있는 모든 토큰을 다시 구매할 수 있도록 충분한 양의 이더를 보내야 한다.그렇지 않으면 컨트랙트가 파산하여 사용자가 토큰을 판매 할 수 없게 된니다.


위 샘플에서는 단일 중앙구매자와 판매자간의 컨트랙트를 설명했지만 좀더 흥미롭게 다른 사람이 다른 가격을 입찰하거나 외부에서 가격을 직접로드할 수 있습니다.


자동리필


이더리움에서 트랜잭셕이 일어날때마다 채굴자에게 일정비율의 요금을 지불하게 되는데 이 값은 컨트랙트에서 계산되어진다. 순간적으로 수수료는 이더로만 지불되므로 토큰의 모든 사용자는 이더를 필요로 한다. 소유자가 필요한 비용이 지불할 수 있을 때 까지 수수료보다 적은 잔액을 가진 계좌의 토큰은 정지(stick)된다. 하지만 어떤 경우에는 유저가 이더리움, 블록체인 또는 이더리움을 어떻게 얻을 수 있는지 몰라도 되기를 원할 수 있다. 이 경우 한가지 가능한 접근방법은 잔액이 너무 적게되면 자동으로 채워질 수 있게 하는것이다.


이렇게 하기 위해서는 먼저 임계치값을 변수로 생성해야 하며 변경할 수 있게 해야 한다. 5 finney(0.005 ether)로 설정해보자


uint minBalanceForAccounts;


function setMinBalance(uint minimumBalanceInFinney) onlyOwner {

     minBalanceForAccounts = minimumBalanceInFinney * 1 finney;

}


그리고 transfer함수를 수정한다.


/* Send coins */

function transfer(address _to, uint256 _value) {

    ...

    if(msg.sender.balance<minBalanceForAccounts)

        sell((minBalanceForAccounts-msg.sender.balance)/sellPrice);

}


송금인이 수취인에게 수수료를 지불할 수 있도록 변경할수도 있다.


/* Send coins */

function transfer(address _to, uint256 _value) {

    ...

    if(_to.balance<minBalanceForAccounts)

        _to.send(sell((minBalanceForAccounts-_to.balance)/sellPrice));

}


이러면 토큰을 받는 계좌가 수수료를 지불하는데 필요한 이더보다 적게 수수료를 지불하지 않습니다.


작업검증


수학공식을 코인과 엮는 몇가지 방안이 있다. 가장 간단한 방법은 이더로 "병합된 광산(채굴)"로 만드는것이다. 다시 말해 이더리움에서 블록을 발견한 사람은 누구나 그 불록에 대한 보상 기능을 호출하면 코인에서 보상을 받을것이다. 블록을 찾은 광부를 지칭하는 coinbase 키워드로 이를 수행할 수 있다.


function giveBlockReward() {

    balanceOf[block.coinbase] += 1;

}


이것은 또한 수식을 추가할 수 있는데 누구든 이를 수행하면 보상에서 승리할 수 있다. 다음 예에서 당신은 포인트를 얻는 현재 도전의 큐빅루트를 계산해야 하고 다음 도전을 설정할 수 있는 권한을 얻는다.


uint currentChallenge = 1; // Can you figure out the cubic root of this number?


function rewardMathGeniuses(uint answerToCurrentReward, uint nextChallenge) {

    if (answerToCurrentReward**3 != currentChallenge) throw; // If answer is wrong do not continue

    balanceOf[msg.sender] += 1;         // Reward the player

    currentChallenge = nextChallenge;   // Set the next challenge

}


물론 계산을 누군가의 머리로 하는것은 많이 어렵지만 계산기는 아주 쉽다.그래서 이 게임은 컴퓨터로는 금방 끝난다. 또한 마지막 승자가 다음 도전을 고를수 있기 때문에 다른 플레이어에게는 공정하지 않다. 인간에게는 쉽지만 기게로는 매우 어렵지만 스크립트로 코딩하는것을 매우 어렵다. 대신에 더 공정한 시스템은 기계가 할 수 있는것은 매우 어렵지만 기계가 검증하기가 그리 어렵지는 않다. 가장 적절한 후보는 도전자가 주어진 난이도보다 낮은 해시를 찾을때 까지 여러 숫자의 해시를 생성해야 하는 해시 도전을 만드는것이다.

이 프로세스는 1997년 Adam Back에 의해 hashcash로 처음 제안되었고 2008년에 satosi nakamoto의 비트코인에서 구현되었습니다. 이더리움은 보안모델을 위해 이러한 시스템을 사용하여 출시되었지만 작업증명보안모델에서 혼합된 모델(링크탭하여 더 알아보세요)로 이동하려고 계획하고 있습니다.

해싱을 코인의 랜덤발행형태로 하려는 경우 작업방행증명이 있는 자신의 이더기반 통화를 만들수 있다.


bytes32 public currentChallenge;                         // The coin starts with a challenge

uint public timeOfLastProof;                             // Variable to keep track of when rewards were given

uint public difficulty = 10**32;                         // Difficulty starts reasonably low


function proofOfWork(uint nonce){

    bytes8 n = bytes8(sha3(nonce, currentChallenge));    // Generate a random hash based on input

    if (n < bytes8(difficulty)) throw;                   // Check if it's under the difficulty


    uint timeSinceLastProof = (now - timeOfLastProof);  // Calculate time since last reward was given

    if (timeSinceLastProof <  5 seconds) throw;         // Rewards cannot be given too quickly

    balanceOf[msg.sender] += timeSinceLastProof / 60 seconds;  // The reward to the winner grows by the minute


    difficulty = difficulty * 10 minutes / timeSinceLastProof + 1;  // Adjusts the difficulty


    timeOfLastProof = now;                              // Reset the counter

    currentChallenge = sha3(nonce, currentChallenge, block.blockhash(block.number-1));  // Save a hash that will be used as the next proof

}


생성자함수도 변경해야 한다.


    timeOfLastProof = now;


컨트랙트가 온란인상태가 되면 "작업 증명"기능을 선택하고 nonce필드에 원하는 번호르 추가하여 실행해라. 확인 창이 "데이터를 실행할 수 없습니다"라는 빨간색 경고 메시지가 나타나면 거래가 진행될때까지 다른 번호를 선택하라. 이 프로세스는 임의적이다. 하나를 찾으면 마지막 보상이 주어지기 때문에 매 순간마다 1토큰을 받게되며 도전난이도는 보상당 평균 10분을 목표로 위아래로 조정된다.

보상을 제공하는 번호를 찾으려는 이 과정을 채굴이라고 부른다. 난이도가 올라가면 숫자를 찾기가 어려울 수 있지만 발견한것을 확인하는것은 항상 쉽다.



Posted by 삼스
블록체인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 삼스