이더리움과 이더제로 소스코드의 차이점 살펴보기

in #kr2 years ago (edited)

소스도 공개 안되고 허접한 깃허브 레포지터리 관리로 스캠 대접 받던 이더리움제로가 드디어 소스코드를 공개했더군요. 이번에도 궁금증을 참을 수 없어서 어떤 변경이 있는지 살펴보았습니다.

개발에 관심이 있으신 분이 꽤 되시는 것 같아서 git를 사용하여 비교하는 방법을 이전에 라이트코인이나 비트코인 캔디에서 했던 방법을 써서 그대로 써서 기술하도록 하겠습니다.

이더리움 제로의 특징

우선 이더리움 제로가 처음 나왔을 때 가장 논란이 되었던 것은 Zero fee 입니다. "전송료가 없으면 DDoS 어택은 어떻게?" 라는 의문이 들게 될 것이고요, 발행량은 이더리움대비 두배입니다. 이더리움 제로의 가치를 이더리움의 가치 대비 10% 수준이 될 것으로 생각해본다면 즉, 어느정도 시간이 지나면 이더제로 2개의 가치가 이더리움 1/10 가치 즉 1 ETZ ~ 1/20 ETH 정도로 단기 수렴이 될 것으로 생각됩니다. 따라서 최소 몇개월 안으로 2018/2/11일 기준가로 이더리움이 100만원 수준이니 5만원이 되는데, 이것은 이더리움 클래식보다 비싼것이 되므로, 이클의 가격이 좀 더 오르거나, 이클보다 좀 더 낮은 가격으로 시장 가격이 형성될 것으로 짐작할 수 있습니다.

자세한 내용은 https://etherzero.org/ 사이트를 통해서 확인하실 수 있습니다.

소스코드는 뭐가 달라 졌을까

그러면 본격적으로 소스코드를 비교해보도록 하죠.

이더리움제로 프로젝트 역시 이더리움 커밋을 그대로 보존하지 않는 만행(?)을 저질러서 정확히 어떤 브랜치 포인트에서 이더리움 소스코드를 가져왔는지 알기 어려습니다만, 이더리움 소스를 가져와서 150여회 변경을 했고, 개발자가 최소 두명정도 된다는 사실을 볼 수 있네요.

일단 diff를 떠서 변경점을 살펴보기 위해 다음 과정을 수행합니다. 우선 이더리움 소스코드를 가져오고..

$ git clone https://github.com/ethereum/go-ethereum

여기에 remote 브랜치로 이더리움제로를 추가하고 fetch

$ git remote add zero https://github.com/etherzero-org/go-etherzero # zero라는 이름으로 리모트 브랜치 추가
$ git fetch zero # zero 리모트 브랜치 소스 가져옴
...

그런 다음 zero라는 이름의 브랜치로 zero/master 리모트 브렌치를 checkout

$ git checkout -b zero remotes/zero/master # zero/master 브랜치를 zero라는 이름의 브랜치로 checkout

이렇게 기본적으로 소스코드를 받아놓고 나서 무엇이 달라졌는지 살펴볼 차례입니다.

이더제로는 140여회 커밋을 했기때문에 이더제로의 최초 커밋소스와 이더리움 소스코드를 비교하는 것이 더 쉽습니다. 이더제로의 최초 커밋은 다음과 같습니다. (git log로 확인하니 커밋 01e4b426가 최초)

commit 01e4b4263d1773f65fe3094f8fda0e80b9d027c4
Author: Rolong <[email protected]>
Date:   Fri Jan 5 15:20:08 2018 +0800

    Init

우선 이 커밋과 이더리움master 브랜치 포인트를 비교하는 git diff master 01e4b426 명령으로 diff파일을 얻어서 달라진 점 살펴보기를 합니다.

첫번째 난관

