안녕하세요, 세계 최초 EOS 기반 탈중앙화 거래소 DEXEOS의 개발자 Lecko 입니다.
최근 blocktwitter라는 계정이 EOS 네트워크에 지속적으로 트랜잭션을 만들면서 대부분의 EOS 기반 dApp들이 동작하지 않는 현상이 발생했습니다. 이는 blocktwitter로 인해 EOS 네트워크의 CPU limit이 급감했기 때문인데요. 이로인해 이오스나이츠, 다이스 등의 dApp을 즐기시던 분들은 큰 불편을 겪으셨습니다.
이러한 문제의 원인은 무엇이었을까요? 또 해결할 방법은 없는걸까요?
오늘은 EOSIO 소프트웨어가 한 계정의 CPU Max Limit을 어떻게 계산하는지를 알아보고 이를 통해 해결책을 알아보는 시간을 갖겠습니다.
여러분도 내가 CPU/NET 리소스를 얼만큼 가지고 있는지를 보기 위해 블록 익스플로러를 보신 적이 있으실 겁니다.
그런데 보시다시피 새록고침 할 때마다 추가 스테이킹을 하지 않았음에도 최대 사용 가능량이 계속해서 바뀝니다!?
왜 그런걸까요?
검색해봐도 관련된 설명이 나오지않아 EOSIO의 소스코드를 직접 열어봤습니다.
EOSIO의 CPU Max Limit 측정 방법
사용되는 변수
- window_size = 24x60x60x1000 / 500 (고정값)
- 즉 2x24x60x60
- virtual_cpu_capacity_in_window
- = virtual_cpu_limit x window_size
- = virtual_cpu_limit x 2x24x60x60
- user_weight = 유저의 cpu에 스테이킹한 EOS
- all_user_weight = 모든 유저의 CPU 스테이킹한 EOS
계산식
CPU의 Max Limit = (virtual_cpu_capacity_in_window x user_weight) / all_user_weight = virtual_cpu_limit x 2x24x60x60 x user_weight / all_user_weight = virtual_cpu_limit x 172800 x (전체 CPU 스테이킹 대비 내가 CPU에 스테이킹한 비율)
즉, 총 스테이킹과 내가 스테이킹한 양이 변하지 않는다면, 위처럼 새로고침했을 때 CPU 최대 사용 가능량이 바뀌는 이유는 virtual_cpu_limit 때문이라는 것이 됩니다.
virtual_cpu_limit 구하기
https://api.eosnewyork.io/v1/chain/get_info 에 접속하면, 아래처럼 현재 virtual_block_cpu_limit의 값을 확인하실 수 있습니다.
새로고침하면 이 값이 계속 변경되는 것을 확인하실 수가 있는데요.
아! 그렇습니다. 이제 왜 CPU 최대 사용 가능량이 계속 변경되는지 알 것 같군요.
virtual_cpu_limit 때문이었습니다.
virtual_cpu_limit은 한 블럭이 생산될 때마다 아래와 같은 방법으로 계산됩니다.
- 해당 블럭에 담긴 모든 트랜잭션의 리소스 사용량을 각각 더합니다.
- 리소스 사용량의 평균값을 구합니다.
- 이 평균값이 20,000 마이크로초(0.02초) 보다 크다면 -> 평균값에 99/100을 곱합니다. (즉, 감소 시킵니다.)
- 이 평균값이 20,000 마이크로초(0.02초) 보다 작다면 -> 평균값에 1000/999를 곱합니다. (즉, 증가 시킵니다.)
- 이 평균값과 20만 중에 큰 값을 선택합니다.
- 선택된 값곽 2억 중에 작은 값을 새로운 virtual_cpu_limit으로 설정합니다.
- 즉, virtual_cpu_limit의 최소값은 20만, 최대값은 2억인 것이죠.
자, 이제 blocktwitter의 무분별한 트랜잭션 발송으로 인해 우리의 CPU 최대 사용 가능량이 왜 줄었는지를 알 수 있습니다.
이 평균값이 20,000 마이크로초(0.02초) 보다 크다면 -> 평균값에 99/100을 곱합니다. (즉, 감소 시킵니다.)
한 블럭에서 실행한 트랜잭션의 실행 시간이 0.02초가 넘어가면 다음 블럭에서 사용 가능한 CPU 최대 사용 가능량이 계속해서 줄어드는 것입니다.
반대로 실행 시간이 0.02초 이하라면, 다음 블럭에서 사용 가능한 CPU 최대 사용 가능량은 다시 늘어납니다.
이 0.02초라는 시간은 어디에서 나온걸까요?
바로 max_block_cpu_usage와 target_block_cpu_usage_pct 라는 체인의 글로벌 config값을
기준시간 = max_block_cpu_usage x target_block_cpu_usage_pct / 10,000
위의 공식에 대입하여 계산되고 있습니다.
현재는 이 값이 max_block_cpu_usage는 200,000으로, target_block_cpu_usage_pct는 1,000 이라는 기본 값으로 설정되어 있는데요, 때문에 200,000 x 1,000 / 10,000 = 20,000 으로 즉 0.02초라는 시간이 결정된 것이지요.
이는 global config의 수정으로 늘리거나 줄일 수 있는 값입니다.
즉, 이번 blocktwitter 사건의 경우, 대비를 위한 방책은 사실 존재했지만 EOSIO 소프트웨어에 대한 이해도의 부족으로 인해 발생한 문제라고 할 수 있겠습니다.
저는 이를 eosio 소프트웨어 자체에 대한 Document(문서화)가 부족하기 때문이라고 생각합니다.
때문에 이번 일을 계기로 관련 EOSIO 소프트웨어에 대한 전문성을 확보해야할 뿐만 아니라 이러한 자료를 함께 공유하고 배워야한다는 교훈을 얻을 수 있었습니다.
이처럼 앞으로도 많은 문제가 나올테지만, 이러한 문제들을 극복하면서 EOS는 더욱 더 발전할 것입니다.
+추가
CPU Max Limit 의 최솟값:
200,000 x (2x24x60x60) x (내스테이킹)/(총스테이킹)
CPU Max Limit 의 현재값:
(chain_info에 나오는 virtual_cpu_limit) x (2x24x60x60) x (내스테이킹)/(총스테이킹)
CPU Max Limit 의 최댓값:
200,000,000 x (2x24x60x60) x (내스테이킹)/(총스테이킹)
심플하게는 위에 근거하여,
내스테이킹: 1만
토탈스테이킹: 3억
이라는 가정하에 메인넷의 상태에 따라서
CPU 대역폭을 최소 1.152초~최대 1152초(약 20분) 라는 값을 얻을 수 있습니다.
감사합니다.
( 국내 BP인 EOSEOUL에서 잘못된 수치를 정정해주셨습니다 :D 감사드립니다! )
좋은 분석 글 잘 읽고 갑니다
한가지 궁금한 것은 global config 값을 변경하는 것도 bp 간 합의에 의해 이루어지는 것인가요?
왜 그랬을까 너무나 궁금했던 바로 이 것!!!
장롱 스팀 계정을 후다닥 로그인 해서 덧글이라도 꼭 남기고 싶었을만큼 감사한 글입니다. 앞으로도 계속 계속 반짝반짝 빛나시길 응원하고 기원합니다 ^^*
감사합니다, 덱시오스~!
분석 잘 하셨네요... 잘 읽고 갑니다.
Config 값을 잘못해서 너무 크게 늘리면 다량의 미싱블록이나 심하면 마이너 포크가 날 수도 있습니다. 저도 해당 부분을 좀 더 세심하게 공부해봐야겠네요.
저도 의문을 가졌는데
이런 이렇게 답을 알려주세셔
감사합니다.