반응형
solidity03_data_var

Solidity 03. Variables/Datatypes

변수를 어떻게 사용하는가?

  • 멤버 변수들은 Storage 변수. 상태 변수이다.
  • 파라미터들은 Memory 변수. 함수 리턴시 날라간다.
  • 파라미터에 Storage를 지정하면? 참조가 된다?

integer와 string을 get/set 하는 예제

pragma solidity >=0.4.0 <0.6.0;

contract SimpleStorage {
    uint storedData;
    string storedNm;

    function set(uint x) public {
        storedData = x;
    }

    function setNm(string memory x) public {
        storedNm = x;
    }

    function get() public view returns (uint) {
        return storedData;
    }

    function getNm() public view returns (string memory ) {
        return storedNm;
    }
}
  • 기본 자료형이 아닌 것은 저장소를 명시해 주어야 한다. string을 사용하는 부분에 memory 타입으로 명시함.

datatype

  • 기본형
    uint/int ; uint, int는 뒤에 256이 생략되어 있다. (u는 unsigned 의미)
    uint8~uint256 ; 여기서 숫자는 비트수를 의미. 1바이트부터 32바이트까지 있다.
    bool : true or false
    byte : uint8과 같다고 생각하면 된다.
    address : 20바이트 주소값
    address payable : address타입인데 멤버함수가 있다. transfer, send.
    address payable x = address(uint160(to));

enum State { Created, Locked, Inactive } ;
산술/비교/비트/논리 연산자는 C 와 같음. enum도 같다.

  • 참조형
    배열 : [] array
    구조체: struct
0xffff ; int16(-1)
0x42 ; bytes1(0x42)
0x0003 ; uint16(0x03)
0x48656c6c6f2c20776f726c6421 ; string("Hello, world!") (without null)

address의 멤버

  • balance ; 계정 주소에 있는 이더를 wei로 반환
  • transfer(uint amount) ; 계정 주소(받는 사람 주소)에 있는 amount 금액을 송금. to.transfer(_amount)
  • send(uint amount) returns (bool) ; 상동. 실패시 false 리턴. to_send(_amount)
  • call(…) returns (bool) : 상동, 실패시 false 리턴. 가스량 조절 가능. to.call.value(_amount).gas(1000000)() . 리턴값을 확인하여 false이면 revert()로 롤백한다.
  • delegatecall(…) returns (bool) : 다른 계약의 함수를 호출.
address x=0x123 ;
address myAddress = this ;
if (x.balance<10 && myAddress.balance>=10) x.transfer(10) ;
  • send : low-level의 transfer임. (실패시 롤백없음). 리턴값(true/false)을 반드시 확인.

고정크기 바이트 배열

bytes1/bytes2/bytes3/… bytes32 : bytes뒤에 숫자를 붙인다. 바이트수를 의미.
byte : bytes1과 같다.
멤버
length : 고정된 길이를 반환. 읽기 전용.
bytes32는 32바이트까지만 담을 수 있다.
ex)
bytes2 b = “bac”

동적 크기 바이트 배열

bytes : 임의 길이의 원시데이터.
string : UTF-8 인코딩 문자열. 임의의 길이. 거의 무제한.(2^256 * 256 비트)

  • 멤버로 length, push()가 있다.
  • 작은 따옴표나 큰 따옴표 상관없다.
    ex) bytes memory a = ‘aaaaaaaaaa’;
    a.length ;
    a.push(‘c’) ;
    a.push(“C”) ;
    a.push(“AB”) ; // error. byte[]라서 byte 하나만 push 가능.

문자열 리터럴

작은 따옴표, 큰 따옴표 둘 다 가능.
C랑 다르게 null terminated가 아니다. 보이는 문자 개수만큼만 메모리를 차지함.
\n, \xNN (16진수), \uNNNN (유니코드) 도 지원.

16진수 리터럴

hex"001122FF"
앞에 hex를 지정.

이중배열

uint [][5] : 주의할 점은 행과 열이 다른 언어와 반대임.
이것을 C로 보면 uint [5][] 이 된다.

  • 웃긴건 접근할 때는 C처럼 행, 열 순으로 접근한다.
  • 선언할 때랑 사용할 때랑 다르다니 문화충격이다.
uint[3][2] dArray ;
// row index는 0,1까지 가능. column index는 0,1,2까지 가능.
// C나 java로 치면 uint dArray[2][3] 으로 생각해야 함.
dArray[1][2] = 100 ;  // last element.

dArray[2][2] = 100 ; // error. 
dArray[0][3] = 100 ; // error. 
function f(uint len) public pure {
	uint[] memory a = new uint[](7) ;
	bytes memory b = new bytes(len) ;
	// a.length==7, b.length=len
	a[6]=8 ;
}
function f() public pure {
	g([uint(1), 2, 3]) ;
}
function g(uint[3] _data) pubilc pure {
}