git diff master 01e4b426 > a.diff 명령으로 diff를 떠서 살펴보니 이런이런... "^M" 문자가 잔뜩 보입니다. (한숨...) 이 경우라면 dos2unix 명령을 써서 diff 크기를 줄여주거나, -w 옵션을 사용해서 white space를 무시하고 diff를 떠서 diff의 크기를 확 줄일 수 있습니다. a.diff 변경을 살펴보았더니 그 내용은 대부분 리브렌딩입니다. 즉 eth=>etz 혹은Ethereum=>Ethzero로 문자열을 모두 교체했습니다. 처음에는 Copyright 문구도 모두 바꾸는 만행을 저질렀다가 모두 복구했습니다. 심지어 디렉토리 명을 eth에서 etz로 바꿨습니다. 아마도 스크립트를 통해서 일괄 수정한 것 같은데 나중에는 이러한 별 의미없는 수정에 대한 문제를 깨달았는지 이더제로의 두번째 이후의 커밋은 자신들의 잘못을 수정한 커밋들이 이어지고 있었습니다.

commit 2b3d57e4d661898810b1d344222ca2b2927824f7
Author: luomijie <[email protected]>
Date:   Mon Jan 8 20:25:43 2018 +0800

    modify by roger on 2018-01-08 for eth to etz

commit 8699d5f99b6c72208931d2a4a45305404852e652
Author: luomijie <[email protected]>
Date:   Mon Jan 8 15:45:25 2018 +0800

    modify by roger on 2018-01-08 for eth to etz

commit 8dc7624cc6426b3d396b2cce40f1f0af037a4c0b
Author: luomijie <[email protected]>
Date:   Mon Jan 8 14:36:18 2018 +0800

    modify by roger on 2018-01-08 for eth to etz

commit ed4b4746a72e818b14f06b23231fafa771d4233e
Author: luomijie <[email protected]>
Date:   Mon Jan 8 14:11:15 2018 +0800

    modify by roger on 2018-01-08 for eth to etz

commit e9ff3c5342fedab585147fb74d34b2832eba64cd
Author: luomijie <[email protected]>
Date:   Mon Jan 8 14:02:18 2018 +0800

    modify by roger on 2018-01-08 for eth to etz

commit 01e4b4263d1773f65fe3094f8fda0e80b9d027c4
Author: Rolong <[email protected]>
Date:   Fri Jan 5 15:20:08 2018 +0800

    Init

(그리고 중간에 다시 dos형식의 파일을 유닉스로 바꿔주는 커밋이 중간중간에 있었습니다.)

일단은 이더제로의 최초 커밋을 2b3d57e라고 상정하여 diff를 떠서 확인해봅니다. (-w 옵션으로 공백 변경은 일단 무시)

$ git diff -w master 2b3d57e > master.diff

diff파일의 사이즈가 좀 큽니다. 그렇다면 안정브렌치를 가져와서 고쳤을 가능성이 높기때문에 가장 최신의 안정버전인 v1.7.3 태그와 비교를 해봅니다.

$ git diff -w v1.7.3 2b3d57e > 1.7.3.diff

diff 파일 크기를 비교해보니 버전 1.7.3 안정버전을 기반으로 해서 이더제로 소스코드를 분기했을 가능성이 가장 높아 보입니다. (그밖에 버전 1.7.2와도 비교해보니 diff가 오히려 커졌습니다.) 이더제로 소스코드는 버전 1.7.3 안정버전을 가져다가 수정한 것으로 일단 가정합니다. 최소 버전 1.7.3 과 master 브랜치포인트 중간 어느 지점이 될 것으로 생각할 수 있습니다.

두번째 난관

이더제로 소스코드를 이더리움 버전 1.7.3을 기반으로 수정했을 것으로 생각하고, 변경된 내용을 diff로 떠서 살펴봅니다.

$ git diff -w v1.7.3 zero > zero.diff

zero.diff를 읽어보면 상당수 부분은 다음과 같은 리브렌딩입니다.

