Nonce
블록체인 서비스를 개발하는데 있어서 중요한 역할을 합니다.
논스를 알기 위해서 Tx
을 알아야 합니다.
Tx
: 일종의 사용자의 요청(송금을 한다. 블록체인 위에서 동작하는 스마트 컨택트를 실행하는데 사용)
Nonce
: 대기표라 생각할 수 있습니다. Nonce는 Tx를 처리하기 위해 순서를 정해줍니다.
1. "철수에게 200원 송금 - 2"
2. "영희에게 100원 송금 - 1"
3. "릭에게 10000원 송금 - 3"
4. "영희에게 100원 송금 - 4"
각각의 트랜잭션의 논스를 지정하게 되면, 2번
1번
3번
4번
순으로 진행될 것입니다.
Klaytn에서는 노드가 서로가 연결되어 있습니다. 연결된 노드에게 Tx를 전파합니다.
노드가 Tx를 담아 블록을 생성하는데 어떤 노드에서 블록을 생성하는지 모르니 최대한 Tx를 모든 노드에게 전파해야만 빠르게 Tx가 처리 될 수 있습니다.
블록체인은 일종의 글로벌 디비입니다. Tx를 담아 블록을 생성하면 Tx의 내용이 디비에 반영됩니다.
사용자의 어떤 요청이 A노드가 받게 되면, 노드는 연결된 B, C에게 Tx를 전파합니다.
노드는 Tx를 받게되면, 다시 서로 연결 되어 있는 B, C에게 전달합니다.
모든 노드는 같은 Tx를 공유하게 되는데, 이 때 각 노드들이 블록을 한 번씩 생성한다면, 동일한 Tx가 3번 반영되게 됩니다.
노드는 이미 Tx가 처리된건지 안된건지 알 수가 없기 때문에 모든 블록에 Tx를 적용하여 생성하게 됩니다.
1. "철수에게 200원 송금"
2. "영희에게 100원 송금"
3. "릭에게 10000원 송금"
4. "영희에게 100원 송금"
만일 nonce
가 없다면 2번
4번
은 내용이 같이 때문에 구분할 수 없습니다. 모두 처리해줘야 합니다.
nonce
는 순서를 정해주고 이미 처리된 Tx인지 아닌지 구분해주는 역할을 할 수 있습니다.
nonce
에는 크게 2가지 법칙이 적용됩니다.
어렸을 때 한 번씩 했던 도미노를 생각해보겠습니다.
1번이 쓰러지면 2번이 쓰러지고 ... 차례대로 쓰러질 것입니다.
만약 3번째가 없다면, 2번째까지만 쓰러질 것입니다.
Tx
도 똑같이 3번 nonce
가 적용된 Tx가 없다면 4번 논스가 적용된 Tx는 처리되지 않을 것입니다.
모든 nonce
는 유일해야 합니다.
동일한 nonce
을 사용하는 Tx가 있다면 한 Tx는 처리되지 않을 것입니다.
블록체인에서 Tx를 생성할 때 동일한 nonce
들을 사용해서 만들거나 이미 사용한 nonce
을 재사용하면 안됩니다.
클레이튼은 사용자가 사용할 수 있는 nonce
이미 알고 있습니다.
Tx를 만들기 전에 클레이튼에게 논스를 묻고 응답 받은 nonce
을 Tx에 적용하여 네트워크에 보내게됩니다.
그 후에, 반영이 되었는지 확인해야 합니다.
반영 확인을 하는 이유는 만일 Tx를 반영되지 않는 상태에서 nonce
을 다시 묻게 된다면 동일한 nonce
을 받게 되어 Unique Rule
에 위배 됩니다.
클레이튼은 다른 블록체인에 비해 블록을 빠르게 만듭니다.(1초에 1블록)
논스를 묻고 확인하는 과정을 갖는다면 모든 Tx를 1초의 시간이 걸리게 될것입니다.
100개의 요청을 한다면 운이 좋으면, 한 2분쯤 걸릴 것입니다.
nonce
을 묻는 과정을 제외하고 서비스 내부에서 nonce
을 저장하는 변수를 두는 것입니다.
Tx는 nonce
을 저장한 변수로부터 nonce
을 읽습니다.
그리고 해당하는 nonce
을 Tx 적용 한 뒤 전송해줍니다.
다음 요청을 처리하기 위해서 nonce
의 값을 업데이트해줍니다.
이후 계속 반복을 하게 됩니다.
일반적인 서비스에서는 많은 사용자의 처리하기 위해서 스케일 아웃
을 사용합니다.
하지만 약간의 문제 발생합니다.
서버를 2개 띄운다고 발생하면,
날리고 논스값을 업데이트 할 것이며, 계속해서 진행할 것입니다.
Unique Rule
이 발생하게 됩니다.
공용 저장소
가 필요합니다.
공용 저장소
를 사용하기 때문에 Unique Rule
에 위배되지 않고 진행할 수 있습니다.
두 서버가 동시에공용 저장소
에 접근하면 데이터 레이스
라는 문제가 발생합니다.
두 서버가 공용 저장소
동시에 접근하면 동일한 nonce
을 얻게 되어 Unique Rule
에 위배됩니다.
위의 문제를 해결하기 위해서 Redis INCR 명령
을 사용
값을 순차적으로 증가시키고 1을 반환해줍니다.
key값을 해당하는 변수를 1씩 증가시켜줍니다.
이 명령을 atomic 해서 순차적으로 처리해줍니다.
서버가 죽어서 nonce
가 1인 것이 실패하고 다른 서버가 nonce
가 2인 것을 보내게 된다면 Domino Rule
에 위배됩니다.
그래서 실패한 Nonce를 재활용
하게 됩니다.
우선순위 큐
를 사용하여 실패한 nonce
를 저장합니다.
실패한 nonce
가 있다면 우선순위 큐에서 뽑아서 사용하고 우선순위 큐가 비어있다면 INCR 명령
을 사용합니다.
우선순위 큐
는 레디스의 Sorted Sets을 이용하면 쉽게 구현이 가능합니다.
문제가 생기는 이유들은 Tx를 서비스에서 생성하고 관리하기 때문입니다
(https://if.kakao.com/session/45)