[1,2,3] 은 uint8[3] memory 타입이다. array에 첫 번째 요소에 타입을 명시해 줄 수 있다.

  • 고정 크기 배열을 동적크기 배열에 할당할 수 없다.!
uint8[] memory x = [uint8(1),2,3] ;	// 에러
uint8[3] memory x = [uint8(1),2,3] ;	// 가능.

uint[] dArray ;
dArray.push(2) ;
dArray.push(3) ;
  • 삭제는 delete로 배열을 삭제한다.
  • 일반 변수에 delete를 하면 초기값(0)으로 할당된다.

자료구조

struct 지원

struct Voter {
uint w ;
bool v ;
address dele ;
uint vote ;
}

Enum Types

enum State { Created, Locked, Inactive }

Type Conversion

  • uint를 스트링으로 변환. 하나씩 바이트 단위로 ascii char로 변환한다.
function uintToString(uint v) constant returns (string str) {
        uint maxlength = 100;
        bytes memory reversed = new bytes(maxlength);
        uint i = 0;
        while (v != 0) {
            uint remainder = v % 10;
            v = v / 10;
            reversed[i++] = byte(48 + remainder);
        }
        bytes memory s = new bytes(i + 1);
        for (uint j = 0; j <= i; j++) {
            s[j] = reversed[i - j];
        }
        str = string(s);
}

function uint2str(uint i) internal pure returns (string)
{ 
	if (i == 0) return "0"; 
	uint j = i; 
	uint length; 
	while (j != 0){ length++; j /= 10; } 
	bytes memory bstr = new bytes(length); 
	uint k = length - 1; 
	while (i != 0){ bstr[k--] = byte(48 + i % 10); 
	i /= 10; 
	} 
	return string(bstr); 
}
  • 타입 캐스팅은 타입을 함수처럼 사용하여 파라미터로 받는다.
  • 32비트를 16비트로 타입 캐스팅시 하위 바이트(낮은 자리 값)만 가져온다.
  • 예를 들면. uint32 a= 0x12345678 ; 이것을 uint16 b = uint16(a) ; 이렇게 하면 하위 바이트인 0x5678을 가져온다.

Mapping

contract Mappings {
 struct User {
   string name ;
   string email ;
 }
 mapping(address => User) users ;
 function addUser(string memory _name, string memory _email) public {
   users[msg.sender].name = _name ;
   users[msg.sender].email = _email ;
 }
 function getUser() public returns (string memory, string memory) {
   return (users[msg.sender].name, users[msg.sender].email) ;
 }
}

이더리움 단위

wei ; 가장 작은 단위
1000 배씩 올라간다.
kwei, mwei, gwei, micro, milli, ether
kether, mether, gether, tether
위 단위를 코드에 그대로 사용한다.
즉, 1 이더는 10**18 wei

시간 단위

second, minute, hour, day, week, year

블록 및 거래 속성

  • block.blockhash(uint blockNumber) returns (bytes32) : 지정한 블록의 해시값을 리턴. (최근 256개 블록만 사용 가능)
  • block.coinbase ; address 채굴자 계정 주소
  • block.difficulty ; uint 현재 블록 난이도
  • block.gaslimit ; uint 현재 블록의 가스 제한량
  • block.number ; uint 현재 블록 번호
  • block.timestamp ; uint 현재 블록의 타임스탬프
  • msg.data ; bytes 호출 데이터
  • msg.gas ; 남은 가스양
  • msg.sender ; address 메시지를 보낸사람
  • msg.sig ; bytes4 calldata의 첫 4바이트로 함수 식별자
  • msg.value ; uint 메시지와 같이 보낸 wei
  • now ; block.timestamp와 같다. (현재 시간을 의미하는 값은 아니다. 현재시간과 대략 비슷)
  • tx.gasprice ; uint 거래의 가스가격
  • tx.origin ; 거래 발신자 주소. (sender.address와 같을 수도 다를 수도 있다.)
  • this ; 현재 계약
  • selfdestruct(address) ; 현재 계약을 파기해 지정한 주소로 금액을 보냄
  • suicide(address) ; 상동

예외 처리

  • assert(bool condition) ; 조건이 실패하면 에러를 발생시킨다. (보통 내부에러)
  • require(bool condition) ; 위와 같다. 입력값 체크시 사용. (보통 외부에러)
  • revert() ; 에러가 발생하면 롤백을 시킨다.

기타 연산

  • addmod(uint x, uint y, uint k) returns (uint) : (x+y)%k
  • mulmod(uint x, uint y, uint k) returns (uint) : (x*y)%k
  • keccak256( data ) returns (bytes32) : 이더리움 sha3 (KECCAK256) 해시
  • sha256
  • sha3 ; keccak256과 동일
  • ripecmd160(data) returns (bytes20)
  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) return (address) : 타원곡선암호서명에서 공개키와 연결된 주소를 리턴

할당

  • 복수 데이터를 할당 할 수 있다. 리턴도 복수개가 가능
    • (x,y) = f() ;
  • swap
    • (x,y) = (y,x) ;
  • 함수 파라미터를 이름대로 지정할 수 있다.
    • f(3, 2) 대신 f({value:2, key:3}) 이렇게 사용. (파라미터 이름)
    • new로 다른 계약을 만들 수 있다.

Author: crazyj7@gmail.com

'BlockChain' 카테고리의 다른 글

Solidity#2 HelloWorld  (0) 2019.12.06
Solidity 0.4 vs 0.5  (0) 2019.12.06
Windows Ethereum python module install error  (0) 2019.12.04
[ether02] 코인만들기  (0) 2019.11.10
[ether01] solidity 맛보기  (0) 2019.11.10
반응형
solidity02_helloworld

Solidity 02

  • solidity 버전 표시
pragma solidity ^0.4.25;    // 정확히 이 버전만 지원
pragma solidity >=0.4.0 <0.6.0;  // 지원 범위

  • 파일 import
import "filename";
import "filename" as symbolName ;
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;

github에 있는 소스도 사용할 수 있다.

  • 주석은 c 형식 사용. /**/ // 등
  • public 함수나 변수는 외부에 노출
  • 반대는 internal로 표시한다. 내부에서만 호출 가능.
  • 파리미터에 memory는 라이프사이클이 함수내.
  • 파리미터에 storage로 주면 참조 형식으로 값이 변할 수 있다.
  • 함수에 view를 주면 storage 변수에 읽기 접근만 가능하다. 이벤트 발생 안된다.
  • 함수에 pure를 주면 storage 변수에 접근이 안된다.
  • view, pure를 귀찮게 왜 쓰나? gas 비용 절감과 보안측면 이다.

구버전

pragma solidity ^0.4.25 ;
contract HelloWorld {
	string public greeting ;
	function HelloWorld(string _g) public {
		greeting = _g ;
	}
	function setGreeting(string _g) public {
		greeting = _g ;
	}
	function say() public constant returns (string) {
		return greeting ;
	}
}

위는 0.4대 버전, 아래는 0.5대 버전이다. 문법이 약간 달라졌다.
- constructor가 클래스명에서 명시적으로 constructor로 변경.
- 파라미터, 리턴 변수앞에 저장소 지정을 명시적으로. (엄격해짐)
- constant가 없어짐. view로 대체.
  • public/internal 의 위치가 타입 뒤에 가는 것이 특징. (cpp, java와 다르다.)
  • 함수 리턴 타입을 지정하는 부분이 마지막에 들어간다.

신버전

pragma solidity >0.5.0;

contract HelloWorld {
	string public greeting ;
	
	constructor(string memory g) public {
		greeting = g;
	}
	
	function setGreeting(string memory g) public {
		greeting = g;
	}
	function say() public view returns (string memory) {
		return greeting ;
	}
}

image

  • deploy시 remix에서 펼쳐서 이름을 입력해줘야 인코딩에러가 안난다.
  • setGreeting시도에 펼쳐서 값을 넣어줘야 작동되었다.

Author: crazyj7@gmail.com

'BlockChain' 카테고리의 다른 글

Solidity#3 변수와 타입  (0) 2019.12.06
Solidity 0.4 vs 0.5  (0) 2019.12.06
Windows Ethereum python module install error  (0) 2019.12.04
[ether02] 코인만들기  (0) 2019.11.10
[ether01] solidity 맛보기  (0) 2019.11.10
반응형
solidity01_version

Solidity

Truffle

npm install -g truffle

작업 폴더를 만들고, 들어가서 프로젝트 초기화

truffle init

컴파일

solc source.sol --abi --bin (컴파일 변환 결과를 출력)

전체출력을 JSON 형태로 출력 (뒤에 받을 정보를 기록)
solc source.sol --combined-json abi, asm, bin

truffle을 사용한다면 truffle compile
배포는 truffle migrate로 한다.

문법

cpp처럼 ;으로 끝난다.
주석도 cpp처럼 한다. //, /* 등

pragma solidity >= 0.4.22 <0.6.0 ;
지원하는 버전을 표시한다. 0.4.22이상 0.6 미만.
특정 버전을 지칭할 경우는 ^0.4.22 이렇게 한다.

import ‘a.sol’;
다른 파일을 include 한다.
다른 사용 방식은
import * as cs from “filename”;
import “filename” as shortname;

contract 계약명 {
}
cpp 클래스처럼 정의한다.

mapping (address => uint) balances ;

버전 4와 5와 차이

solidity는 4, 5의 버전 차이가 심하다. 그것을 알아야 빌드를 할 수 있다.

  • Low-Level 함수 호출
    • callcode 삭제
    • staticcall 추가
    • 입력 파라미터가 bytes로 통일
    • 리턴값 지원
  • 지역변수 scope
    • C처럼 scope을 사용한다.
  • 배열에 pop 메소드 추가
  • 중요한 변화
  • address payable 타입 추가
    • 기존에 address 타입에 있던 send, transfer 메소드 삭제
    • 주소를 address payable 타입으로 변환해야 사용 가능하다.
    • send, transfer는 같은 기능인데 send는 low-level함수로 예외처리가 가능하다. transfer는 트랜잭션으로 처리.
    • 주소 타입을 payable로 변환하려면,
(0x...).transfer(1 ether); // 주소 상수 뒤에 바로 사용 OK
address to = 0x...;  
address(to).transfer(1 ether); // 에러!  
address(uint160(to)).transfer(1 ether); // 두번 변환은 OK
address payable x = address(uint160(to)); // 저장할 때도 두번 변환해야 OK
- msg.sender는 address payble 타입으로 변함
- msg.value는 payable, internal 함수에서만 접근 가능
- 다른 곳에서 사용하고 싶으면, 
function msgvalue() internal returns (uint256) {  
return msg.value;  
}
  • 변수 선언을 먼저 확실하게 해주어야 함. (C code)
  • 함수의 visibility (external/public/internal) 명시.
    • (v0.4는 default public)
  • 데이터로케이션(storage(상태변수참조)/memory(함수내)/calldata(함수파라미터)) 명시.
    • (v0.4는 default로 함수파라미터는 memory/calldata, 지역변수는 storage로 자동)
  • contract 타입을 address 타입으로 형변환하여 사용.
    • 0.4에서는 contract 타입이 기본적으로 address 타입과 혼용하여 사용가능했지만 transfer, balance 등을 사용하려면 명시적으로 형변환을 해줘야 한다.
  • Contract 타입간 형변환은 상속관계만 가능.
    • 상속관계가 아닌 contract로 변환하려면 형변환을 두 번하면 가능하다. A(address(b))
  • bytesX, uintX는 사이즈가 같은 경우만 형변환이 가능
    • bytes1 c=1 ;
    • bytes2 d = bytes2( c) ; // 0x0100 (오른쪽에 0이 추가)
    • bytes1 e = bytes1(d); // 0x01 (오른쪽을 제거)
    • bytes1 a = bytes1(0x100); // 0.5.0 부터는 error
    • bytes1 b = bytes1(uint8(0x100)); // 결과는 0
    • bytes1 c = bytes1(bytes2(0x100)); // 결과는 1
  • constant 키워드 삭제. 대신 view로 사용해야 함.
  • var 타입 삭제. 명시적 필요
  • suicide 함수 삭제. selfdestruct로 대체
  • sha3 함수 삭제. keccak256로 대체
  • throw 삭제. revert, require, assert 사용
  • contract명과 동일한 이름의 함수 construct 사용 불가. constructor키워드로 대체
  • 16진수표현은 0X는 삭제. 0x만 지원

Author: crazyj7@gmail.com

'BlockChain' 카테고리의 다른 글

Solidity#3 변수와 타입  (0) 2019.12.06
Solidity#2 HelloWorld  (0) 2019.12.06
Windows Ethereum python module install error  (0) 2019.12.04
[ether02] 코인만들기  (0) 2019.11.10
[ether01] solidity 맛보기  (0) 2019.11.10
반응형
windows_ethereum_pkg_error

Windows Ethereum python module install error

ethereum python 패키지를 윈도우에 설치할 때 환경에 따라 ethash에서 alloca.h 에러가 나는데 이것을 해결하기 위한 방법이 있다.

ethash

  • ethereum 패키지를 설치하는 과정에서 pyethash 모듈을 빌드하다가 에러가 발생한다. (alloca.h 에러)
  • ethhash 소스를 받아 코드를 수정하여 설치한다.
    git clone https://github.com/ethereum/ethash
1. src/libethash/mmap_win32.c
아래 코드 추가
#pragma comment(lib, "Shell32.lib")
2. src/python/core.c
#include <alloca.h> 를
#include <malloc.h> 로 바꾼다.

pip install .
으로 설치한다.
이후에 다시 ethereum을 pip로 설치시도하면 ethash를 자꾸 새로 설치하려고 하면서 동일한 에러가 나고 롤백이 된다.

ethereum

  • ethereum 패키지 소스를 받아 의존성 수정하여 설치한다.
    https://github.com/ethereum/pyethereum/releases/tag/v2.3.2
    소스를 받아서 풀고
    requirements.txt 에서 ethash 설치하는 부분을 삭제한다. (이미 패치한것을 위에서 설치했으므로 건너뛰도록 하는 것이다.)
    pip install .
    으로 설치한다.

Author: crazyj7@gmail.com

'BlockChain' 카테고리의 다른 글

Solidity#2 HelloWorld  (0) 2019.12.06
Solidity 0.4 vs 0.5  (0) 2019.12.06
[ether02] 코인만들기  (0) 2019.11.10
[ether01] solidity 맛보기  (0) 2019.11.10
이더리움개발 환경 준비  (1) 2019.11.10
반응형
Ether02coin

