지난 글 “텐더민트 합의에 3단계가 필요한 이유”에서 텐더민트 합의 과정을 Propose-Vote 2단계로 줄일 경우 safety에 문제가 발생함을 확인하였다. 그렇다면 Propose-Prevote-Precommit 3단계로 진행하면 safety 문제가 해결될까? 이번에도 예시를 통해 살펴보자.
이번에도 다음과 같이 N1, N2, N3, N4 4개의 노드가 합의를 하는 상황을 가정해보자. 노드 N1이 라운드 R1에서 블록 B1을 제안하였다.
B1 블록이 네트워크에 전파되어 N3, N3, N4 노드도 B1 블록을 알게 되었다.
B1 블록은 정상적인 블록이므로 노드 모든 노드가 B1 블록에 대한 Prevote 메시지지를 만들어 보낸다.
N2 노드는 네트워크 오류로 다른 노드의 Prevote 메시지를 받지 못하였고, N1, N3, N4는 모든 노드로부터 Prevote 메시지를 받았다.
N1, N3, N4 노드는 ⅔ 이상의 Prevote를 모았기 때문에 Precommit 메시지를 만들어 보낸다.
N3, N4 노드는 네트워크 오류로 Precommit 메시지를 받지 못하였고, N1 노드만 N1, N3, N4 노드의 Precommit 메시지를 받았다.
N1 노드는 ⅔ 이상의 Precommit을 모았기 때문에 B1 블록을 커밋하였다.
타임아웃이 발생하여 라운드 R2가 시작되고 N2 노드가 블록 B2를 제안하였다.
블록 B2가 네트워크에 전파되어 모든 노드가 B2 블록을 받았다.
N3, N3, N4 노드는 N1에 B1 블록에 커밋했다는 사실을 모르므로 B2 노드에 대해 정상적으로 Prevote 메시지를 만들어서 보낸다.
N2, N3, N4 노드가 서로 Prevote 메시지를 교환하여 B2 블록에 대해 ⅔ 이상의 Prevote 메시지를 모았다.
N2, N3, N4 노드는 ⅔ 이상의 Prevote 메시지를 모았기 때문에 B2 블록에 대한 Precommit 메시지를 보낸다.
N2, N3, N4 노드가 서류 Precommit 메시지를 교환하여 B2 블록에 대해 ⅔ 이상의 Precommit 메시지를 모았다.
N2, N3, N4 노드는 ⅔ 이상의 Precommit 메시지를 모았기 때문에 B2 블록을 커밋한다.
N1 노드는 B1 블록을 커밋하고 N2, N3, N4 노드는 B2 블록을 하였기 때문에 safety가 깨졌다.
위에 예에서 볼 수 있듯이 Propose-Prevote-Precommit 3단계로 합의를 진행해도 여전히 safety가 깨지는 상황이 존재함을 알 수 있다. 이러한 상황이 발생하는 이유는 N3, N4가 이미 라운드 R1에서 B1 블록에 대해 ⅔ 이상의 Prevote를 보고 Precommit을 했음에도 불구하고 R2 라운드에서 마음을 바꿔 B1이 아닌 B2 블록에 대해 Prevote를 했기 때문이다.
노드가 Precommit을 하면 이 Precommit 메시지 때문에 다른 노드가 커밋을 했을 가능성을 생각해야 한다. safety를 보장하려면 노드가 한 번 Precommit을 하고 나면 이후 Precommit한 블록과 같은 블록에 대해서만 Prevote를 해야 하고, 리더가 되었을 때도 Precommit한 블록과 같은 블록을 제안해야 한다. 이러한 규칙을 텐더민트 락(lock)이라고 한다.
텐더민트 락을 적용해서 다시 한 번 합의를 진행해보자.
이전 시나리오와 마찬가지로 N1 노드가 B1에 커밋한 상황에서 N2가 블록 B2를 제안하였다. N2는 B1 블록에 대해 ⅔ 이상의 Prevote를 본 적이 없기 때문에 락을 잡지 않았다.
N2, N3, N4 노드에 B2 블록이 전파되었고, 각 노드는 B2 블록에 대한 Prevote 메시지를 만들려고 한다.
하지만 N3, N4 노드는 라운드 R1에 이미 B1 블록에 대해 ⅔ 이상의 Prevote를 보고 락을 잡은 상태이기 때문에 B2 블록에 대해서 Prevote 메세지를 보내지 않는다.
N2, N3, N4 노드가 B2 블록에 합의하지 못했기 때문에 다시 타임아웃이 발생하고 이번에는 N3 노드가 블록을 제안한다. N3는 R1 라운드에 B1 블록에 락을 잡았기 때문에 리더가 되었을 때도 B1 블록을 제안한다. 이후 N2, N4 노드가 B1 블록에 Prevote 및 Precommit을 하고 B1 블록으로 합의하게 된다. N1, N2, N3, N4가 모두 B1 블록에 커밋하였으므로 safety가 깨지지 않았다.
추가로 ⅔ 이상의 Prevote를 모았을 때 락을 잡기만 하고 풀지 않으면 더 이상 합의가 진행되지 않는 liveness 이슈가 생기게 된다. 따라서 라운드 R에서 ⅔ 이상의 Prevote를 보고 락을 잡았더라도 라운드 R’ (R’>R)에서 또 다시 ⅔ 이상의 Prevote를 보았다면 이전 락을 풀고 새로 락을 잡아야 한다. 이러한 특성 때문에 ⅔ 이상의 Prevote를 PoLC (Proof of Lock Change)라고 부른다.
Pingback: 텐더민트 합의에 3단계가 필요한 이유 | Kwang Yul Seo
와~ 잘 읽었습니다. 락이 안전성을 보장하는 핵심이었군요. 좋은글 감사합니다.