dir : miner/worker.go
루틴 종료시 모든 이벤트 unsubscribe
defer w.wg.Done()
defer w.txsSub.Unsubscribe()
defer w.chainHeadSub.Unsubscribe()
defer w.chainSideSub.Unsubscribe()
// 현재 작업 중단
defer func() {
if w.current != nil {
w.current.discard()
}
}()
// uncle 데이터 제거 주기 설정
cleanTicker := time.NewTicker(time.Second * 10)
defer cleanTicker.Stop()
각 채널에서 이벤트, 데이터. 요청을 받고 대응하는 리액션을 실행
newWorkCh : 새로운 블록 제안 생성을 trigger. 이 채널에서 요청이 수신되면 worker는 수집한 tx를 사용해 새 블록을 생성하고, mining/sealing process 진행
for {
select {
// 새 작업 요청을 받으면 요청에 포함된 tx들을 이용해 block을 새로 생성
// 적절한 tx를 고르고 > block header를 만들고 > tx를 block body에 추가하고,
// > nonce 값을 찾거나(pow) 검증자 서명을 추가하고 (poa)
// > 네트워크로 만들어진 block을 broadcast
case req : <-w.newWorkCh:
// commit은 tx를 선택해 block에 추가하고,
// block의 검증, 체인에의 추가를 위해 broadcast하는 과정을 의미한다.
w.commitWork(req.interrupt, req.noempty, req.timestamp)
getWorkCh : 현재 작업중(생성 or 채굴 중인)인 패키지 정보 요청을 수신한다. 일반적으로 header와 (채굴자가 블록 작업을 하는데에 필요한) 다른 정보들을 포함해 응답을 준다.
// worker가 작업중인 block에 관한 정보에 대한 요청을 받았을 때 응답
// 현재 채굴중인 작업을 준다. (완성되지 않은 block도 무관)
// 보통 외부 miner들과의 소통에 이용되는데, poa에선 용도가 한정됨
case req := <- w.getWorkCh:
// 주어진 파라미터들로 block, fee 정보를 retrieve
block, fees, err := w.generateWork(req.params)
req.result <- &newPayloadResult{
err: err,
block :block,
fees: fees
}
chainSideCh : side chain, uncle을 수신, 나중에 이를 canonical block에 추가한다.
case ev := <-w.chainSideCh:
// ...중략 (poa는 side chain 없음)
txsCh : 개별 txs들을 수신하는데 사용된다. tx가 수신되면 worker는 local state를 업데이트하고,
모인 tx들은 나중에 newWorkCh에서 블록 생성시 투입된다.
// 새로운 tx를 받았을 때
case ev := <- w.txsCh:
// sealing 중이 아니라면 tx를 pending state로 apply
// tx중 일부는 중복될 수도 있지만 나중에 알아서 제거된다.
if !w.isRunning() && w.current != nil {
// 이미 해당 block에서 가용한 가스를 전부 사용했다면 tx를 처리하지 않음
if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas {
continue
}
// address - trasaction type을 k-v 쌍으로 같는 매핑 생성
txs := make(map[common.Address]types.Transactions)
// tx를 순차적으로 추가
for _, tx := range ev.Txs {
acc, _ := types.Sender(w.current.signer, tx)
txs[acc] = append(txs[acc], tx)
}
txset := types.NewTransactionsByPriceAndNonce(...)
tcount := w.current.tcount
// tx들을 순차적으로 처리 (상태 반영, receipt 회수)
w.commitTransactions(w.current, txset, nil)
if tcount != w.current.tcount {
w.updateSnapshot(w.current)
}
} else {
// clique, dev mode가 아니라면 여기에선 아무것도 하지 않음
}
// 새로운 tx들의 수를 반영
atomic.AddInt32(&w.newTxs, int32(len(ev.Txs)))
// ...
}
}
newWorker()