이더리움 개발 관련된 사항

알아야 될 것.

  • view 값을 가져오는 것은 가스 소모가 되지 않는다.
  • 코인 발행은 계약을 만든 사람만이 가능하다.
  • 코인 전송시에는 ID/PWD가 필요없다. 단지 이더리움 키쌍이 필요하다.

코인 만들기

image

pragma solidity ^0.5.0;

contract Coin {
    // The keyword "public" makes those variables
    // easily readable from outside.
    address public minter;
    mapping (address => uint) public balances;

    // Events allow light clients to react to
    // changes efficiently.
    event Sent(address from, address to, uint amount);

    // This is the constructor whose code is
    // run only when the contract is created.
    constructor() public {
        minter = msg.sender;
    }

    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        require(amount < 1e60);
        balances[receiver] += amount;
    }

    function send(address receiver, uint amount) public {
        require(amount <= balances[msg.sender], "Insufficient balance.");
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

가상 화폐(코인) 계약은 위와 같다. 정말 간단하다. 저렇게 간단한데, 코인 발행와 송금, 조회가 가능하다.

위 코드를 한 줄씩 읽어나가면 이렇게 된다.

코드 요약

  • 코인 발행자는 minter 라는 주소. (위 계약을 deploy할때 선택한 계정이 발행자가 된다. 중요하다.)
  • 주소마다 매핑된 balances가 있다. 즉, 주소로 코인 잔고 조회가 가능하다.
  • Sent는 이벤트로 송금이 완료되면 발생시키려고 만든 것이다. send 함수 마지막에 보면 호출한다.
  • 생성자(constructor)에서는 최초에 deploy시 사용자를 minter 발행자로 지정한다.
  • mint는 코인을 receiver로 amount 만큼 발행해 준다. (코인을 찍어서 준다.)
  • mint 조건을 보면 발행자만 mint를 사용할 수 있다. 금액 제한은 걸려있다. 수신자의 balances에 금액을 추가한다.
  • send는 코인 송금이다. 수신자 주소와 금액을 넣게 되어 있다.
  • send의 조건은 요청자(msg.sender)의 잔고 금액이 amount(송금금액)보다 커야 한다.
  • send에서는 송신자의 잔고에서 금액을 빼서 수신자의 잔고에 추가한다. 마지막에 송금완료 이벤트(Sent)를 발생시킨다.

저렇게 간단한 코드로 이 기능이 다 되는건가? 실제 테스트를 해 볼 수 있다.

테스트

  • deploy 계정 : 0xCA… (주소는 길기 때문에 여기서는 생략함)
  • balances에 위 계정을 입력하여 확인. 코인 잔고는 0으로 나옴.
    image
  • 나부터 코인을 찍어보자. 1000개.
    발행자만 가능하니 account는 0xCA… 로 설정하고,
    mint로 수신자 0xCA…, amount는 1000으로 해서 tranact 발생! 이후 다시 balances로 확인. 1000 코인이 발행되어 잘 들어왔다.
    image
  • 이제 다른 계정으로 발행해 보자. 계정을 0x147…로 바꿔서 mint를 해보니, 발행자 권한이 아니라 거부된다. 현재 잔고는 0으로 조회된다.
    image
    -원래 계정 0xCA에서 100원만 0x147한테 주자. 전송할때는 계정을 0xCA로 바꾼다음, send에 receiver와 amount를 입력하고 transact를 한다. balances조회하면 100 코인이 정상적으로 수신되었다. 0xCA로 balances를 조회하면 100코인이 줄어 900코인이 된 것을 확인할 수 있다.
    imageimage

Author: crazyj7@gmail.com

'BlockChain' 카테고리의 다른 글

Solidity#2 HelloWorld  (0) 2019.12.06
Solidity 0.4 vs 0.5  (0) 2019.12.06
Windows Ethereum python module install error  (0) 2019.12.04
[ether01] solidity 맛보기  (0) 2019.11.10
이더리움개발 환경 준비  (1) 2019.11.10
반응형
Ether01getset

smart contract / solidity 맛보기

온라인 solidity 개발 테스트 사이트에 접속한다.
https://remix.ethereum.org/

  • 코드를 작성한다.
    단순하게 integer값을 set하고 get하는 API 2개가 있다.
    image

  • 컴파일 한다.
    image

  • Deploy를 한다.
    image

  • 생성된 contract에서 각각의 메소드를 테스트해 볼 수 있다. 위에서는 100을 set하고 get으로 100이 나오는 것을 확인하였다.

Author: crazyj7@gmail.com

'BlockChain' 카테고리의 다른 글

Solidity#2 HelloWorld  (0) 2019.12.06
Solidity 0.4 vs 0.5  (0) 2019.12.06
Windows Ethereum python module install error  (0) 2019.12.04
[ether02] 코인만들기  (0) 2019.11.10
이더리움개발 환경 준비  (1) 2019.11.10
반응형
Ethe00_Setup

Etherium

이더리움 주소

  1. 개인키 생성
  2. 개인키에서 공개키 생성
  3. keccak256으로 공개키의 해시값 생성
  4. 해시값에서 뒤쪽 20바이트를 이더리움 주소로 사용한다.

계정

  1. 외부 소유계정 (EOA)
    다른 계정과 이더 송수신 및 컨트랙트에 트랜잭션 전송도 가능

  2. 컨트랙트 계정
    개인키가 없다. 스마트계약을 블록체인에 배포시 생성됨.
    다른 계정과 이더 송수신 가능.
    코드를 감고 있다.
    EOA나 다른 컨트랙트의 영향으로 트랜잭션을 발생시킬 수 있다.

지갑

이더리움 계정을 저장하고 관리
여러 계정을 관리하고 트랜잭션에 서명, 잔고 추적 등.

가스

스마트 계약 배포, 트랜잭션 실행등에 비용이 소모된다. 채굴자에게 이더를 지불해야한다. 트랜잭션에 얼마나 많은 단위연산이 포함되는지에 따라 비용이 결정됨. 연산의 단위를 가스라고 한다.

가스 가격

트랜잭션 생성자가 원하는 가스 가격을 정할 수 있다. 가스당 3wei 처럼 설정한다. 설정한 가스가격이 높을 수록 트랜잭션 처리 속도가 빠르다. 채굴자들이 높은 가격순으로 처리하기 때문.

가스 한도

트랜잭션 수행 최대 금액을 지정할 수 있다. 블록가스 한도와 다르다.

바이트 코드

스마트 계약 코드는 solidity 언어로 작성 EVM 바이트코드로 컴파일하여 EVM(이더리움 VM)에서 실행된다.

게스(Geth)/패리티(Parity) 클라이언트

geth는 이더리움재단에서 제공하는 공식 클라이언트. (Go로 개발). geth는 블록체인의 복사본을 최신 상태로 유지하고 위해 계속 통신한다. 블록을 채굴하고, 블록체인에 트랜잭션을 추가하고 검증하고 실행한다. API를 제공하기도 한다.

Web3JS

이더리움과 상호작용하는 javascript library.

가나슈. 메모리블록체인 개발테스트
https://www.trufflesuite.com/ganache

지갑관리
https://metamask.io/

메인넷 모니터링
https://etherscan.io/

https://www.etherstudy.net/geth.html

geth 다운로드 설치

https://geth.ethereum.org/downloads/

> geth --dev console
> eth.blockNumber

가나슈설치

Ganache
https://www.trufflesuite.com/ganache
또는
https://github.com/trufflesuite/ganache/releases

온라인 solidity 개발

https://remix.ethereum.org/#optimize=false&evmVersion=null

윈도우/linux solidity compiler

https://github.com/ethereum/solidity/releases

https://github.com/ethereum/solidity/releases/download/v0.5.12/solidity-windows.zip

가나슈가 개발 테스트시에는 빠르다. 추천! (단, 키스토어가 없다. 개인키 접근이 필요하면 복호화된 스트링을 복사해서 사용한다. UI에 열쇠모양 클릭.)

geth는 메모리를 많이 먹어서 느림. 대신 키스토어에 개인키 저장.

py-solc 모듈이 solidity 여러가지 버전에 대해서 잘 지원이 안되는 듯함. python내에서 source compile시도시 에러발생.
커맨드로 빌드하여 output을 파일에 생성하고, 그 파일을 파이썬에서 읽어서 설정하는 방식으로 해야 할 듯 하다.

solc 컴파일러는 버전에 따라 다르니 주의가 필요하다. ubuntu에서 구버전 solc 를 설치하려면?

우분투에서 apt-get 으로 설치하면 최신버전의 solc가 설치된다.
구버전을 사용하려면 위 사이트에서 구버전 soliidity-ubuntu-trusty-clang.zip을 받아서 설치한다.
실행시 libz3 에러가 발생?? 하면 아래와 같이 라이브러리를 설치해 준다. 그 외에도 여러가지 개발툴들을 설치한다.
apt-get -y install build-essential cmake g++ gcc git unzip
apt-get install libz3-dev
solc --version

강좌

https://www.ethereum.org/ko/developers/#%EC%8B%9C%EC%9E%91%ED%95%98%EB%A9%B4%EC%84%9C

https://solidity-kr.readthedocs.io/ko/latest/

https://winterj.me/smart-contract-with-python/


실습

  • geth 설치
sudo add-apt-respository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum
sudo apt install golang-go

확인
geth version
1.9.6-stable
go version
1.10.4
  • genesis 블록 설정
    genesis.json 파일 생성
$ cat genesis.json 
{
    "config": {
        "chainId": 16,
        "homesteadBlock": 0,
        "eip150Block": 0,
        "eip155Block": 0,
        "eip158Block": 0
        },
    "nonce": "0x0000000000654123",
    "timestamp": "0x00",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "extraData": "0x00",
    "gasLimit": "0x2db7579a600",
    "difficulty": "0x20",
    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "coinbase": "0x0000000000000000000000000000000000000000",
    "alloc": {}
}
  • difficulty 값은 채굴난이도로 낮을수록 빨리캔다. 위의 설정에서는 32가 된다.
  • geth 접속 후, eth.getBlock(0) 으로 확인할 수 있다.

초기화

현재 폴더에서 chain-data 폴더가 만들어진다. 데이터는 다 그곳에 저장됨. (geth, keystore 등)

geth init genesis.json --datadir chain-data
geth --datadir chain-data console

구동

접속을 쉽게하려면 rpc를 만들어 놓자. 아래와 같은 start.sh 스크립트를 만들어 저장해 두고 실행하자. 기본 포트는 8545인데, 여기서는 8485로 변경하였다. (주의!)
원격에서 계정 unlock을 허용하려면 --allow-insecure-unlock 옵션을 추가한다.

just running...
> geth --datadir ./chain-data console
> 최초 계정을 만들어 주어야 한다. 없으면 마이닝 모드 구동시 
> ether base가 없다고 에러가 남.
> 
> personal.newAccount('pass')
> 파라미터가 암호임. 반복하여 여러개의 계정을 임시로 만들어 본다.
> exit

start with options...
> cat start.sh
geth --rpc --rpcport 8485 --rpccorsdomain "*" --datadir "./chain-data" --port 30303 --nodiscover --rpcapi "db,eth,net,web3" --networkid 15 console
다른예) 위와 같이 실행해서 계정을 만든 다음 다음부터 아래처럼 실행
geth --rpc --rpcport 8545 --rpccorsdomain "*" --datadir "./chain-data" --port 30303 --nodiscover --mine --minerthreads 1 --allow-insecure-unlock --rpcapi "admin,personal,miner,db,eth,net,web3" --networkid 15 console
> ./start.sh
실행하면 메시지와 함께 콘솔이 뜬다.

