이전 포스팅에서 TestRPC 블록체인에 컨트랙트를 발행하는 것에 이어서 진행하겠습니다.
이전 포스팅 내용을 다시 보고 싶다면, '다시보기'를 클릭해주세요.
다시 Spring Boot 로 돌아와서 /src/main/resources/static 경로에 js 폴더를 만들고 script.js 라는 파일을 생성합니다.
그럼 JSP 에서 경로 설정 시 다음과 같이 추가해주면 되겠습니다. 또한 js 파일에서 web3.js 이라는 라이브러리를 사용하기 위해 해당 구문을 추가해줍니다.
web3.js ?
web3.js 는 Ethereum Compatible JavaScript API 로 이더리움과 자바스크립트 간 호환이 가능하도록 기본적인 기능 또는 여러 함수들을 묶어 놓은 라이브러리 입니다. web3.js 는 자바스크립트 기반으로 dApp 이나 서비스를 구현할 때 매우 유용하며 실질적으로 JSON RPC API 와 함께 이더리움의 표준 api 로 보여지고 있습니다.
다시 script.js 파일로 돌아가서 상단에
두 줄을 작성합니다. contract_address 와 abi 는 각각 조금 전에 컨트랙트 발행 시 생긴 컨트랙트 주소 와 abi 입니다.
그 후 web3 객체를 설정합니다. web3 를 지원하는 브라우저(크롬 등)의 경우 자동으로 가져오게 되며, 지원하지 않는 브라우저(익스플로러 등)는 직접 설정을 해주어야 합니다.
자세한 것은 https://github.com/ethereum/web3.js/ 를 참고하시면 되겠습니다. 저는 크롬의 메타마스크를 사용하기 때문에 그 계정의 정보를 가져오게 됩니다. 그리고 web3.eth.contract(abi) 문을 사용하면 이더리움 블록체인에서 스마트 계약을 쉽게 처리 할 수 있습니다. 새 컨트랙트 객체를 만들면 스마트 컨트랙트의 json 인터페이스를 제공하고 web3 는 모든 호출을 RPC를 통해 저수준 ABI 호출로 자동 변환합니다. 이를 통해 스마트 컨트랙트를 JavaScript 객체처럼 상호 작용할 수 있습니다. 그 컨트랙트 객체에 .at(contract_address) 를 설정해주면 해당 주소의 컨트랙트에 접근할 수 있습니다.
web3.eth.getAccounts 는 현재 접속된 계정, 여기서 크롬의 메타마스크에 로그인된 계정이 불러오게 됩니다. web3.eth.getBlockNumber 는 현재 블록체인의 마지막 블록의 번호를 가져옵니다. web3.eth.getBlock 는 현재 블록체인의 마지막 블록의 정보들을 가져옵니다. 추가적으로 https://web3js.readthedocs.io/en/1.0/web3.html 에서 web3.js 의 API 를 확인하실 수 있습니다.
아래의 voting.getVoter 구문은 블록 내부에 아까 전에 제가 작성했던 컨트랙트에 접속하는 부분입니다. voting 은 위에서 설정한 스마트 컨트랙트의 객체입니다. getVoter 함수는 아까 작성한 컨트랙트의 함수였습니다.
이 함수는 투표자의 투표 여부를 확인하는 함수이며 리턴 값이 TRUE / FALSE 이기 때문에 둘 중 하나의 값이 넘어오게 될 것입니다. 만약 투표가 된 계정인 경우 TRUE 값이 넘어오게 될 것이며, 투표 시 해당 후보자의 이름도 컨트랙트에 저장할 수 있게 해놨었기 때문에 후보자의 이름도 voting.getCandidate 함수를 실행하게 됩니다.
candidates 에 자신의 계정(msg.sender)을 key 값으로 하여 해당 value 값을 불러오게 됩니다. 값을 받아오는 것은 콜백함수로 처리를 하게 되며 function(e, r) 에서 e 는 에러 발생시, r 는 성공시 리턴되는 데이터 값을 뜻합니다.
setVote 는 투표하는 함수입니다. 화면에서 해당 후보자의 투표 버튼을 누르게 되면 실행을 하게 됩니다. 만약 메타마스크를 로그인하지 않았거나 투표를 한 경우에는 실행을 할 수 없게 설정을 했습니다. voting.setVote 는 인자로 후보자의 이름과 gas 를 설정합니다. 인자를 넣어주어야 하는 이유는 컨트랙트 setVote(string name) 이 있기 때문입니다.
이때 인자 값이 여러 개로 되어 있는 함수의 경우 스크립트에서 순서대로 값이 대입이 되어버리기 때문에 유의해야 합니다. 그리고 인자의 개수가 맞지 않으면 오류가 발생합니다.
gas 값을 적어주는 이유는 트랜잭션이 발생하게 되면 비용을 지불하여야 하기 때문입니다. 만약 gas 를 설정하지 않을 경우 네트워크 환경에 따라 자동으로 값을 추정해주지만 그 값이 맞지 않는다고 오류가 발생하는 경우가 있으므로 직접 설정을 해주었습니다.
그 후 이 메타마스크 팝업 창이 자동으로 뜨게 되며 승인을 눌러 요금을 지불합니다.
성공적으로 요금 지불을 마쳤을 경우 candidate 에 자신의 계정(msg.sender)을 key 값으로 하여 받아온 후보자의 이름은 value 로 저장합니다. 또한 콜백함수에 결과 값으로 이 함수는 컨트랙트 내 상태변수 값을 변경하게 되므로 트랙잭션이 발생이 되었으므로 트랜잭션 ID 값이 반환됩니다. 트랜잭션 ID 값 반환도 성공적으로 마치면 ajax 구문을 통해 Controller 로 값을 넘기게 됩니다.
ajax 에서 요청 url 을 /vote 로 설정하였기 때문에 Controller 에서 @RequestMapping (value="/vote") 가 있는 곳으로 연결됩니다. 이 때 method=RequestMethod.POST 를 설정해주지 않으면 기본적으로 GET 방식으로 세팅이 됩니다. 여기서 mVotingMapper 는 VotingMapper 인터페이스의 객체입니다.
VotingMapper.java 의 모습입니다.
VotingMapper.xml 파일의 모습입니다.
VotingMapper.java 의 메소드들은 xml 파일 내부의id 값들과 일치하는 것을 가져오게 됩니다.
이 과정을 거치게 되면 DB 에 VOTERS 테이블에 투표자의 계정, 투표한 후보자, 투표시 발생한 트랜잭션 ID 값을 저장하게 됩니다. 또한 CANDIDATES 테이블에 해당 후보자를 찾아 VOTE 컬럼(득표 수)에 +1 을 시켜줍니다.
DB 는 현재 이렇게 간단하게 구성되어 있습니다. candidates 는 후보자들의 리스트이며 득표 수를 저장하는 컬럼이 있습니다. voters 는 투표자들의 리스트이며 투표 시 자신의 계정, 후보자의 idx 값, 발생한 트랜잭션 ID 값을 저장해야 합니다. 여기서 굳이 데이터 베이스는 사용하지 않아도 되지만 사용한 이유는 테스트를 위해 사용한 것일 뿐이며 컨트랙트 작성 시 투표 정보들을 다 담을 수 있도록 작성을 하게 된다면 투표에 관한 모든 정보를 블록체인에 다 담을 수 있을 것이라고 생각합니다.
성공적으로 완료한 경우 location.reload() 를 통해 페이지를 새로고침 하여 데이터를 다시 보여주게 됩니다.
MC THE MAX 후보자의 득표 수가 2486표 -> 2487표로 증가한 것을 확인할 수 있습니다. 비슷한 방식으로 투표를 취소시킬 수 있습니다. 내 투표 수정 글귀를 클릭 시 트랜잭션을 발생시켜 컨트랙트에서 voters[msg.sender] = false 로 설정하는 등 기존과의 반대 과정을 거치면 투표했던 기록을 취소하는 것도 가능합니다.
후보자와 득표 수 등의 데이터는 Controller 부분에서
이렇게 설정되어 해당 데이터들을 불러오게 됩니다. INSERT 하는 것과 비슷한 방법으로 SELECT 로 데이터를 가져온 것입니다. 가져온 데이터를 model 객체를 통해 뷰로 넘길 수 있습니다. JSTL 을 사용하여 반복적이고 조건적인 작업을 처리하였습니다.
JSTL 을 사용하기 전 index.jsp 파일의 최 상단에 위 코드를 추가해주어야만 JSTL 문법이 정상적으로 동작합니다.
후보자 리스트가 있는 경우에는 <c:otherwies> 로 들어오게 되고 <c:forEach> 문을 사용하여 후보자들의 데이터들을 반복적으로 처리를 합니다. 여기서 <c:if> 문을 사용하여
후보자 들의 득표 수와 득표 율을 계산하는 부분을 구현했습니다. 총 득표 수가 0 인 경우 0% 처리를 하게 되며 아닌 경우 ( 득표 수 / 총 투표 수 * 100 ) 으로 득표 율을 계산합니다. 이때 <fmt:formatNumber> 를 사용하여 계산시 나오게 되는 소수점 문제를 처리하였습니다.
여기서 화면 상의 득표 율 막대 바는 부트스트랩의 progress-bar 를 사용하며 css 로 화면 로드시 막대바는 점점 증가하게, 막대바 위의 득표율 % 는 서서히 보이게 설정하였습니다. 아래에 css 파일의 막대 바 부분의 소스를 올려놓았습니다.
이로써 이더리움 기반의 투표하는 dApp 의 개발 과정은 끝이 나게 되었습니다.
감사합니다.
전편의 내용이 궁금하시면 아래의 경로를 클릭해주세요.
Ethereum_dApp_2_스마트컨트랙트와 dAPP, 개발환경 구축하기
참고 사이트
https://ko.wikipedia.org/wiki/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8
https://www.youtube.com/watch?v=662wnupQ8fg
https://steemit.com/kr/@loum/1
https://steemit.com/kr/@jsralph/4r1deg-1
https://www.gopax.co.kr/cryptocurrency/ethereum/
https://steemit.com/kr/@jul06/dkarm
http://www.seunghwanhan.com/2015/06/ethereum-introduction_3.html
http://etherandbitcoin.tistory.com/95
https://blog.theloop.co.kr/2017/03/28/
https://steemit.com/kr/@twinbraid/68fbdz
https://steemit.com/kr/@jongjhon9900/dapp
https://github.com/trufflesuite/ganache-cli
https://www.npmjs.com/package/ethereumjs-testrpc
http://blockchaindev.kr/models/content/65
https://solidity.readthedocs.io/en/v0.4.23/
http://remix.readthedocs.io/en/latest/
참고 자료
이더리움 소개 및 특징 분석 - 보안연구부 보안기술팀(2016.03)
'유용한 정보' 카테고리의 다른 글
모바일 터치 디자인하기 (0) | 2018.07.06 |
---|---|
Airbnb Lottie (0) | 2018.07.02 |
Ethereum_dApp_3_개발하기(1) (0) | 2018.06.15 |
Fabric에 대해 살펴보겠습니다.(3편) (0) | 2018.06.07 |
Ethereum_dApp_2_스마트 컨트랙트와 dApp, 개발환경 구축하기 (0) | 2018.06.01 |