Account 까지 만들었으므로 이제 Account 의 address 에 이더가 충만한 나만의 genesis 를 만들어서 간단한 Transfer Transaction 을 실행해보겠다.

참고로, 그간 golang 강좌 초반부를 쓰느라 신경을 좀 못쓴 동안에 1.2.0 버전이 바로 어제 릴리즈 되었다 (2016.02.29 에).
git pull 하고 submodule 을 update 한 후 1.2.0 버전으로 소스를 업데이트 하고서 다시 빌드를 하였으며, 이후 설명은 eth 1.2.0 기준으로 해 가도록 하겠다.

1.1.4 버전으로 Private Network 을 구성하고 나서 좀 당황스러운 점들이 있었다. 일단, Node 간에 RLPx handshake 가 auth 를 검증하는 동안 실패하는 상황이 발생하며 Handshake가 실패하면 아예 Miner 가 Mining 을 멈추는 상황으로 가는 버그이다. 이게 수정되었는지 궁굼한데 Release Note 를 보니 Mining 쪽 버그 픽스가 되었다고 하는데 1.2.0 에서 확인해봐야 하겠다.

그리고, Geth 의 Attach 가 eth 에 가능하게 되었다. geth 에는 --session-key 옵션이 없는데 이게 어떻게 동작할라나 모르겠다. 암튼 된다고 하니 이 두녀석들을 갖고 또 테스트 해봐야 하겠다. eth 1.2.0 과 geth 1.3.4 가 거의 동시에 릴리즈 되었으니, geth 설명할 때에도 최신버전 (아예 1.3.4의 코드네임이 Homestead 이다)으로 해야 하겠다.

[goodjoon Debug]$  ./eth --version
eth version 1.2.0
eth network protocol version: 63
Client database version: 12041
Build: Windows/msvc/int/Debug
[goodjoon Debug]$

일단은 Private Network 상에서 PoW 로 Consensus 를 하는, Public 형태와 동일한 Ethereum Local Network 을 구성 해보도록 한다.

▌config.json (genesis.json) 만들기

genesis.json 이 Frontier Release 버전인 eth 1.0.0 과 달라졌다. Geth 와도 호환이 안되는 JSON 포맷으로 바뀌었다 (config.json). 그나마 좀 Simple 한 포맷이었는데, 좀더 복잡하게 바뀌었다.
create-genesis.py 스크립트로 만들어져 나오는 json 은 동작하지 않으므로, 수동으로 작업해보도록 하겠다.

1.2.0 부터는 genesis.json 으로 부르지 않고, config.json 으로 부른다. 옵션도 --config 로 바뀌었다. --genesis 옵션도 코드 내에서는 아직 살아있지만 --help 로 볼때는 나오지 않는다.

우선 내 Account 중에 억만장자를 만들고 싶은 Account 의 Address 를 결정해야 한다.
eth 가 잘 빌드되었다면

$WEBTHREE/build/libethereum/ethkey/Debug
밑에 ethkey.exe 파일이 있다

[goodjoon Debug]$  ethkey.exe list --master 1111
1a7e55b0-3eb7-05ec-248e-8d901e268d76 0096bb98… XE602H4XB00HUY08LU416SCBGO3CS63H66  Default key
6ecc980b-2f99-013d-167e-0ea9caffde4e 007386ab… XE561WBEXUY46M6G05SDKF5P9C334V3JT6  myname
31ae0923-14da-a1a9-85ba-ab9563c5da4b 005bfaf9… XE241IE5KGWVRVYD6B5H8ZHMXNMP57Q4KM  joooooon
[goodjoon Debug]$
위 처럼 Wallet 의 Key 들이 보인다면 이중에서 사용할 Key 를 선택한다. 난 "Default key" 로 자동생성되었던 Account 를 선택한다.

Genesis 에는 Account 의 Balance 를 지정해주려면 Address 가 필요한데, 위 ethkey list 명령으로 출력된 결과에는 address 가 FULL 로 표시되지 않는다. ethkey 를 다시 사용하여 Full Address 를 표시해본다.
[goodjoon Debug]$  ethkey.exe inspect "Default key" --master 1111
Default key (0096bb98…)
  ICAP: XE602H4XB00HUY08LU416SCBGO3CS63H66
  Raw hex: 0096bb9802b14f72ba4cdbd105127fe57a1dafae
[goodjoon Debug]$

옵션에 계속 --master 1111 을 넣는 이유는, 현재 MinGW/MSYS 를 사용하고있는데 eth 가 이 환경에서는 key store 의 master 패스워드 입력하라는 Prompt 가 나올 때 Exception 이 발생하므로 master 패스워드를 바로 지정해주어야 한다. (Windows Command Prompt 환경에서는 문제가 없다)

위 Raw hex : 부분이 사용할 Account 의 address 이다.

이렇게 Linux 나 Mac 버전 또는 다른 Windows 에서도 Wallet 을 만들고 (keys.info, keys.salt), Key 를 생성한다 (Wallet (keys.info) 에 key 추가, .web3/keys 디렉토리에 추가된 key 의 정보(json) 추가).
Account 의 Address 를 모두 파악했다면, 이제 Genesis 정보를 만들어준다

{
    "sealEngine""Ethash",
    "params": {
        "accountStartNonce""0x00",
        "maximumExtraDataSize""0xFF",
        "tieBreakingGas"false,
        "minGasLimit""0x1388",
        "gasLimitBoundDivisor""0x0400",
        "minimumDifficulty""0x020000",
        "difficultyBoundDivisor""0x0800",
        "durationLimit""0x0d",
        "blockReward""0x4563918244F40000",
        "registrar" : "",
        "networkID" : "0xA1"
    },
    "genesis": {
        "nonce""0x0000000000000000",
        "difficulty""0x020000",
        "mixHash""0x0000000000000000000000000000000000000000000000000000000000000000",
        "author""0x0000000000000000000000000000000000000000",
        "timestamp""0x00",
        "parentHash""0x0000000000000000000000000000000000000000000000000000000000000000",
        "extraData""0x",
        "gasLimit""0x1388"
    },
    "accounts": {
        "0096bb9802b14f72ba4cdbd105127fe57a1dafae": { "wei""10000000000000000000000000000000000"},
        "0047d27a61e384403d875239cbc462896044213e": { "wei""20000000000000000000000000000000000"}
    }
}

위 처럼 genesis 정보를 만들어 준다. 가장 아래의 "accounts" 내의 정보가 주소와 Balance 이다.

아래는 "파악된" json 파라미터 정보들이다. Ethereum 의 가장 큰 문제가 바로 "체계 없는 문서화" 라고 생각한다. 어떤것은 Github Wiki 에 있고 어떤건 Gitbook 에, 또 어떤건 readthedocs 에.. 또 어떤건 각 Repository 의 wiki 에.. 또 어떤건 Repository 내의 프로젝트에 있는 .md 파일에.. 뭐 난리다.. 그래서 더 접근하기가 쉽지 않다.

위 config.json 의 경우도 제대로 된 문서 하나를 찾지 못했다. 개념적인 부분과 소스코드를 분석했던 기억을 더듬어 다시 써보니 혹시 틀린 부분이 있다면 그저 그러려니 하자.

[SealEngine]
Block 생성을 위한 Consensus 메커니즘을 어떤걸 사용할것인지를 지정한다.
현재 SealEngineBase Class 를 상속받는 Class 들에는 Ethash, BasicAuthority, NoProof 가 있다. 

Ethash 는 DAG 나 General Hashing 을 통해 PoW 를 하는 엔진이고, BasicAuthority 는 PoA 를 위해 실험적으로 Ethereum 에서 만들어놓은 Consensus 메커니즘으로, 현재 flu core 를 통해 사용할 수도 있으며, web3 에 통합되어있다. NoProof 는 Consensus 를 위한 증명작업을 하지 않는 Sealer 이다.

[Params]
"AccountStartNonce" : Account 의 최초 시작 Nonce 값을 지정한다. 기본적으로는 당연히 0 부터 시작하면 된다.
"maximumExtraDataSize" : 블럭의 Extra Data 의 최대 크기를 지정한다. 
"tieBreakingGas" : 
"minGasLimit" : 블럭의 최소 Gas 제한량이다. Block 의 GasLimit 값은 이 minGasLimit 보다 커야한다.
"gasLimitBoundDivisor" : 현재 블럭의 GasLimit 값은 parent block 의 gaslimit 대비 +- (parent block 의 GasLimit / gasLimitBoundDivisor)이내에 있어야 한다.
"minimumDifficulty" : 블럭의 최소 Difficulty 이다. 아무리 시간이 오래걸려도 PoW 는 이 Difficulty 이상을 유지해야 한다.
"difficultyBoundDivisor" : Frontier 까지 유효하며, 이전 Block 생성시간 대비 현재 Block 생성 시간이 durationLimit 보다 작으면 parent 의 difficulty 에 parent 의 difficulty / difficultyBoundDivisor 값을 더하고, 크면 같은값을 빼서 블럭 생성 시간을 조정한다
"blockReward" : Miner 의 Codebase 에 챙겨줄 reward wei 이다
"registrar" : Olympic 부터 Frontier, Homestead 등에서 기본적으로 존재하는 registrar Smart Contract 의 Address 이다. Name Register 서비스를 해주는 Contract 로 보면 된다.
"networkID" : 피어간의 통신 시 논리적으로 네트웍을 구분짓는 ID 이다. 피어간에 통신을 위해서는 이 networkID 값이 같아야 한다. Olympic 은 0, Frontier 는 1, Morden Testnet 은 2를 쓴다.

[Genesis]
"nonce" : 블럭의 nonce 값
"difficulty" : Block 의 Difficulty
"mixhash" : Block 의 hash 값
"author" : Block Author 정보, 필요하면 넣고..
"timestamp" : 블럭 생성 시각
"parentHash" : Genesis 이므로 0
"extraData" : 넣고싶은 Extra Data
"gasLimit" : Block 의 Gas Limit

[Accounts]
"<Account Address>": {"wei":<Balance>} 와 같은 형식은 UCA/UOA Account 의 Balance 를 적는 형식이고,
"0000000000000000000000000000000000000001": { "wei": "1", "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } } 와 같은 형식은 Precompiled Contract 를 표시하는 형식이다. Precompiled Contract 사용에 대해서는 향후에 알아보자.


이렇게 하면 일단 Private Network 에서 동작하는 Ethereum 을 위한 기본적인 Genesis 정보를 정의할 수 있다. 원래는 Genesis 만 지정하였는데, C++ Ethereum 은 좀더 유연성을 부여하기 위해 
  1. sealEngine
  2. options
  3. params
  4. genesis
  5. accounts
  6. network
로 구성된 config 정보를 입력할 수 있도록 하였다. 일단 목적은 private blockchain 을 염두에 둔것 같다.

다음은 이 Genesis 정보 기반으로 두 노드간에 실제적으로 통신을 해보자 (졸려졸려..)

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
조건, 반복, 분기문에 대해 알아본다. Java 나 C/C++ 대비 다른 부분만 설명하도록 하겠다. 일반적인 부분은 느낌대로 쓰면 된다. 뭔가 잘못되면 문법 오류가 바로 뜰테니 몇번 만나면 익숙해진다.

▌if

if <조건> { 처럼 사용, 중괄호 “{“ 가 반드시 inline 으로 와야한다. 중괄호를 생략해도 에러난다.
조건문에는 괄호 () 가 오지 않는다.
if err != nil {
   utils.Fatalf("Unlock error: %v"err)
}

if 의 block 이 끝나는 중괄호와 같은 라인에 else { 가 와야 한다
if script := ctx.GlobalString(utils.ExecFlag.Name)script != "" {
   repl.batch(script)
else {
   repl.welcome()
   repl.interactive()
}

} else if <조건> { 과 같이 else if 문도 inline 이어야 한다
if entry := GetHeader(dbheader.Hash())entry == nil {
   t.Fatalf("Stored header not found")
else if entry.Hash() != header.Hash() {
   t.Fatalf("Retrieved header mismatch: have %v, want %v"entryheader)
}

if <조건문> 내에서 함수 실행. 세미콜론 ; 으로 구분하여 if 구문 안에서 하고자 하는 작업을 선행할 수 있다. 
if berr := ioutil.ReadFile("./hello.txt")err == nil {
fmt.Printf("%s"b)
}

위에서 ioutil 패키지는 []byte, error 를 동시리턴하도록 되어있다. 나중에 다룰 내용이지만 이 동시리턴 된 값중 error 값을 조사하여 error 가 있으면 if block 을 실행하는 예제이다.

위에서 if 조건문에서 사용한 b, err 변수는 if 문 바깥에서는 사용할 수 없다


▌for

Go 에는 do…while 이나 while 이 없고 for 반복문만 제공됨
if 문 처럼 for <조건문> 에서도 괄호 () 를 사용하지 않으며 { 는 inline 으로 붙어야 함

for 문에 <조건문> 을 주지 않으면 무한루프를 돈다
func main() {
   for {
      fmt.Println("무한 루프")
   }
}


▌루프 Label 과 break, continue

Go 에서는 break 와 continue 시에 Loop Label 을 지원함
Label 은 for 문 바로 윗줄에 쓰여야 함
func main() {
   OutterLoop:
   for i := 0i < 10i++ {
      for j := 0j < 10j++ {
         if i == && j == {
            break OutterLoop
         } else if j == {
            continue OutterLoop
         }

         fmt.Println(ij)
      }
   }
}
결과
0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1

▌switch

Go 의 switch 문에서는 switch / case 만 쓰면 되며, 매 case 마다 break 를 사용할 필요가 없다.
조건에 만족하지 않으면 default: 라벨로 간다
case 에 “문자열” 을 쓸 수 있다.
func main() {
   str := "굿준"
   switch str {
   case "굿준":
      fmt.Println(str"'s Blog")
   default:
      fmt.Println("DEFAULT")
   }
}

그러나 여전히 break 문을 case 를 빠져나오기 위해 사용할 수 있다. (if 문 안에서..)

case 안에서 fallthrough 키워드를 사용하면 java 나 C/C++ 에서 break 문이 없는것과 같이 다음 case 로 넘어가는 효과를 낼 수 있다
func main() {
   str := "굿준"
   switch str {
   case "굿준":
      fmt.Print(str)
      fallthrough // 다음 case 로 흘러간다
   case "블로그":
      fmt.Println("'s 블로그")
   default:
      fmt.Println("DEFAULT")
   }
}

결과
굿준's 블로그

case 안에서 여러 조건을 함께 처리할 수 있다. case 의 값을 콤마 , 로 분리하면 된다.
func main() {
   str := "굿준"
   switch str {
   case "굿준""개발자":
      fmt.Print(str)
      fallthrough // 다음 case 로 흘러간다
   case "블로그""트위터""페이스북":
      fmt.Println("'s 블로그")
   default:
      fmt.Println("DEFAULT")
   }
}

switch 안에서 조건식도 사용 가능하다. 조건문 안에서 함수를 호출하고 case 로 분기하는 예제이다.
이때 조건문 안에서의 함수호출 다음에는 반드시 세미콜론 ; 이 와야한다.
func main() {
   val1 := 100

   rand.Seed(time.Now().UnixNano())
   switch swVal := val1 + rand.Intn(10)// 조건문 안에서의 함수호출은 ; 필수!
   case swVal > 100 && swVal < 200:
      fmt.Println("100 보다 크고 200보다 작음")
   case swVal >= 200 :
      fmt.Println("200 보다 크거나 같음")
      fallthrough
   default:
      fmt.Println("많이 큼")
   }
}

그리고, 함수가 호출된 경우에는 case 문의 값은 <조건식> 만 가능하다.

반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.3 Go - Package  (0) 2016.03.01
3.2 Go - 기본 문법 및 Type  (0) 2016.02.29
3.1 Go - Hello World  (0) 2016.02.29
2. Go - 개발환경 구성  (0) 2016.02.28
1.3 Go 언어란? - 다른 언어와 비교  (0) 2016.02.28
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
Java 와 같이 import 키워드로 Package 를 사용한다

하나의 패키지를 import 할때는 아래와 같이 import “<패키지명>” 을 사용한다
import "fmt"

여러 패키지를 import 할 때에는 import 를 여러번 쓸 수도 있지만, import ( ) 를 사용하면 편하다
import (
   "fmt"
   "io/ioutil"
   "os"
   "path/filepath"
   "runtime"
   "strconv"
   "strings"
   "time"

   "github.com/codegangsta/cli"
)

import 한 패키지를 패키지 이름 없이 전역으로 사용하려면 
import "fmt"

func main() {
   Println(runtime.NumCPU())
}
처럼 해주면 되나, 추천하지 않음

위 전역으로 사용하는 예제를 봐서 감이 오겠지만, import 키워드 다음에는 alias name 이 올 수 있다.
import out "fmt"

func main() {
   out.Println(runtime.NumCPU())
}

위 처럼 out 을 “fmt” 의 Alias Name 으로 지정하여 사용할 수 있다.
이전에도 잠깐 이야기 했지만, _ 를 alias name 으로 사용하면 사용하지 않은 Package 에러가 나지 않는다

반응형

'Software Development > Go (golang)' 카테고리의 다른 글

3.4 Go - 제어문  (1) 2016.03.01
3.2 Go - 기본 문법 및 Type  (0) 2016.02.29
3.1 Go - Hello World  (0) 2016.02.29
2. Go - 개발환경 구성  (0) 2016.02.28
1.3 Go 언어란? - 다른 언어와 비교  (0) 2016.02.28
블로그 이미지

Good Joon

IT Professionalist Since 1999

,