내가 쓰는 구동 스크립트

> cat start3.sh
> geth --rpc --rpcport 8485 --rpcaddr "0.0.0.0" --rpccorsdomain "*" --datadir "./chain-data" --port 30303 \
--allow-insecure-unlock --mine --minerthreads 5 --identity private_chain \
--rpcapi "personal,miner,admin,db,eth,net,web3" --networkid 15 console
  • 윈도우에서 구동시 CPU100% 먹길래 "minerthreads 1"을 삭제해주니까 CPU가 정상적으로 떨어졌다. (참고) 또는 5나 10정도로 설정한다.
  • 구동해 놓으면 coinbase 계정으로 이더가 알아서 쌓이기 시작한다.
  • 마이닝이 안되면 miner.start(5) 이렇게 쓰레드를 지정해서 시작해 보자.
  • 그래도 마이닝이 계속 안되면, 작업관리자를 띄워서 메모리를 살펴보자. 메모리가 점점 증가하다가 1기가 좀 넘어서 기다리면 그 때 부터 CPU를 막 잡아먹기 시작하면서 마이닝을 할 것이다. 컴퓨터 성능에 따라 마이닝 하는데 시간이 좀 걸릴 수 있으니 기다려라.

로컬의 다른 쉘에서 geth 연결하기

