libplanet
libplanet copied to clipboard
인수인계 체크리스트
- [x] 다른 노드에서 논스 리스트를 얻어와서 현재 스토어와 비교가능
- [x] GraphQL 쿼리 9c headless에 작업
- [ ] 환경구성(논스깨뜨려놔야함)
- [ ] volume 붙일수있는 도커 이미지(립플래닛툴, 복구 스크립트포함)
- [ ] 해당 이미지로 스크립트를 통해 논스 복구 성공
- [x] 노드 실행시 스테이트 pruning 과정 추가하기
- [x] 이건 잘 모르겠어서 조사 필요함
- [x] regensis 관련 조사(뭘해야하는지)
- [x] 이슈화 및 제네시스에 인덱스 넣는거 유닛테스트 넣어서 PR?
- [x] 엄밀한 Truncate 조사
- [x] 이슈화 및 PR?
- [x] 구조 정리
- 노드 실행 이후 블록 하나 찍힌 이후 그게 전파 될 때까지의 프로세스
- 스토리지(스토어) 구조
- [ ] 메모리 누수 원인 - 이미 시도해본것들
엄밀한 Truncate 관련 조사
- IStore에 Block index DB를 조작하는 기능을 넣어, 블록만을 깎는 것은 가능함
- 동시에 기타 체인데이터들도 조작하여 깎아줘야 함
- BlockCommit : Tip을 깎는 와중에, 타겟 인덱스의 다음 블록에서 LastCommit값을 읽어온 뒤, 이 값을 BlockCommit으로 교체함으로서 정합성이 맞도록 할 수가 있음
- Nonce : Tip을 하나씩 깎아나가며, 트랜잭션들을 돌며 논스를 깎아나가는 방식으로 정합성이 맞도록 할 수 있음
- Evidence : 만료된 증거들은 유실되기 때문에, 정합성을 확보할 수 없음
일단 Swap으로 블록커밋에 대해서만 고친 PR 올려두었습니다
Regenesis
- 현재 있는 Index - Count와 매칭을 해제하는 것은 스토어와 체인에서 동작의 정합성 체크를 많이 제거해야 함. 따라서 리스크가 큼.
- 구현의 폼이 매우 큼
- 따라서 제네시스에 인덱스를 설정하는것보다, 체인을 리셋 할 때마다 State에 genesisIndex 상태를 넣은 뒤, 인덱스를 참조하는 로직에서
GenesisIndex + context.Index이런식으로 계산하게 하면 어떨까 제안.
Truncate는 사용용도가 InvalidBlockStateRootHashException 대비용임
메모리 누수 관련 해본일
- 락스DB캐시사이즈 조절(효과없음)
- liveness_probe 메모리 포트를 찌르다 문제가 발생함(적용함)
- AEV?
안쓰이는 Legacy state를 Null로 셋해주는 어드민 액션?
논스가 깨졌을 때, 논스를 붙이는 방법은 아래와 같습니다.
논스가 깨지는 이유
블록을 붙이는 과정은
- 블록을 받아서 저장한다(https://github.com/planetarium/libplanet/blob/a1740886bc7424f7cb23088e6a65feb7968df6ba/src/Libplanet/Blockchain/BlockChain.cs#L869)
- 논스를 올린다 (https://github.com/planetarium/libplanet/blob/a1740886bc7424f7cb23088e6a65feb7968df6ba/src/Libplanet/Blockchain/BlockChain.cs#L873)
- 팁의 인덱스를 올린다 (https://github.com/planetarium/libplanet/blob/a1740886bc7424f7cb23088e6a65feb7968df6ba/src/Libplanet/Blockchain/BlockChain.cs#L896)
블록 B를 붙이다가, 트랜잭션 T의 논스 N이 깨졌을 때 으레 나타나는 메시지는 아래와 같습니다.
Transaction T has an invalid nonce N that is different from expected nonce N+1.
이렇게 되는 시나리오는 아래와 같습니다.
"B번 블록을 받아서 저장하고, 논스를 올리던 중 작업이 중지" 따라서 이 때, 팁의 인덱스는 증가하지 않은 상태입니다(여전히 B-1). 다만, 논스는 이미 N을 받아 N+1으로 증가했습니다.
이 상태에서 체인이 내려갔다가 올라오게 되면 체인은 다시 블록 B부터 붙이려 합니다. 그런데, 블록 B의 트랜잭션 T에 적힌 논스는 N인데, 이미 체인은 N+1을 바라보고 있기 때문에 위와 같은 메시지를 내며 터지게 됩니다.
이는 블록이 붙는 전 과정을 atomic하게 처리한다면 해결될 수 있는 문제입니다.
당장 땜질로 이 문제를 해결하려면,
-
붙이다가 터져버리는 블록(이전에 붙이던 블록을 다시 붙이기 때문에, Tip + 1 인덱스의 블록이자, Trying to Append Block #에서 지정하고 있는 블록입니다)의 인덱스에 대하여 작성된 헤들리스 쿼리를 실행합니다.
-
체인의 어드레스별 논스들을 해당 쿼리에서 얻은 값들로 덮어씌웁니다. 이 때, libplanet.tools의 set-tx-nonce 커맨드를 이용합니다(https://github.com/planetarium/libplanet/blob/43a58ed17be69dd63aa48fbf0cfb0b4f5a54882f/tools/Libplanet.Extensions.Cocona/Commands/StoreCommand.cs#L183-L205) 상세 방법은 해당 노션 페이지에 설명되어 있습니다 (https://www.notion.so/planetarium/Libplanet-1deed889905f801188f9e806c352ed2f)
=> 해결되었습니다.
https://github.com/planetarium/libplanet/wiki/Block-life 블록이 만들어지고 전파되는 과정에 대한 설명을 추가하였습니다. 혹 상기 내용으로 정보가 부족한 부분이 있다면 알려주시면 보완해보겠습니다.
합의 과정에서 NetMQTransport가 어떤 식으로 쓰이는거냐고 물어보셨던 기억이 있어서... 사실 이 부분은 따로 위키에 적기에 애매한 것이 모든 노드간 메시지 통신은 ITransport를 통해서 이루어집니다. (Swarm이건, ConsensusReactor이건) 따라서 메시지를 주고받는다는 모든 부분들에는 트랜스포트가 사용되기 때문에 별개로 적기가 좀 애내한 부분이 있습니다. 이를테면, https://github.com/planetarium/libplanet/wiki/Swarm-%EC%83%81%EC%84%B8#broadcastblockasync 링크에 소개된 Swarm의 BroadcastBlockAsync는 아래와 같이 트랜스포트를 사용하여 메시지를 전달합니다. https://github.com/planetarium/libplanet/blob/2f8dac93d6ff24f8d9e6d2343460ac95f9a1b8e4/src/Libplanet.Net/Swarm.cs#L1120-L1128 https://github.com/planetarium/libplanet/blob/2f8dac93d6ff24f8d9e6d2343460ac95f9a1b8e4/src/Libplanet.Net/Swarm.cs#L1137-L1142 모두 이런 식이라 하나하나 열거하기는 좀 애매하고...메서드 이름대로 작동한다고 기대하고, 직접 코드를 따라가시는 편이 좀 더 이해하기 편하실 것 같습니다.