혼자서 자잘하게 컨트랙트와 web을 연동하여서 끄적인 적은 있지만 내놓기 부끄러운 수준이었다.
물론 부끄러운 수준이지만 그래도 고민다운 고민을 해보고 그나마 dApp이라고 말할 수는 있을 첫 프로젝트에 대한 회고를 작성해보려 한다.
약 한달간 진행되었고 팀원은 프론트엔드 1명, 백엔드 2명이서 진행했다.
원래 프론트엔드 1명, 백엔드 3명이서 진행하려 했으나 프론트엔드를 맡은 분이 탈주를 해버려서....
결국 백엔드 한 분이 희생하여 프론트엔드를 맡아주셨다. 정말 감사하게 생각하고 덕분에 프로젝트를 완수할 수 있었다.
직접 언급하진 않겠다만 시중에 있는 블록체인 DID 프로젝트들은 대부분 인프라 블록체인, 프라이빗 블록체인에서 구현되어 있다. 하지만 이러한 환경은 블록체인의 본질과는 조금 다르다고 생각하였고, 퍼블릭 블록체인 환경에서의 DID를 구현해보고자 DID 기술을 활용하여 프로젝트를 진행하였다.
이 프로젝트를 진행하기에 앞서 계획서 작성을 꽤나 열심히 했다.
내가 기획하는 프로젝트였기에 후회하지 않기 위해 열정 넘치고 훌륭한 팀원들을 모으고 싶었다.
그러기 위해선 당연히 팀장인 내가 솔선수범해야했다.
만들 필요는 없었지만 나의 열정을 보여주기 위해 PPT기반으로 30장짜리 계획서를 작성하였고 이로 팀원을 모집하였다. 지금 다시 보니 배보다 배꼽이 큰 것 같기도...
그래도 덕분에 좋은 팀원들과 의미있는 프로젝트를 진행할 수 있어서 좋았다 ㅎ
팀장으로서 프로젝트를 기획하고 SmartContract 작성과 Deploy 부분을 맡아서 진행했다.
Deploy파트는 팀에 계신 백엔드 현직자분의 오더를 내가 구현하는 식이었다.
(첫 배포였는데 덕분에 많이 배워갔습니다.ㅎㅎ)
DIDNOW는 블록체인을 활용한 인증서 관리 플랫폼이다.
시연 영상 : https://youtu.be/z9BfNxf1GaI
GitHub : https://github.com/donggni0712/DIDNOW
서비스를 만들기 위해서는 '정책'을 잘 정해야 한다.
보안을 중시할 것이냐. 성능을 중시할 것이냐.
우리 팀은 보안을 중시하기로 했었다.
VC를 개인이 보관하도록 하면 편의성이 떨어지기 때문에 IPFS에 보관해놓기로 결정했었다.
DB에 보관할 수도 있지만 그렇게 되면 중앙화되어있기 때문에 탈중앙화시키고 싶었다.
하지만 IPFS에 있는 데이터는 누구나 열람이 가능하다. 이를 방지하기 위해 암호화를 2번 진행하였다.
비밀키암호화로 디지털 서명을 하여 소유권을 증명하였고
공개키암호화로 다른 사람이 VC를 읽지 못하도록 하였다.
허나 발급한 VC의 길이가 길어지면서 암호화에 필요한 키보다 긴 문자열은 암호화를 할수가 없었다...!
1300Byte가 넘는 VC를 암호화하기 위해 350Byte씩 쪼개서 구현하였는데...
사실 길이가 긴 건 괜찮다.
근데 근데 이렇게 되면 1300byte가 약 네 개의 파트로 쪼개지는데 이를 두 번의 암호화와 두 번의 복호화... 한번 등록하고 확인하는데 Response Rate가 6000ms를 넘어가버렸다.
IPFS와 백엔드가 파일을 주고받다가 탈취되어도 데이터는 공개되지 않고, IPFS에 보관하기 때문에 위변조될 일도 없었다. 하지만 느렸다.
보안을 중점적으로 다룬 결과였다.
결국 엎기로 했다.
VC를 IPFS가 아닌 DB에 보관하기로 하였고 탈취, 해킹 등의 보안 이슈의 가중치를 조금 낮췄다.
결과는 성공적이었다. 공개키 암호화과정은 불필요해졌고, Response Rate를 6000ms에서 2000ms까지 줄일 수 있었다.
아 물론 탈취되는 걸 그냥 보고만 있을 건 아니다.
DB보안을 강화하기 위해 NginX Reverse Proxy Server를 구현하였고 MongoDB Atlas Network Access권한을 축소하였다.
조금 무리하다고 생각할 수도 있는 부하를 테스트해봤다. Artillery를 사용해 1초에 8명이 동시접속하는 상황을 1분간 진행하며 테스트하고 확인했다. 시나리오는 아래와 같았다.
1. Holder 로그인 (5초 대기)
2. Holder가 Issuer에게 VC를 요청 (5초 대기)
3. Holder가 VP를 생성 후 Verifier에게 인증 요청
한 유저당 3개의 요청, 1초에 8명, 1분간 진행. 대략 1300개의 response가 나와야하는 상황이지만 900개 가량의 response만 정확했다.
블록 생성주기를 감안해도 klaytn의 블록생성 주기는 1초이므로 문제가 없어야하는 상황이었다.
이를 해결하기 위해 배포를 담당했던 나는 우선 NginX를 활용해 로드밸런싱을 진행하여 트래픽을 분산했다. 로드밸런싱을 진행하며 MSA도 진행하긴 했지만 추후 더 공부해보니 MSA는 트래픽분산보다는 유지/관리에 더욱 초점이 맞혀져 있는 것 같았다. 물론 명확한 정의라는 게 애매하다보니 어떻게 구현하느냐에 따라 다를 것 같기는 하다.
또 비동기 메소드로 구현하여 데이터가 늦게 들어오더라도 처리가 가능하도록 하였고 블록체인에 데이터를 입력하는 부분에 사용되는 데이터양을 최대한 줄였다. 데이터의 길이가 길어지면 데이터가 loss될 수 있을 것이라는 생각에서 착안된 방안이었다.
이러한 방식들로 전보다는 개선되었지만 드라마틱한 효과를 보지는 못했다. 한 달이라는 기간이 있었고 마무리를 해야했기에 프로젝트는 이정도까지 진행됐었다.
프로젝트가 끝나고 어언 2달... 이제야 드는 생각이지만 백엔드에서 서명을 하는 방식으로 테스트를 진행했기 때문에 nonce가 겹치진 않았을까 하는 생각도 든다. 따로 테스트 한번 해보고 포스팅하도록 하겠다.
이런 생각 하는 나... 조금은 성장했을지도?
DB가 손상되는 경우를 대비해 백업 DB는 필수적이다.
EC2 서버에서 crontab을 사용하여 주기적으로 DB를 백업하도록 설정하였다.
또 시스템 장애에 대비하기 위해 MongoDB Atlas에서 제공되는 Primary + Secondary 2개로 구성된 레플리카 셋을 사용하였다.
배포를 자동화하였습니다. main branch에 commit이 발생하면 trigger가 이를 캐치하여 build하여 image를 만들어 registy에 등록하고 EC2에 설치된 github runner를 통해 deploy합니다.
AWS Certificate Manager와 Route53을 활용하여 SSL인증서를 등록하고 HTTPS를 적용하였습니다.
Nginx에 gzip 옵션을 사용해 데이터를 압축하여 서버의 성능을 끌어올리려고 노력하였습니다. 서버 성능은 미미한 향상도 큰 의미가 있다고 생각하였고 이 성능을 조금이라도 향상시키기 위해 데이터를 압축하여 통신하도록 하였습니다.
스마트 컨트랙트에도 Proxy Model이 있다는 것을 알았고 Openzeppelin에서 제공하는 오픈 소스로 Eternal Storage Proxy
를 구현하였다. 아래 그림처럼 외부에서 입력을 받는 EternalStorageProxy
컨트랙트가 있고 실제 로직을 처리하는 Logic Contract
가 따로 존재한다.
아래 그림은 프로젝트를 배포한 후 스캐너를 확인한 모습인데, EOA 지갑으로 프록시 컨트랙트를 호출하면 프록시 컨트랙트가 LogicContract를 호출하여 함수를 실행하는 식으로 작동한다.
일반적은 스마트 컨트랙트는 한번 배포하면 수정될 수 없다. 해당 컨트랙트 주소에 해당하는 내용은 불변인 것이다. 그렇다면 후에 버그가 발견되거나 업데이트를 해야하는 경우 주소를 통채로 바꿔줘야하는 불편함이 따른다. 그렇기 때문에 업데이트를 편리하게 하기 위해서 Proxy Model이 사용된다. 이를 사용하면 주소를 업데이트해줌으로써 간단하게 스마트 컨트랙트를 업데이트할 수 있다.
이건 내가 면접에서 받았던 질문이다. 그러게요 왜 안쓸까요.
뭐야 Proxy Model 개꿀이네! 그럼 다 Proxy Model쓰지 왜 안 씀!
일단 가스비가 더 든다. 함수를 더 많이 호출하는 꼴이고 당연히 OPCode가 길어지면서 가스비가 증가한다.
그리고 업데이트가 가능하다는 것을 장점이라고 보지 않는 입장도 많다. 블록체인은 위변조가 되지 않아야 하는데, 업데이트가 가능하다는 말은 위변조가 가능하다는 말이지 않나.
맞는 말이다. 고민해볼 필요가 있는 것 같다.
요즘 블록체인 기술이 그런 것 같다. 탈중앙성, 위변조의 불가능, 익명성 등등 다양한 장점들때문에 대두된 기술이 이제는 역으로 중앙화되고 위변조도 가능하게 하려고 하고 익명성도 제한하려한다.
Klaytn은 조금 특이한 기능을 제공한다. 바로 수수료 대납
이다.
사용자가 수수료를 직접 내도록 하면 서비스에 대한 거부감이 생길 수 있을 것이라고 생각하여 DelegateFee를 적용하여 서버 측에서 수수료를 대신 지불할 수 있도록 구현하였다.
아쉽다면 아쉽고 보람차다면 보람찬 한 달간의 프로젝트가 끝났다.
훌륭한 팀원들을 만나 잘 몰랐던 기술에 대해서도 접하고 구현해볼 수 있었다.
사실 이 글을 작성하는 시점이 프로젝트가 끝나고 2달 후라서 또 약간의 심경변화도 있는 듯 하다.
프로젝트를 막 마쳤을 때는 DID뿐 아니라 NFT, DAO, M2E 등 다양한 dApp을 개발해보고 싶었다. DIDNOW는 기능의 다양성보다는 기술의 완성도에 초점을 둔 프로젝트였다. 덕분에 많은 것을 배웠고, 앞으로의 사이드프로젝트들도 이러한 방향으로 진행하고 싶다.
물론 기능도 많고 완성도도 있으면 좋겠지만...! 그건 사이드 프로젝트가 아니라 그냥 대규모 프로젝트니...
그리고 2달이 지난 지금보니, 문제 해결의 방향성이 조금 틀린 부분들도 있는 것 같다. 예를 들면 블록체인 데이터가 유실되는 것을 해결하기 위해 트래픽을 분산했다던가... 조금 다른 방향으로 접근해보고 싶다. 이 부분은 속히 테스트해보고 포스팅해보도록 하겠다 ㅎ