index 4d75704..0b685ea
--- a/core/gen_genesis.go
+++ b/core/gen_genesis.go
@@ -7,10 +7,10 @@ import (
        "errors"
        "math/big"

-       "github.com/ethereum/go-ethereum/common"
-       "github.com/ethereum/go-ethereum/common/hexutil"
-       "github.com/ethereum/go-ethereum/common/math"
-       "github.com/ethereum/go-ethereum/params"
+       "github.com/ethzero/go-ethzero/common"
+       "github.com/ethzero/go-ethzero/common/hexutil"
+       "github.com/ethzero/go-ethzero/common/math"
+       "github.com/ethzero/go-ethzero/params"
 )

 func (g Genesis) MarshalJSON() ([]byte, error) {

리브랜딩 관련된 부분이 여기 저기 분산되어서 쉽게 나누기 어려워보입니다. 일단 쉽게 분리할 수 있는 것들만 빼고난 후에 변경된 내역을 diffstat으로 살펴보도록 합니다.

제외 혹은 삭제된 부분

다음 코드는 제외 혹은 삭제된 코드들입니다. libethash라이브러리입니다.

vendor/github.com/ethereum/ethash

다음 테스트 코드는 비교에서 제외합니다.

...
 b/tests/block_test_util.go        
 b/tests/difficulty_test.go        
 b/tests/difficulty_test_util.go   
 b/tests/gen_btheader.go           
 b/tests/gen_difficultytest.go     
 b/tests/gen_stenv.go              
 b/tests/gen_sttransaction.go      
...
 b/p2p/discv5/net_test.go
...

그리고 스크립트 파일이나 일반 텍스트 파일 및 설정파일을 제외시키도록 합니다.

제외할 부분을 filterdiff 옵션으로 적용시켜서 diff를 추출합니다.

$ filterdiff -x "*/vendor/*" -x "*/tests/*" -x "*/*_test.go" -x "*/.*" -x "*/build/*" -x "*/*.sh" -x "*/whisper/*"  zero.diff > z.diff

원래 600여개의 파일이 변경되었다고 나오던 것이 396개 파일로 줄었습니다.

z.diff 파일을 살펴보니 */accounts/* 파일도 거의 리브렌딩 내용뿐입니다. 따라서 이것도 제외시킵니다. 이런 식으로 */swarm/* 파일도 목록에서 제외시키면서 특정 파일이 바뀐 것이 이더제로 개발자가 바꾼 것인지, 이더리움 개발자가 바꾼 것인지 범위를 좁혀갑니다.

예를 들어서 swarm/api 파일이 일부 다른데, 이 변경은 이더리움 원본 소스가 변경된 것입니다. 따라서 기준점얼 v1.7.3 이였던 것을 아래 커밋을 기준점으로 변경합니다.

commit f0ac925fa760a3a681de673ec3687e84f6ee657e
Merge: 0981d2e 03ec3fe
Author: Péter Szilágyi <[email protected]>
Date:   Fri Nov 24 16:23:37 2017 +0200

    Merge pull request #15329 from holisticode/exact-match-fix

    swarm/api: bug fix exact match for manifest

이런 식으로 diff 파일 크기가 최소화 되는 브랜치 포인트를 찾아내는 것입니다.

최종적으로 브렌치 포인트를 be12392f 커밋으로 특정하였습니다.

commit be12392fbad9f4a861130a347e6bcf07a5c34974
Author: Felix Lange <[email protected]>
Date:   Tue Nov 28 20:05:49 2017 +0100

    core/vm: track 63/64 call gas off stack (#15563)

    * core/vm: track 63/64 call gas off stack

    Gas calculations in gasCall* relayed the available gas for calls by
    replacing it on the stack. This lead to inconsistent traces, which we
    papered over by copying the pre-execution stack in trace mode.

    This change relays available gas using a temporary variable, off the
    stack, and allows removing the weird copy.

    * core/vm: remove stackCopy

    * core/vm: pop call gas into pool

    * core/vm: to -> addr

따라서 filtediff하기 전의 diff는 git diff be12392f zero 명령으로 얻은 것입니다.

그런 후에 diff 파일을 훝어 읽으면서 다음의 파일을 제거목록 및 포함 목록으로 지정하였습니다.
그리하여 추가적으로 다음을 제외시킵니다.

  • */rpc/* (리브랜딩 변경만 있음)
  • */p2p/* (리브랜딩 대부분)
  • */miner/* (리브랜딩 대부분)
  • */log/*
  • metrics/metrics.go
  • light/*
  • les/*(리브랜딩 대부분)
  • internal/*
  • eth/* (리브랜딩 대부분. 일부 디버그 코드 추가 eth/handler.go, eth/peer.go, eth/sync.go)
  • dashboard/*
  • crypto/*
  • core/*
  • consensus/*
  • common/*
  • cmd/*
  • params/dao.go

변경에 포함된 파일들

  • node/defaults.go (포트번호)
  • p2p/simulations/adapters/inproc.go (포트번호)
  • mobile/geth.go(이더리움 네트워크 아이디)
  • miner/worker.go(gaspoolvalue)
  • les/protocol.go (NetworkId = 88)
  • internal/ethapi/api.go(IsEthzeroTOSBlock())
  • eth/config.go (NetworkId: 88)
  • eth/backend.go (genesisHash fix)
  • eth/api.go (defaultBalanceTxProcess, SetBalance() added)
  • core/vm/interpreter.go(디버그)
  • core/types/transaction_signing.go(IsEthzeroTOSBlock() fix etc.)
  • core/types/transaction.go (defaultGas, defaultGasPrice added)
  • core/tx_validator.go (newly added)
  • core/tx_pool.go (변경됨)
  • core/tx_list.go (변경됨)
  • core/state_transition.go (변경됨)
  • core/state_processor.go (변경됨)
  • core/state/statedb.go (변경됨)
  • core/state/state_object.go (변경되었으나 모두 comment out상태)
  • core/genesis.go (변경되었으나 코멘트 아웃상태)
  • core/block_validator.go (변경됨)
  • consensus/ethash/consensus.go (변경됨)
  • cmd/wnode/main.go (포트번호)
  • cmd/utils/flags.go (포트번호)
  • cmd/puppeth/wizard_wallet.go (포트번호)
  • cmd/puppeth/wizard_node.go (포트번호)
  • cmd/puppeth/wizard_faucet.go (포트번호)
  • cmd/puppeth/wizard_explorer.go (포트번호)
  • cmd/puppeth/module_wallet.go (포트번호)
  • cmd/puppeth/module_explorer.go (포트번호)
  • cmd/geth/main.go (setBalance() call)
  • cmd/faucet/faucet.go (포트번호)

(헉헉..)

이제 패치를 정리하려면 전체 패치에서 1) 제외시킬 파일을 모두 제거 2) 포함시킬 파일을 추가 하면 됩니다.

이를 filterdiff 명령으로 쓰면

$ filterdiff -x "*/accounts/*" -x "*/vendor/*" -x "*/tests/*" -x "*/*_test.go" -x "*/.*" -x "*/build/*" -x "*/*.sh" -x "*/whisper/*" -x "*/rpc/*" -x "*/p2p/*" -x "*/miner/*" -x "*/log/*" -x "*/metrics/metrics.go" -x "*/light/*" -x "*/les/*" -x "*/internal/*" -x "*/eth/*" -x "*/dashboard/*" -x "*/crypto/*" -x "*/core/*" -x "*/consensus/*" -x "*/common/*" -x "*/cmd/*" z03.diff -x "*/trie/*" -x "*/swarm/*" -x "*/Dockerfile" zero.diff > 00.diff

이렇게 해서 00.diff 파일을 얻고, 그 다음으로 포함시킬 파일을 같은 방법으로 처리하면 됩니다.

*/node/defaults.go
*/p2p/simulations/adapters/inproc.go
*/mobile/geth.go
*/miner/worker.go
*/les/protocol.go
*/internal/ethapi/api.go
*/eth/config.go
*/eth/backend.go
*/eth/api.go
*/core/vm/interpreter.go
*/core/types/transaction_signing.go
*/core/types/transaction.go
*/core/tx_validator.go
*/core/tx_pool.go
*/core/tx_list.go
*/core/state_transition.go
*/core/state_processor.go
*/core/state/statedb.go
*/core/state/state_object.go
*/core/genesis.go
*/core/block_validator.go
*/consensus/ethash/consensus.go
*/cmd/wnode/main.go
*/cmd/utils/flags.go
*/cmd/puppeth/wizard_wallet.go
*/cmd/puppeth/wizard_node.go
*/cmd/puppeth/wizard_faucet.go
*/cmd/puppeth/wizard_explorer.go
*/cmd/puppeth/module_wallet.go
*/cmd/puppeth/module_explorer.go
*/cmd/geth/main.go
*/cmd/faucet/faucet.go

위 패턴 파일을 zinc라는 이름으로 만들면 filterdiff -I zinc zero.diff > 01.diff 명령을 통해서 변경된 파일 목록에 대한 diff를 추출할 수 있습니다.

그리하여 00.diff + 01.diff 파일을 cat 00.diff 01.diff | diffstat 으로 요약정보를 보면,

 Dockerfile.alltools                         |    4                                                                                                         [15/1932]
 README.md                                   |   24 +--
 VERSION                                     |    1
 appveyor.yml                                |    2
 cmd/faucet/faucet.go                        |   38 ++---
 cmd/geth/main.go                            |   27 ++-
 cmd/puppeth/module_explorer.go              |    4
 cmd/puppeth/module_wallet.go                |    6
 cmd/puppeth/wizard_explorer.go              |    4
 cmd/puppeth/wizard_faucet.go                |    6
 cmd/puppeth/wizard_node.go                  |   10 -
 cmd/puppeth/wizard_wallet.go                |    4
 cmd/utils/flags.go                          |   56 +++----
 cmd/wnode/main.go                           |   22 +-
 compression/rle/read_write.go               |    2
 consensus/ethash/consensus.go               |  144 ++++++++++++++++---
 console/bridge.go                           |    6
 console/console.go                          |    9 -
 containers/vagrant/Vagrantfile              |    2
 contracts/chequebook/api.go                 |    2
 contracts/chequebook/cheque.go              |   16 +-
 contracts/chequebook/contract/chequebook.go |    8 -
 contracts/chequebook/gencode.go             |   10 -
 contracts/ens/contract/ens.go               |    8 -
 contracts/ens/ens.go                        |   10 -
 contracts/release/contract.go               |    8 -
 contracts/release/release.go                |   20 +-
 core/block_validator.go                     |   44 +++--
 core/genesis.go                             |   56 ++++++-
 core/state/state_object.go                  |   43 +++++
 core/state/statedb.go                       |   21 +-
 core/state_processor.go                     |   25 ++-
 core/state_transition.go                    |  100 +++++++++++--
 core/tx_list.go                             |  183 +++++++++++++++++++++++-
 core/tx_pool.go                             |  207 +++++++++++++++++-----------
 core/tx_validator.go                        |   90 ++++++++++++
 core/types/transaction.go                   |   29 +++
 core/types/transaction_signing.go           |   17 +-
 core/vm/interpreter.go                      |   10 -
 eth/api.go                                  |   41 +++--
 eth/backend.go                              |   60 ++++----
 eth/config.go                               |   22 +-
 ethclient/ethclient.go                      |   12 -
 ethclient/signer.go                         |    4
 ethdb/database.go                           |    4
 ethdb/memory_database.go                    |    2
 ethstats/ethstats.go                        |   22 +-
 event/subscription.go                       |    2
 interfaces.go                               |    4
 internal/ethapi/api.go                      |   46 +++---
 les/protocol.go                             |   12 -
 miner/worker.go                             |   50 ++++--
 mobile/accounts.go                          |    8 -
 mobile/big.go                               |    2
 mobile/bind.go                              |    8 -
 mobile/common.go                            |    2
 mobile/discover.go                          |    8 -
 mobile/ethclient.go                         |    4
 mobile/ethereum.go                          |  147 -------------------
 mobile/geth.go                              |   48 +++---
 mobile/init.go                              |    2
 mobile/interface.go                         |    2
 mobile/logger.go                            |    2
 mobile/p2p.go                               |    2
 mobile/params.go                            |    6
 mobile/types.go                             |    6
 mobile/vm.go                                |    2
 node/api.go                                 |   10 -
 node/config.go                              |   16 +-
 node/defaults.go                            |   36 ++--
 node/node.go                                |   14 -
 node/service.go                             |   10 -
 p2p/simulations/adapters/inproc.go          |   12 -
 params/bootnodes.go                         |   12 -
 params/config.go                            |   95 +++++++++---
 params/dao.go                               |    2
 params/protocol_params.go                   |    5
 77 files changed, 1282 insertions(+), 738 deletions(-)

변경점 요약

위 변경된 내용을 간략히 정리하면 다음과 같습니다.

  • 리브렌딩 등 전체 변경된 파일은 약 600개 (598 files changed, 2997 insertions(+), 5679 deletions(-))
  • 리브렌딩 등을 제외한 변경은 약 80개 (1282줄 추가. 738줄 삭제)

(filterdiff 명령이 git diff 출력물을 제대로 처리하지 못하는 관계로 git 에 의해 얻어진 extended header를 간단히 스크립트로 전처리하여 extended header를 날리고 filterdiff를 이용하였습니다)

금방 끝날줄 알았으나 시간이 상당히 걸렸네요.

추천 및 댓글은 제게 힘이됩니다~

※ 변경사항

  • 2/12 - 작성 시작하다가 일이 너무 커져서 뒤로 미룸.. 2/13일 오전 8:05 작성 완료.
Sort:  

열정이 대단하십니다. 소스 비교가 정말 지루하면서도 힘든데...!덕분에 조금 이나마 이더제로에 흥미가 생기네요.
감사합니다!

어쩌다 보니 이더리움 계열 소스코드를 들여다보게 되었네요 go언어를 배워야....

??? 덧글 감사합니다~

정성과 열정적인 포스팀, “이게 github 분석이다”를 보여주시는군요 ㅎㅎ리스팀합니다 @홍보해

띠용~? 그냥 홍보해만 적으면 안되는건가요??

허허 포인트는 있으십니까 ~

베타테스트때만 설명서를 잠깐 훑어봤더니...ㅠㅠ
포인트가 있어야 사용이 가능한거였네요ㅋㅋㅋㅋ 창피...ㅠㅠ
다시한번 설명서를 정독해보고 오겠습니다

말씀 감사합니다~~

@hackyminer님 안녕하세요. 아리 입니다. @julianpark님이 이 글을 너무 좋아하셔서, 저에게 홍보를 부탁 하셨습니다. 이 글은 @krguidedog에 의하여 리스팀 되었으며, 가이드독 서포터들로부터 보팅을 받으셨습니다. 축하드립니다!

오 그런게 있나보죠? 감사합니다~~

근데 진짜 이더리움제로는 전송료가 없나요? 부작용 같은건 없나요?

DDoS 어택을 우려하는 부분이 있는데, 소스코드에 DDoS어택을 방어하도록 하는 코드를 넣어놓은 것 같습니다. 그 고친 소스코드를 제대로 읽어봐야 뭔가를 알 수 있을 것 같습니다~

어렵지만 코린이 읽고 많은 공부하고 갑니다. ^^
팔로우하겠습니다.

감사합니다~~

소스같은 걸 보면 어렵다는 생각밖에는 들지가 않네요...
이런 어려운걸 하시는 분들을 보면 대단하다는 생각밖에... 들지가 안습니다
감사합니다
즐거운 설명절 보내세요

저도 어렵다고 생각합니다~ 감사합니다~