geth 소스 읽기 Part2 Day02 by woojin.joe

View this thread on steempeak.com
· @woojin.joe · (edited)
$1.80
geth 소스 읽기 Part2 Day02
![main_logo](https://steemitimages.com/DQmWD8NAiZnbdwXrZArK2knyXvrxeQBDqFtrsWErvTXgnZ5/main_logo.jpg)

이 글은 자바 개발자의 go-ethereum(geth 클라이언트) 소스 읽기 시리즈 Part2 연재 중 두 번째 글입니다. 


1. [Day 01: 마이닝 과정 실습](https://steemit.com/kr/@woojin.joe/geth-part2-day01)
2. **(본 글)**  Day 02: 마이닝 시작 과정 코드 읽기 (1)
3. Day 03: 마이닝 시작 과정 코드 읽기 (2)
4. TBD


전체 연재 목록은 아래 페이지에서 확인해 주세요.
http://www.notforme.kr/block-chain/geth-code-reading




## Part2 연재의 대상 독자 및 목표
이 글은 독자 분들이 적어도 Java와 같은 OOP 계열의 언어로 프로그래밍 경험이 있다는 것을 가정합니다. 또한 계정, 채굴 등 블록체인과 이더리움과 관련된 기초적인 개념과 이더리움 백서나 황서의 내용을 간단하게 알고 있다고 가정합니다. `geth` 코드를 읽으면서 백서 및 황서에서 정의된 스펙이 어떻게 구현되었는지를 확인하는 것이 목적입니다.

더불어 이 연재는 다음 3가지 목적을  염두하고 쓴 것입니다.

1. 새로운 언어(`Go`)를 오픈소스 코드를 읽으며 배운다.
2. 오픈소스를 읽으며 코드리딩 능력을 배양한다.
3. 블록체인의 기술을 직접 코드를 통해서 익힌다.



지난 Part1에서는 총 6번의 글을 통해서  `geth`구조와 실행방법에 대해서 살펴봤습니다. Part2에서는 좀 더 구체적으로 이더리움의 핵심 기능들이 어떻게 구현되었는지  Part1에서와 마찬가지로 코드를 통해서 알아보려고 합니다






## 다루는 내용

지난 글에서는 로컬에 하나의 `geth` 노드를 띄운 후 마이너를 실행하고 블록이 생성되는 과정을 직접 실습했습니다. 이 과정에서 발생한 이더리움을 다른 신규계정으로 전송하는 것 또한 실습했습니다. 

오늘은 이더리움을 마이닝하는 과정을 실습이 아닌 코드로 따라가 보려고 합니다. 물론 마이닝 과정 가운데 일부 로직은 좀 더 세부적으로 살펴볼 것도 있습니다. 예를 들면 `PoW`를 실행하는 `ethash`나 블록상태를 저장하는 로직 등이 그렇습니다. 오늘은 이러한 세부 로직을 모두 파악하기 보다는 **코드 레벨에서 지난 번 실습한 마이닝 동작과정을 큰 흐름으로 살펴보는 것**이 목적입니다. 



>  한 번에 많은 내용을 살펴보고 글로 담기가 쉽지 않을 것 같습니다. 앞으로도 되도록 너무 길지 않게 분석할 코드의 내용을 논리적으로 잘개 쪼개서 포스팅을 하려고 합니다. 



마지막으로 오늘부터 본격적으로 시작하는 Part2에서 읽는 코드의 커밋 해시 [0fe479e](https://github.com/ethereum/go-ethereum/tree/0fe47e98c4d93f952dc7415f401fd03b2664a21d)입니다.

---



## 마이닝 시작 포인트

첫 출발은 마이닝을 실행하는 지점에서 출발하려고 합니다. `geth`에서 마이너를 실행시키는 방법은 2가지가 있습니다. 하나는 `geth` 실행 시에 `--mine`옵션을 주는 것이고 다른 하나는 지난 시간에 했던 방법처럼 `web3`를 사용하여 `rpc`로 실행하는 방법입니다.



> 마이너를 실행시키는 2가지 방법
>
> 1. `geth` 실행 시 mine 옵션 주기
> 2. `web3`를 활용하여 `miner.start()` 명령을 콘솔에 입력하기



2가지 방법은 호출 방식만 다를 뿐 결국 `Ethereum` 객체의 필드인 `miner`의 `Start` 함수를 호출합니다. 지난 글 마지막에 콘솔에서 `miner.start()`를 호출할 때 실행되는 함수에 디버깅 포인트를 걸어서 `GoLand`에서 실행된 `geth`의 동작 흐름을 멈추게 했었습니다. 이 지점이 바로 `miner`의 `Start` 함수였습니다.



그럼 `miner` 객체의 코드에서부터 시작해야 겠네요!




### 마이너의 생성 로직

`miner`관련 코드를 읽기에 앞서 `miner` 객체의  생성 로직을 살펴보고 넘어갈까 합니다. Part1 [마지막 글](https://steemit.com/kr/@woojin.joe/go-ethereum-day-6)에서 `geth`의 노드 실행 과정 중에서 `Ethereum` 객체의 생성과정을 이미 살펴봤는데 이 때 `miner` 생성된 것을 기억하시나요? 복습 차원에서 [코드](https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/eth/backend.go#L169-L170)를 다시 가져와 봅니다.



```go
eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine)
eth.miner.SetExtra(makeExtraData(config.ExtraData))
```
\
지난 글에서는 `miner.New()`가 호출 된다는 것까지 확인을 했었습니다. 오늘은 `New` 함수 코드를 들여다 보겠습니다.



```go
func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine) *Miner {
	miner := &Miner{
		eth:      eth,
		mux:      mux,
		engine:   engine,
		worker:   newWorker(config, engine, common.Address{}, eth, mux),
		canStart: 1,
	}
	miner.Register(NewCpuAgent(eth.BlockChain(), engine))
	go miner.update()

	return miner
}
```
\
함수에서 인자로 넘겨 받은 내용은 다음과 같습니다.

1. `eth` 객체: eth의 속성인 `miner` 에게 스스로의 참조를 전달하고 있네요.
2. `config`: 타입이름을볼 때 블록체인 관련 설정
3. `mux`: 이벤트 처리를 할 때 쓸 것으로 추정
4.  `engine`:  마이닝을 위해서는 합의 과정이 관련이 있겠지요?

이렇게 넘겨받은 인자로 `Miner` 타입의 객체를 생성합니다. 이 때 `worker`라는 속성은 `newWorker` 함수로 생성이 되는 것을 볼 수 있습니다. 그리고 나서 `Register` 함수를 `NewCpuAgent` 함수의 반환 값으로 호출하고 있네요. `Register` 함수는 간단합니다. 



```go
func (self *Miner) Register(agent Agent) {
	if self.Mining() {
		agent.Start()
	}
	self.worker.register(agent)
}
```
\
인자로 `Agent`를 받네요. 앞에서 `NewCpuAgent`가 `Agent`타입의 객체를 반환한다는 것을 유추할 수 있겠네요. 코드의 로직은 간단합니다. 이미 마이닝 중이면 `agent`의 `Start`를 실행하고, 아니면 `worker`에 인자로 받은 `agent`를 등록합니다. 아하! 실제 등록되는 위치는 `miner`가 아니라 `worker`군요!



그럼 이제`worker`를 생성한 `newWorker` [함수](https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/miner/worker.go#L135-L164)를 봐야할 것 같습니다. 



```go
func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
	worker := &worker{
		config:         config,
		engine:         engine,
		eth:            eth,
		mux:            mux,
		txsCh:          make(chan core.NewTxsEvent, txChanSize),
		chainHeadCh:    make(chan core.ChainHeadEvent, chainHeadChanSize),
		chainSideCh:    make(chan core.ChainSideEvent, chainSideChanSize),
		chainDb:        eth.ChainDb(),
		recv:           make(chan *Result, resultQueueSize),
		chain:          eth.BlockChain(),
		proc:           eth.BlockChain().Validator(),
		possibleUncles: make(map[common.Hash]*types.Block),
		coinbase:       coinbase,
		agents:         make(map[Agent]struct{}),
		unconfirmed:    newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth),
	}
	// Subscribe NewTxsEvent for tx pool
	worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh)
	// Subscribe events for blockchain
	worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh)
	worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh)
	go worker.update()

	go worker.wait()
	worker.commitNewWork()

	return worker
}
```
\
`worker`가 많은 속성을 갖고 있네요! 이쯤 되면  `miner` 객체는 마이닝의 실행/종료를 위한 컨테이너 정도의 역할이고 로직의 많은 부분은 `worker`가 담당한다는 것을 짐작할 수 있습니다. 속성 중에 자세히 들여다 보면 `agents`가 맵으로 선언되어 있네요. 앞에서 `Register`할 때 `worker`에 했던 부분이 여기서 연결되네요.



객체를 생성한 후에는 여러 이벤트를 구독하기 위한 채널 설정이 있습니다. 친절하게 주석으로 설명해주는 것이 보이시죠? 트랜잭션 Pool에 추가된 새 트랜잭션을 구독하는 이벤트와 블록체인의 변경 상태를 구독하는 채널을 셋팅합니다. 이어서  `go` 문법을 사용하여 `worker.update()`와 `worker.wait()` 루틴을 각각 실행하고  `commitNewWork` 함수를 실행한 뒤에 생성된 `worker`를 반환합니다.



> 계속해서 앞으로 코드에서 Work라는 단어가 나올텐데요. 체인에 포함되지 않은 블록을 마이닝하여 포함시키는 과정. 즉 우리가 개념적으로 하는 그 작업 증명이 코드레벨에서는 Work, Worker와 연관된 것이라 보면 될 것 같습니다.



`worker`를 반환하기 전에 고루틴으로 호출한 `update`, `wait`은 for 문을 계속 돌면서 특정 이벤트에 따라 실행하는 로직입니다. 우선은 이 정도까지만 확인하고 이 부분은 이후에 다시 확인하는 것으로 하겠습니다. 



마지막 `worker.commitNewWork()`이 실제 작업증명을 위해 컨펌되지 않은 블록을 포함시키는 부분인데요. 이 함수는 앞으로 보게될 마이너를 시작하는 함수에서 다시 호출될 겁니다. 여기서는 로직상 호출은 되지만 내부에서 마이닝 실행중이 아니라 실제 블럭을 커밋하지 않습니다. `newWorker`에서 왜 이 함수를 호출하는지는 아직 정확하게는 모르겠네요;...



자 다시 `miner`의 생성 로직인  `New` 함수로 돌아오면 `miner` 객체를 생성한 후 이를 반환하기 직전에 고루틴으로 다음과 같은 함수를 실행합니다.

```go
go miner.update()
```
\
이 함수는 마이닝 하기 전에 기존에 네트워크에 있는 블록체인 정보를 받아와서 싱크하는 로직입니다. 들어가 보면 전체 블록 정보를 받기 전까지는 마이닝을 하지 않고 모두 받고 나서 시작하는 로직이 구현되어 있습니다. 이 함수의 구현은 궁금한 분들을 위해서 [링크](https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/miner/miner.go#L78-L104)로 대체합니다.



### 마이너의 시작

앞에서 마이너를 시작하는 방법은 `geth` 실행 시 옵션으로 실행하는 방법과 콘솔에서 명령을 주는 방법이 있다고 했습니다. 간단히 각 코드 부분이 어디인지 확인해 보겠습니다.



#### geth 실행 시 마이너 시작부분

이 코드는 `geth`패키지 `main.go` 파일의  `startNode` 함수에 있습니다. Part1에서 `utils.StartNode` 함수만 설명하고 이후 로직은 자세하게 다루지 않았는데요. 이 함수의 마지막 부분을 보면 다음과 같은 [로직](https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/cmd/geth/main.go#L283-L306)이 있습니다.

```go
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
		// 마이닝을 실행하기 위한 조건 확인 하는 부분은 생략....
		// Set the gas price to the limits from the CLI and start mining
		ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name))
		if err := ethereum.StartMining(true); err != nil {
			utils.Fatalf("Failed to start mining: %v", err)
		}
	}
```
\
보시는 바와 같이 if문의 조건으로 `utils.MiningEnabledFlag.Name`을 볼 수 있습니다.  이 플래그가 바로 터미널에서 옵션으로 주는 `--mine` 입니다. 마이닝 옵션이 있으면 아래 `ethereum.StartMining` 함수를 호출하는 것을 확인할 수 있습니다. 이 함수가 실제 마이닝을 시작하는 함수가 됩니다. 그럼 콘솔에서 `rpc` 호출은 어떻게 되는지 보겠습니다.



#### rpc로 실행 시 마이너 시작부분

`geth`는 `rpc`  엔드포인드를 관리하는 로직이  `rpc` 패키지에 있고 실제 각 API는 관련 패키지의 `api.go`에 선언되어 있습니다. 하지만 마이닝을 시작하는 엔드포인트는 `miner`패키지는 아닙니다. 실제로는 `eth` 패키지의 `api.go`  에 있습니다. `Ethereum` 객체가 하나의 컨테이너로서 관련된 로직을 위임하고 있는 구조라 실제 API엔드포인트가 여기 있는 것 같습니다. [코드](https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/eth/api.go#L135-L160)를 그럼 한 번 볼까요?

 

```go
// Start the miner with the given number of threads. If threads is nil the number
// of workers started is equal to the number of logical CPUs that are usable by
// this process. If mining is already running, this method adjust the number of
// threads allowed to use.
func (api *PrivateMinerAPI) Start(threads *int) error {
	// Set the number of threads if the seal engine supports it
	if threads == nil {
		threads = new(int)
	} else if *threads == 0 {
		*threads = -1 // Disable the miner from within
	}
	type threaded interface {
		SetThreads(threads int)
	}
	if th, ok := api.e.engine.(threaded); ok {
		log.Info("Updated mining threads", "threads", *threads)
		th.SetThreads(*threads)
	}
	// Start the miner and return
	if !api.e.IsMining() {
		// Propagate the initial price point to the transaction pool
		api.e.lock.RLock()
		price := api.e.gasPrice
		api.e.lock.RUnlock()

		api.e.txPool.SetGasPrice(price)
		return api.e.StartMining(true)
	}
	return nil
}
```
\
친절하게 주석에 API 설명이 있네요. 함수 초반 몇가지 로직을 일단 지나치고 보면 마지막  `return` 부분에 `StartMining` 함수가 보이네요. 바로 이전에 `geth` 실행 시 호출 했던 것과 동일한 함수입니다! 



### StartMining 함수

이 함수는 마이너를 실행을 감싸고 있습니다. [코드](https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/eth/backend.go#L335-L358)는 다음과 같습니다.



```go
func (s *Ethereum) StartMining(local bool) error {
	eb, err := s.Etherbase()
	if err != nil {
		log.Error("Cannot start mining without etherbase", "err", err)
		return fmt.Errorf("etherbase missing: %v", err)
	}
	if clique, ok := s.engine.(*clique.Clique); ok {
		wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
		if wallet == nil || err != nil {
			log.Error("Etherbase account unavailable locally", "err", err)
			return fmt.Errorf("signer missing: %v", err)
		}
		clique.Authorize(eb, wallet.SignHash)
	}
	if local {
		// If local (CPU) mining is started, we can disable the transaction rejection
		// mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous
		// so none will ever hit this path, whereas marking sync done on CPU mining
		// will ensure that private networks work in single miner mode too.
		atomic.StoreUint32(&s.protocolManager.acceptTxs, 1)
	}
	go s.miner.Start(eb)
	return nil
}
```
\
첫 줄의 코드는 마이닝시 생성된 이더리움을 전달할 코인베이스 계정을 가져오는 함수입니다. 함수 구현을 보면 특별한 예외가 없는한  `geth`가 실행되는 곳의 지갑 첫번째 계정을 반환합니다. 지난 시간 실습 때 아무런 계정 생성없이 `miner.start()`하면 에러가 반환되어 계정 생성 했던 부분이 바로 이 코드와 관련이 있습니다.



마이닝을 실행하는 실제 로직은 함수의 제일 마지막 `return`문 위에 있는 고루틴 `s.miner.Start`함수입니다. 코인베이스를 인자로 전달하는 이 함수가 마이너를 시작하는 지점입니다.



#### Miner의 Start 함수 

이 함수가 바로 지난 시간 디버깅 포인트를 걸었던 부분입니다. 전체 [코드](https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/miner/miner.go#L106-L119)를 한 번 살펴볼까요?

```go
func (self *Miner) Start(coinbase common.Address) {
	atomic.StoreInt32(&self.shouldStart, 1)
	self.SetEtherbase(coinbase)

	if atomic.LoadInt32(&self.canStart) == 0 {
		log.Info("Network syncing, will start miner afterwards")
		return
	}
	atomic.StoreInt32(&self.mining, 1)

	log.Info("Starting mining operation")
	self.worker.start()
	self.worker.commitNewWork()
}
```
\
인자로 받은 코인 베이스를 마이너 객체에 저장하고 마이닝 과정을 시작해도 되는지 `canStart` 변수로 확인하고 있습니다. 이 변수는 최초 생성 시에는  `1`로 셋팅되어 있기 때문에 위 조건으로 실패할 일은 없습니다. 다만  앞에서  마이너 객체를 생성할 때 기존의 블록체인을 받아오는 함수  `miner.update()` 에서 값이 변경될 수도 있습니다. 이 경우는 `update` 할 내용이 있어서 모든 데이터를 받아오면 그때 `canStart`를 `1`로 변경한 후 `Start`를 실행합니다.



다음으로 시작할 준비가 되면 `mining` 변수에 `1`을 셋팅합니다. 이후에도 코드 여기저기에서 `self.mining`의 상태를 보고 마이닝 중인지 확인합니다.  이어서 `start` 함수와  `commitNewWork` 함수를 각각 호출합니다. 



#####  worker.start 함수

앞에서 마이너 객체를 생성할 때 `Register` 함수에서도 봤지만 마이너 객체는 실제 마이닝 작업을 하는 객체가 아닙니다. 이 함수의 [코드](https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/miner/worker.go#L204-L214)를 보면 실제 실행은 `agent`임을 확인할 수 있습니다.

```go
func (self *worker) start() {
	self.mu.Lock()
	defer self.mu.Unlock()

	atomic.StoreInt32(&self.mining, 1)

	// spin up agents
	for agent := range self.agents {
		agent.Start()
	}
}
```
\
최종적으로 위 코드를 통해서 마이닝 작업을 수행하는 함수는 `agent` 라는 것을 알 수 있습니다. 그렇다면 `self.agents`에는 어떤 `agent`가 들어있을까요? 우선 `miner.New()`함수에서 `CpuAgent`가 등록했다는 것을 떠올려보면 최소한 하나의 `agent`는 들어 있다는 것을 보장할 수 있습니다. 추가로 `rpc`로 마이닝을 실행할 경우에도 `RemoteAgent` 타입이 추가됩니다. 따라서 최대 2개의 `agent`가 실행됩니다. 



depth가 깊어지네요… `CpuAgent`와 `RemoteAgent`의 각각 `Start`함수를 살펴보기 전에  여기서 한번 정리를 해볼까요.

1. `geth` 실행 시점이든, `rpc` 호출이든 =>  `Ethereum`객체의 `StartMining`함수를 호출
2. `StartMining`함수는 => `Miner` 객체의 `Start` 함수 호출
3.  `Miner` 객체의 `Start` 함수는 => `Worker` 객체의 `Start` 함수 호출
4. `Worker`객체의 `Start`함수는 => 각 `Agent`의 `Start` 함수 호출



이제 각 `Agent`의 함수를 살펴봅시다. 먼저 `RemoteAgent` 함수의 [코드](https://github.com/ethereum/go-ethereum/blob/fbf57d53e272c2d79d4d899bb94db824678de2d5/miner/remote_agent.go#L80-L87)부터 보겠습니다.

```go
func (a *RemoteAgent) Start() {
	if !atomic.CompareAndSwapInt32(&a.running, 0, 1) {
		return
	}
	a.quitCh = make(chan struct{})
	a.workCh = make(chan *Work, 1)
	go a.loop(a.workCh, a.quitCh)
}
```
\
2개의 채널을 생성한 후 이 값을  `loop` 함수에 인자로 전달하면서 고루틴으로 실행하고 있네요.`loop` 함수의 코드를 보면 인자로 전달 받은 채널에 값이 있을 때에 따른 처리로직만 있을 뿐 실제 마이닝 관련 코드는 없습니다. 함수에 선언된 주석을 보면 모니터링 관련 코드라고 하는 군요. 따라서  `loop`의 [코드](https://github.com/ethereum/go-ethereum/blob/fbf57d53e272c2d79d4d899bb94db824678de2d5/miner/remote_agent.go#L165-L202)를 굳이 자세히 들여다 보지 않겠습니다.



이제 우리의 관심사는 `CpuAgent` 입니다. 이 함수의 코드는 아주 간단합니다.

```go
func (self *CpuAgent) Start() {
	if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) {
		return // agent already started
	}
	go self.update()
}
```
\
이 함수는 현재 마이닝이 실행중인지 확인 후 고루틴으로 `update`함수를 실행하고 있네요. 아… 마이닝 로직이 한 depth 더 들어가는 군요. `update` 함수까지 [코드](https://github.com/ethereum/go-ethereum/blob/fbf57d53e272c2d79d4d899bb94db824678de2d5/miner/agent.go#L78-L100)를 들어가 봅시다.  



```go
func (self *CpuAgent) update() {
out:
	for {
		select {
		case work := <-self.workCh:
			self.mu.Lock()
			if self.quitCurrentOp != nil {
				close(self.quitCurrentOp)
			}
			self.quitCurrentOp = make(chan struct{})
			go self.mine(work, self.quitCurrentOp)
			self.mu.Unlock()
		case <-self.stop:
			self.mu.Lock()
			if self.quitCurrentOp != nil {
				close(self.quitCurrentOp)
				self.quitCurrentOp = nil
			}
			self.mu.Unlock()
			break out
		}
	}
}
```
\
보이시나요? 코드 한 가운데 고루틴으로 `mine` 함수를 호출하는 것이!!! 자 이제 이 함수가 어떻게 `mine`을 호출하는지를 알아야겠지요? 이 코드는 사실 `golang`의 채널과 `goto`문의 독특한 문법으로 돌고 있는 코드입니다. 설명하자면 이렇습니다. 우선   `for`문은 계속 돕니다. 이 `for` 문 안에서 `self.workCh` 채널과 `self.stop` 채널에 데이터가 들어오기를 기다립니다. 이 중에 `workCh`을 통해서 블록체인에 포함할 작업이 `work`로 들어올때 바로 `self.mine()` 함수까지 실행이 되는 것입니다.

반면 `stop` 채널로 데이터가 들어오면 `break out`으로 인해 `for`문을 탈출합니다. 기존의 C 언어를 공부한 분이라면 `goto`문이 가리키는 곳이 for문 위라서 다시 `for` 문이 실행되는 것으로 오해할 수 있는데요.(제가 그랬습니다.) `golang`은  해당 레이블로 돌아간 뒤에 돌고 있던 루프문의 다음 문장으로 이동한다고 합니다! 앞으로도 여기저기서 위와 같이 채널과 `goto`문을 활용하여 특정 이벤트나 데이터를 수신하면서 처리하는 로직을 보게 될 겁니다. 지금 눈에 잘 익혀 두세요 ^^



자 그럼! 여기서 자연스럽게 질문이 하나 나와야 합니다. 바로 **누가 `workCh`에 데이터를 밀어 넣느냐 하는 것**입니다. 이건 바로 위에서 `worker.start`함수 다음으로 실행 한 `worker.commitNewWork()`함수의 역할입니다. 오늘 글에서 이 부분까지 다루면 좋겠지만 이미 적지 않은 내용을 다룬 것 같아… 여기서 한번 호흡을 가다듬고 마이닝을 위한 나머지 코드는 다음 글에서 다뤄야 할 것 같습니다.



---





## 결론

오늘은 지난 시간에 실습했던 마이닝 과정을 코드로 차근히 따라가보는 일을 했습니다. 오늘 살펴본 코드는 위에서 한번 정리했지만 다시 정리하면 다음과 같은 흐름이었습니다.



> 1. geth` 실행 시점이든, `rpc` 호출이든 =>  `Ethereum`객체의 `StartMining`함수를 호출
> 2. `StartMining`함수는 => `Miner` 객체의 `Start` 함수 호출
> 3. `Miner` 객체의 `Start` 함수는 => `Worker` 객체의 `Start` 함수 호출
> 4. `Worker`객체의 `Start`함수는 => 각 `Agent`의 `Start` 함수 호출
> 5. `Agent` 가운데 `CpuAgent` 함수가 바로 마이닝 관련 함수이고 여기서 => `update` 함수 호출
> 6. `update`함수 안에서 `workCh`을 수신하다가 => 데이터가 들어오면 `mine` 함수 호출



긴 여정이었습니다. 다음 글에서 오늘 미쳐 다루지 못한 `mine`함수와 함께  `worker.commitNewWork` 함수에서 어떻게   `workCh` 채널에 `Work` 객체를 넣는지 살펴보고자 합니다.



그럼 다음 연재에서 뵙겠습니다.
👍  , , , , ,
properties (23)
post_id49,899,392
authorwoojin.joe
permlinkgeth-part2-day02
categorykr
json_metadata"{"format": "markdown", "app": "steemit/0.1", "tags": ["kr", "kr-dev", "ethereum", "geth"], "links": ["https://steemit.com/kr/@woojin.joe/geth-part2-day01", "http://www.notforme.kr/block-chain/geth-code-reading", "https://github.com/ethereum/go-ethereum/tree/0fe47e98c4d93f952dc7415f401fd03b2664a21d", "https://steemit.com/kr/@woojin.joe/go-ethereum-day-6", "https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/eth/backend.go#L169-L170", "https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/miner/worker.go#L135-L164", "https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/miner/miner.go#L78-L104", "https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/cmd/geth/main.go#L283-L306", "https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/eth/api.go#L135-L160", "https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/eth/backend.go#L335-L358", "https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/miner/miner.go#L106-L119", "https://github.com/ethereum/go-ethereum/blob/6ce21a4744461fc35c05b1c5fcc92136761be747/miner/worker.go#L204-L214", "https://github.com/ethereum/go-ethereum/blob/fbf57d53e272c2d79d4d899bb94db824678de2d5/miner/remote_agent.go#L80-L87", "https://github.com/ethereum/go-ethereum/blob/fbf57d53e272c2d79d4d899bb94db824678de2d5/miner/remote_agent.go#L165-L202", "https://github.com/ethereum/go-ethereum/blob/fbf57d53e272c2d79d4d899bb94db824678de2d5/miner/agent.go#L78-L100"], "image": ["https://steemitimages.com/DQmWD8NAiZnbdwXrZArK2knyXvrxeQBDqFtrsWErvTXgnZ5/main_logo.jpg"]}"
created2018-05-23 10:40:57
last_update2018-05-23 19:48:18
depth0
children5
net_rshares467,044,884,162
last_payout2018-05-30 10:40:57
cashout_time1969-12-31 23:59:59
total_payout_value1.381 SBD
curator_payout_value0.423 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length15,457
author_reputation131,488,838,444
root_title"geth 소스 읽기 Part2 Day02"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars0
author_curate_reward""
vote details (6)
@sd974201 ·
실행 관련내용 잘봤네요. 정말 멋지네요.
properties (22)
post_id49,902,041
authorsd974201
permlinkre-geth-part2-day02-20180523t110646
categorykr
json_metadata{}
created2018-05-23 11:06:48
last_update2018-05-23 11:06:48
depth1
children2
net_rshares0
last_payout2018-05-30 11:06:48
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length22
author_reputation20,261,270,126,211
root_title"geth 소스 읽기 Part2 Day02"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
@woojin.joe ·
부족한 내용 잘 봐주셔서 감사합니다. :)
properties (22)
post_id49,968,389
authorwoojin.joe
permlinkre-sd974201-re-geth-part2-day02-20180523t110646-20180523t194838922z
categorykr
json_metadata"{"app": "steemit/0.1", "tags": ["kr"]}"
created2018-05-23 19:48:39
last_update2018-05-23 19:48:39
depth2
children1
net_rshares0
last_payout2018-05-30 19:48:39
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length23
author_reputation131,488,838,444
root_title"geth 소스 읽기 Part2 Day02"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars0
@sd974201 ·
항상 정성글은 추천이라고 배웠습니다. ㅎㅎㅎ 다른 내용도 많이 적어주십쇼 ㅎㅎ
properties (22)
post_id50,009,649
authorsd974201
permlinkre-woojinjoe-re-sd974201-re-geth-part2-day02-20180523t110646-20180524t023743780z
categorykr
json_metadata"{"app": "steemit/0.1", "tags": ["kr"]}"
created2018-05-24 02:37:45
last_update2018-05-24 02:37:45
depth3
children0
net_rshares0
last_payout2018-05-31 02:37:45
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length43
author_reputation20,261,270,126,211
root_title"geth 소스 읽기 Part2 Day02"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
@rtong ·
와 귀한 글을 발견했네요.
자바 기반 글 찾기가 왜 이렇게 힘든지,
잘 보겠습니다.
properties (22)
post_id49,904,583
authorrtong
permlinkre-woojinjoe-geth-part2-day02-20180523t113019746z
categorykr
json_metadata"{"app": "steemit/0.1", "tags": ["kr"]}"
created2018-05-23 11:30:18
last_update2018-05-23 11:30:18
depth1
children1
net_rshares0
last_payout2018-05-30 11:30:18
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length46
author_reputation22,444,560,782
root_title"geth 소스 읽기 Part2 Day02"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
@woojin.joe ·
블록체인도 관심있고 고 언어도 알고 싶어 겸사 겸사 분석하면서 이렇게 글을 쓰고 있네요 ^^
properties (22)
post_id49,968,470
authorwoojin.joe
permlinkre-rtong-re-woojinjoe-geth-part2-day02-20180523t194927489z
categorykr
json_metadata"{"app": "steemit/0.1", "tags": ["kr"]}"
created2018-05-23 19:49:30
last_update2018-05-23 19:49:30
depth2
children0
net_rshares0
last_payout2018-05-30 19:49:30
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length51
author_reputation131,488,838,444
root_title"geth 소스 읽기 Part2 Day02"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars0