1 The Wrong Voting System
- 잘못된 방법
- 누구나 주어진 요청에 대해 한 번만 투표 가능
- 각 요청 구조체 내부에 존재하는 새로운 배열 생성 (비어있음)
- 투표를 하기 시작하면 해당 주소 배열을 채우는 것
- 승인자 배열을 반복하며 주소가 트랜잭션을 보낸 사람이라면 true가 되고 루프 돌아
- 주소 배열에 주소가 존재하지 않는 것을 확인하여 존재하지 않을 경우에만 동작하도록 함
1) Issues with Arrays
- for 루프를 1000번 돈다로 가정했을 때 1000 가스를 필요로 함
- 하나의 기여자를 확인하기 위해 불필요하게 많은 가스를 사용함
- 10000의 기여자가 있다면 그만큼 배로 필요로 하는 가스가 증가하는 것
- 많은 사람들을 관리하기 위한 다른 데이터 구조를 사용해야 함 > Mapping
2) Mappings vs Arrays
- 배열의 크기는 검색에 걸리는 시간을 나타냄
- 매핑은 내부에서 검색을 수행할 때 일정한 시간을 수반함
3) Basics of Mappings
1) Key가 내용과 함께 매칭되어 저장되지 않음
- Key를 찾으면 Hash 테이블에서 매핑되고 정해진 index에 따라 값을 가져옴
2) 매핑을 반복하여 매핑에 있는 모든 값을 인쇄할 수 없음
- 매핑 명을 출력해도 List 처럼 모든 값이 출력되지 않음
3) Campaign 최종본
2 Refactoring to Mappings
- mapping은 bool값이 true일 경우에 동작
1) Refactoring Request Stucts
- 실제 사람들을 추적할 필요는 없음
- 찬성과 반대의 수(투표하지 않은 수)만으로 판단하는 것
- 찬성표를 던진 사람만 조사(approvalCount)
2) Approving a Request
- 요청 배열을 반복해서 돌지 않고 approveRequest 함수에서 mapping을 돌아 Request를 특정
2) Finalizing a Request
pragma solidity ^0.4.17;
contract Campaign {
struct Request {
string description;
uint value;
address recipient;
bool complete;
uint approvalCount;
mapping(address => bool) approvals;
// 요청 주소 리펙토링
}
Request[] public requests;
address public manager;
uint public minimumContribution;
mapping(address => bool) public approvers;
uint public approversCount;
modifier restricted() {
require(msg.sender == manager);
_;
}
function Campaign(uint minimum) public {
manager = msg.sender;
minimumContribution = minimum;
}
function contribute() public payable {
require(msg.value > minimumContribution);
approvers[msg.sender] = true;
//approvers.push(msg.sender);
approversCount++;
}
function createRequest(string description, uint value, address recipient) public restricted {
Request memory newRequest = Request({
description: description,
value: value,
recipient: recipient,
complete: false,
approvalCount: 0
});
requests.push(newRequest);
}
function approveRequest(uint index) public {
/* 사본을 조작하기 위한 strage형 변수 */
Request storage request = requests[index];
require(approvers[msg.sender]);
require(!requests[index].approvals[msg.sender]);
request.approvals[msg.sender] = true;
request.approvalCount++;
}
function finalizeRequest(uint index) public restricted {
Request storage request = request[index];
/* 요청에 승인해야 릴리스할 수 있도록 */
require(request.approvalCount > (approvalCount / 2));
require(!request.complete);
/* 지정된 돈을 요청 수신자에게 보내기 */
request.recipient.transfer(request.value);
require.complete = true;
}
}
3Thinking about Deployment
- 각각의 인스턴스에 대한 주소는 완전히 분리되어 있음
- 인스턴스를 2개 배포하면 전혀 연계가 없고 둘 사이는 아무 관련 없음
- 계약을 배포하기 전 사용자가 계약 소스 코드를 수정할 수 있음
- 전체 승인 시스템이나 요청 시스템을 제거할 수 있음
- 신뢰성 떨어짐
- 계약배포 및 인스턴스 생성시 비용을 수반함
- 보안 솔류션은 향상되었지만 비용 부담 증가
- 계약은 또다른 계약을 배포하거나 인스턴스를 생성할 수 있음
- 배포 비용은 트랜잭션을 보내는 사용자에게 지불됨
- 보안성을 증가시키면서 배포 비용에 대한 부담을 줄일 수 있음
1) Campaign Factory
- Variables: 지금까지 배포된 모든 캠페인을 포함하는 주소 배열
- Functions: 캠페인 생성 기능, 모든 캠페인을 검색하기 위한 기능