geth 구동시 datadir에 설정된 경로에 geth.ipc라는 파일이 생기는데 그것으로 연결한다.

$ geth attach ./chain-data/geth.ipc
or
$ geth attach http://localhost:8485 (rpc:http://... 이렇게도 가능)
일부 작업이 제한될 수 있다. geth 시작시 옵션 설정이 필요.
  • 간단한 명령어
    eth.accounts : 계정 목록
    eth.blockNumber : 현재 채쿨된 블록 번호
    eth.hashrate
    eth.coinbase : 채굴 보상받을 계정. 디폴트는 eth.accounts[0]
    eth.mining : 마이닝 상태 on/off
    eth.getBalance(account) : 잔고
    eth.getTransaction(tx) : TX 정보
    miner.start() : 함수를 호출하여 마이닝 시작. 파라미터 1,2등 thread개수옵션
    miner.stop() : 마이닝 중지
    miner.setEtherbase() : 채굴 보상 계정 설정
    personal.newAccount(password) : 계정 생성
    personal.unlockAccount(account, password) : 계정 잠금 해제 (송금등 TX발생시 사전필요작업임)

  • 콘솔 연결 후 작업

personal.newAccount('pass')
personal.newAccount('pass')
personal.newAccount('pass')
personal.newAccount('pass')
위와 같이 테스트 계정들을 만들어 준다. 암호는 일단 다 pass로 하였음.
eth.mining : 마이닝 상태 확인. 
miner.start() : 마이닝이 멈춰있으면 마이닝을 시작한다.
잠시 후,첫번째 계정 잔고를확인한다.
eth.blockNumber
eth.getBalance( eth.accounts[0] ) : 0번 사용자 잔고 확인.

계정의 키는 데이터 루트 폴더(chain-data)안에 keystore 폴더에 계정별로 저장되어 있다.

  • 방화벽
    아까 rpc port로 설정했던 포트를 연다.
    ufw allow 8485

  • remix연결
    Env. web3provider
    http://172.16.100.88:8485
    원격 주소로는 접속이 안되는 것인지??? 계속 실패하였음.
    그래서 ssh로 포트 터널링하여 로컬로 연결함. (참고로 서버 ssh포트는 2222로 변경된 상태)
    접속 실패 원인을 찾아보니, rpcaddr을 안 줘서 그런 거였다.

ssh -L 8545:localhost:8485 blockchain@172.16.100.88
   -p 2222

위와 같이 로컬 8545를 원격의 8485로 연결해 놓고, remix에서 web3 provider에 주소를 로컬 주소를 주었다.
http://localhost:8545

  • smart contract deploy (배포)

계정 unlock을 해 주어야 한다 (unlock을 해주지 않으면 deploy나 set이 안된다.)
한 번 해두면 일정시간만 허용되는 것 같고, 시간이 지나면 자동으로 잠긴다.
personal.unlockAccount(eth.accounts[0])
위 커맨드가 작동하지 않는다면, geth 구동 스크립트에 옵션을 추가해 주어야 한다. –allow-insecure-unlock

remix로 contract를 deploy 시도 및 API 테스트를 했는데, 계속 가스 초과 에러가 발생하였다.
여러가지 시도 끝에, solidity compiler 버전을 0.4.23으로 낮추고 deploy를 하니 정상적으로 작동하였다. 계속 삽질을 했다는…
또 어디서는 genesis에 chainId가 0이면 그런 증상이 발생해서 42정도로 설정하여 해결했다는 얘기도 있다. 나의 경우는 chainId 설정을 하지 않았는데( config 필드가 empty) 위와 같이 해결하였음.
잘 안되면 남들하는 버전을 보고 연관되어 돌아가는 버전을 모두 맞춰 시도해보는 것도 좋다.

참고
원격 접속용 geth 구동

$ nohup geth --networkid 4649 --nodiscover --maxpeers 0 --datadir ~/Blockchain/data_testnet --mine --minerthreads 1 --rpc --rpcaddr "0.0.0.0" --rpcport 8545 --rpccorsdomain "*" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --unlock 0,1 --password ~/Blockchain/data_testnet/passwd --verbosity 6 2>> ~/Blockchain/data_testnet/geth.log &

rpc ; http-rpc 활성화
rpcaddr : 접속 가능한 주소 0.0.0.0는 any 허용. 127.0.0.1을 입력하면 로컬호스트에서만 접속 가능. 자신의 IP 주소를 주면 그 IP로 접근이 허용된다.
rpcapi : rpc에서 허용가능한 모듈을 지정. 여기에 miner, personal 등이 들어가면 사용 가능.
unlock : 계정 잠금 해제. geth에서 해당 계정에 암호없이 접근 가능.

많이 쓰는 명령어

잔고 조회
eth.getBalance(eth.accounts[0])

전송 : 10이더를 해당 사용자에게 전송
personal.unlockAccount(eth.accounts[0])
패스워드(pass) 입력

eth.sendTransaction( {from: eth.accounts[0], 
   to:"0xc8cafbebb42f522f040d5690b1b220c3a9aed8f1", 
   value:web3.toWei(10,"ether")})

eth.getBalance("0xc8cafbebb42f522f040d5690b1b220c3a9aed8f1")

마이닝
eth.mining  : 현재 마이닝 상태
miner.start(1)
miner.stop()

계정
eth.accounts : 계정 목록 조회
personal.newAccount('password') : 계정 생성
personal.unlockAccount(eth.accounts[0]) : 잠금해제

SubLimeText 에서 solidity code intelligence 지원

Ctrl+Shift+P를 누르고 install 을 치고 install package 실행
잠시 기다리면, 입력창이 뜸.
ethereum을 입력. Ethereum을 설치
다시 한 번 반복하고 이번엔 EthereumSoliditySnippets를 설치
다시 시작하면 적용 완료.

강좌

https://www.ethereum.org/ko/developers/#%EC%8B%9C%EC%9E%91%ED%95%98%EB%A9%B4%EC%84%9C

https://solidity-kr.readthedocs.io/ko/latest/

https://winterj.me/smart-contract-with-python/

Author: crazyj7@gmail.com

'BlockChain' 카테고리의 다른 글

Solidity#2 HelloWorld  (0) 2019.12.06
Solidity 0.4 vs 0.5  (0) 2019.12.06
Windows Ethereum python module install error  (0) 2019.12.04
[ether02] 코인만들기  (0) 2019.11.10
[ether01] solidity 맛보기  (0) 2019.11.10

+ Recent posts