블록의 싱크에 관하여..

in #ethereum6 years ago (edited)

https://www.facebook.com/groups/114962092511047/permalink/182003455806910/
몇일째 블록싱크가 끝나지 않는다는 문제를 제기하신 분이 있다.
몇번을 재시작해도, fast option과 상관없이 100블록정도가 낮은 상태로.

중간정리때 까지 fetcher부분을 들여다본 적이 없어서
이글을 계기로 싱크를 조금더 자세히 들여다 보고, 글을 정리한다.

fast옵션을 잘몰라 먼저 코드를 분석해보니
fetcher에서 fast sync의 경우 블록의 정보를 받을 때 영수증 정보를 받고 거의 바로 DB에 쓰는 루틴이 있었다.
수신한 블록을 검증하면서 트렌젝션을 수행하고 상태를 갱신하고 영수증 정보를 생성하는 fullsync 보다는
확실히 일의 량이 다르더라.
(영수증을 받는다는건, 블록내용을 검증하지 않겠다는 의미이니 신뢰에 문제가 발생할수 있다.)

다시 문제로 돌아와서..
공유해주신 결과가 무엇을 의미하는지 알아야 하니까.
어떤값이 어떻게 반환된것인지 확인해본다.

eth.syncing
{
currentBlock: 5814350,
highestBlock: 5814444,
knownStates: 138981482,
pulledStates: 138972551,
startingBlock: 5812861
}

해당 리퀘스트는 eth/downloader/downloader.go 함수에서 반환되며
각필드는 아래의 변수/함수반환값을 참조한다.

currentBlock d.blockchain.CurrentFastBlock
( 현재블록: 현재 이노드가 수신중인 블록번호)
HighestBlock d.syncStatsChainHeight,
(최고높이블록: 이노드가 피어들로 부터 수신한 블록헤더중 최고 높은 블록번호)
KnownStates: d.syncStatsState.processed +d.syncStatsState.pending,
(알려진 상태: 알려진 상태 목록의 수로 처리된 상태 + 수신대기중 상태)
PulledStates: d.syncStatsState.processed,
(현재 수신 상태: 현재까지 처리된 상태 목록의 수)
startingblock d.syncStatsChainOrigin
(시작블록: 노드가 싱크를 시작한 블록번호)

fast syc에서 최고 높이 블록은 이 노드에 연결된 노드중 가장 높은 TotalDifficuty를 가진 피어의 높이이다.(Best Peer)
알려진 상태와 현재 수신상태는 Fastsync일때만 나오는 값이다.
origin은 노드의 트리를 검색해서 공통 조상을 찾게되면 설정된다.
(베스트 피어와 나의 체인이 어디까지 같은지 검색한다는 뜻같다. )

우선 패처의 다운로드 디테일을 보면
헤더는 지정된 베스트 피어로 부터만 받고,
블록과 영수증은 굳이 그럴필요가 없으니, 아무 피어에게나 받는다.
수신된 데이터는 캐시에 써지기 때문에
실제 캐시내용을 DB에 업데이트 하는 고루틴이 하나 추가된다.

흥미로운 점은 DB에 수신한 데이터를 업데이트 하는 방식인데
체인상에 피봇 포인트를 잡은후, 그 블록 번호까진 영수증까지 다받는 fast sync용 처리를 하고,
피봇 포인트이후 부터는 full sync용 처리를 하도록 동작한다.
(물론 동작중에 pivot포인트가 latest와 멀어질 경우, 다시 pivot포인트를 옮긴다.)

쉽게 설명하면 싱크를 해서 데이터를 받은것을 DB로 넣고 체인으로 넣는 작업을 할때
체인에 업데이트 되는 정보가 pivot포인트까지는 영수증까지 다 업데이트를 하고
그이후부터는 풀싱크 처럼 불록검증에 들어간다는 말이다.

우선 처음 싱크가 될때 첫 피봇포인트는 최고 높이 블록 - 64로 설정되어 시작된다.
origin + 1 부터 피봇까지 피어로 부터 데이터를 받기 시작한다.
(64블록은 full 검증하겠다는 의지 + 특정 노드의 체인을 끝까지 받으면 나쁜노드에게
악용될 소지가 있으니 )

FetcherHeaders루틴은 헤더들이 받아지면 headerProcCh 채널을통해 이벤트를 알리고
ProcessHeader 루틴에서 헤더들을 처리한다

결국 받는 루틴은 FetcherHeaders함수이니까, 조금더 자세히 들여다 본다.
우선 from에서 to 까지 헤더를 받을텐데,
192개가 한번에 처리할수 있는 헤더의 개수 max로 설정되어 있어,
max개 만큼 받고 처리하고 받고 처리하고를 반복적으로 실행하게 되어있다.

여기서 부터 소설이라 안읽으셔도 됩니다.

문제를 접근해보면

5814444 - 5812861 = 총 1583개의 블록헤더를 받을 예정이니
192* 8번을 수신하고 나머지 47개의 헤더는 full sync하고 끝날것 같은데..
현재 5814350이고, 192*8번을 하면 5814397이다.
현재 블록높이보다 큰값이 나온다

이런경우 코드상으로 예측할수 있는 가능성이
fastsync중에 청크단위 처리에서 문제가 발생되어 특정피봇지점으로 롤벡이 되고.
거기서 부터 싱크를 따라 가는 형태가 발생할 수 있다.

이런 가정이면 아무리 동기화가 끝났다고 해도 내 체인은 베스트 노드의 체인보다 짧을것이다.
이 상황에서 베스트 피어가 블록 어나운스를 했을 경우에 해당 피어랑 다시 동기화를 하게 될텐데,
많은량의 남은 체인을 수신하고 마지막 블록을 붙이는 순간에 또다른 블록 어나운스가 나온다면? 계속 동기화만 하다 끝날것 같기도하다.
결국 full sync속도가 블록 생성속도를 못따라가는?

fsMinFullBlocks 값을 설정할수 있는 포인트가 있는지 찾아pivot포인트를 좀더 latest로 땡겨서 테스트 해보고 싶다는 생각이 든다.

Coin Marketplace

STEEM 0.19
TRX 0.14
JST 0.030
BTC 60115.50
ETH 3192.77
USDT 1.00
SBD 2.45