‘이더리움 댑 개발’ 세미나 보조 교재 – Mastering Blockchain Programming with Solidity 3
이번 보조 교재 같이 읽기는 Section 4: Design Patterns and Best Practices를 다룹니다.
- Chapter 13, Solidity Design Patterns
- Chapter 14, Tips, Tricks, and Security Best Practices
Solidity Design Pattern
각각의 디자인 패턴이 해결하고자 하는 문제가 무엇이고 어떻게 해결하고 있는지를 알고, 컨트랙트 개발 시에 사용할 수 있도록 기억하고 연습해 둡니다.
아래 요약, 정리한 내용을 다시 한 번 주의를 기울여 읽어봅니다.
Security patterns
- Withdrawal pattern
- pull-over-push pattern으로도 알려져 있음
- In this pattern, ether or token transfer (push) from the contract is avoided; rather, the user is allowed to pull ether or token from the contract.
- 본문 예제는 동적 배열을 가지고 반복문을 실행하는 문제를 함께 다루고 있는데 이것은 분리된 문제로 다루는 게 좋습니다. 아 문제는 반복을 어떻게 없앨 것인지가 해결책으로 제시되어야 합니다.
- 이 패턴은 폴백 함수와 관련된 공격 문제를 다루어주는게 좋습니다.
- 해결책은 이더나 토큰 전송을 다른 기능과 분리하는 것입니다. 분리한 토큰 전송은 컨트랙트에서 알아서 전송(push)하는 것이 아니라 수신자의 요청에 의해 전송(pull)하도록 합니다.
- Access restriction pattern
- 블록체인 특성 상, 컨트랙트는 누구나 접근해서 컨트랙트 함수를 호출할 수 있습니다. 권한 있는 계정 만 컨트랙트 함수를 호출하게끔 하고자 할 수 있습니다.
- 권한 설계를 하고, 권한을 modifier로 작성하고, modifier를 사용해 함수 호출을 제약합니다.
- Emergency stop pattern
- 컨트랙트를 긴급하게 중지시켜야 할 상황이 있습니다.
- It is important to note that when an emergency stop is activated on a contract, all its stakeholders must be able to see the current state of the contract.
- 중지 가능한 컨트랙트로 작성합니다.
- 중지 가능한 역할과 중지하거나 중지를 해지하기 위한 조건을 제약으로 작성합니다. 중지여부를 나타내는 상태를 갖습니다.
- 컨트랙트를 긴급하게 중지시켜야 할 상황이 있습니다.
Creational patterns
- Factory contract pattern
- 컨트랙트 인스턴스를 생성하기 위한 생성 정보가 컨트랙트 배포시 정적으로 결정되지 않을 수 있습니다.
- 팩토리 컨트랙트에서 컨트랙트 인스턴스를 생성 하도록 합니다.
Behavioral patterns
- State machine pattern
- 복잡한 상태를 갖는 컨트랙트가 있을 수 있습니다.
- 상태머신을 설계하고, 상태를 modifier로 작성해서 함수 실행을 제약합니다. 상태는 열거형으로 작성합니다. 현재 상태를 나타내는 상태 변수를 갖도록 합니다.
- 어떤 상태에 있는지를 체크하는 modifier 이름은 atState보다 inState가 더 적당해 보입니다.
- 상태 전이는 modifier보다는 함수로 작성하는 것이 더 적당해 보입니다. transfer 함수로 작성하고, 상태 전이가 일어나야 하는 함수에서 호출하도록 합니다.
- Iterable map pattern
- 매핑을 기준으로 컬렉션을 리턴해야 할 때, 솔리디티에서 매핑은 개별 항목을 반복적으로 열거할 수 없어 문제가 생깁니다.
- 매핑과 관련해 열거해야 하는 항목을 다룰 수 있는 배열을 추가합니다.
- Indexed map pattern
- iterable map 패턴이 적용된 경우 매핑 항목을 삭제하기를 원할 수 있습니다.
- IndexedMapping 라이브러리를 작성해서 사용합니다.
- 패턴으로 분리하기 보다는 공통 라이브러리로 작성해서 제공하는게 좋을 것 같습니다.
- Address list pattern
- 화이트리스트나 블랙리스트를 관리하고자 할 수 있습니다.
- 주소 리스트를 관리하는 컨트랙트를 작성하고, 주소 리스트를 필요로 하는 컨트랙트에서 상속받도록 합니다.
- 주소를 추가 삭제할 수 있어야 합니다.
- 해당 주소가 주소 목록에 존재하는지 확인할 수 있어야 합니다.
- 패턴으로 분리하기 보다는 공통 컨트랙트로 작성해서 제공하는게 좋을 것 같습니다.
- Subscription pattern
- 수수료를 내고 서비스를 받는 구독형 컨트랙트가 필요할 수 있습니다.
- Subscription 컨트랙트를 작성하고, 구독형 컨트랙트가 필요한 경우 상속받도록 합니다.
- 패턴으로 분리하기 보다는 공통 컨트랙트로 작성해서 제공하는게 좋을 것 같습니다.
Gas economic patterns
- String equality comparison pattern
- 바이트 별로 문자열을 비교하는 것은 가스를 많이 사용하게 됩니다.
- 문자열 길이를 비교하고, keccak256 함수를 사용해서 해시 값을 비교하도록 합니다.
- Tight variable packing pattern
- 최적화되지 않은 구조체는 저장소를 효율적으로 사용하지 못하기 때문에 가스를 많이 사용하게 됩니다.
- 솔리디티 optimizer는 구조체를 최적화하지 않습니다.
- 구조체 속성 값이 tight하게 packing되도록 구조체 속성 선언 순서를 조정합니다.
- 최적화되지 않은 구조체는 저장소를 효율적으로 사용하지 못하기 때문에 가스를 많이 사용하게 됩니다.
Life cycle patterns
- Mortal pattern
- 컨트랙트를 소멸 시키고 싶을 수 있습니다.
- selfdestruct를 호출하는 함수를 작성합니다.
- Auto deprecate pattern
- 함수 호출을 시간으로 제약하고 싶을 수 있습니다.
- block.timestamp나 now 호출을 통해 block의 채굴 시간을 얻고, seconds, minutes, hours, days, weeks, years 시간 단위를 사용해 require로 시간 제약을 사용합니다.
Tips, Tricks, and Security Best Practices
Smart contracts best practices
- Avoiding floating pragma
- 하나의 솔리디티 컴파일러 버전이 사용될 수 있도록 합니다.
- 예) pragma solidity 0.5.0;
- 하나의 솔리디티 컴파일러 버전이 사용될 수 있도록 합니다.
- Avoid sharing a secret on-chain
- commit-and-reveal 패턴으로 처리합니다.
- Be careful while using loops
- 반복문에서 컨트랙트 상태 변수를 업데이트하는데 반복 횟수가 실행시에 결정된다면 가스 한도를 넘어서 트랜잭션 처리가 안 될 수 있습니다. 상태 변수 업데이트를 포함한 반복이라면 반드시 반복 횟수가 컴파일 시에 결정되도록 합니다.
- view나 pure가 아닌 external, public 함수에서 view나 pure인 반복 횟수가 결정되지 않은 반복문을 포함하는 함수를 호출하지 않도록 합니다.
- view, pure 함수에서는 반복 횟수가 컴파일시에 결정되지 않아도 사용할 수 있습니다. 문제는 view나 pure가 아닌 external, public 함수에서 반복횟수가 결정되지 않은 반복문을 포함하는 view, pure 함수를 호출하는 경우 가스가 사용된다는 것입니다.
- Avoid using tx.origin for authorization
- tx.origin의 성격을 잘 이해하도록 합니다. 권한 설정을 위해서는 msg.sender를 사용합니다.
- The timestamp can be manipulated by miners
- timestamp를 사용할 때는 채굴자가 여러분이 사용하는 컨트랙트 함수 정보를 알 수 있고, timestamp는 정확한 시간이 아니라 어느 정도 조정 가능한 범위(The 15-second blocktime rule)를 가지며 채굴자에 의해 작성된다는 것을 알고 사용하도록 합니다.
- Avoid dependency on untrusted external calls
- Rounding errors with division
- 배포를 위한 가스 한도를 넘는 컨트랙트는 다수의 컨트랙트로 분할해야 합니다.
- A contract that consumes less than 8 million gas at the time of deployment can be deployed on the Ethereum blockchain at the moment. In the future, this limit of 8 million gas could be increased.
- Rounding errors with division
- To prevent rounding errors to a certain extent, you should do the multiplication (if multiplication exists) of the values first and then only perform the division operation.
- Using assert(), require(), and revert() properly
- assert
- This function should only be used for invariant checking.
- require
- The require() function should be used when you want to validate the arguments provided to the function. It is also used to check for the valid conditions and variable values to be in an expected state.
- assert
- Gas consumption
- 가스 사용을 줄일 수 있도록 노력해야 합니다.
- It is recommended that the contract should be compiled with optimization flag enabled.
- Known attack patterns
- 다양한 공격 패턴들과 방어 수단들을 알고 있어야 합니다.
- Front-running attacks
- Reentrancy attacks
- Signature replay attacks
- Integer overflow and underflow attacks
- 다양한 공격 패턴들과 방어 수단들을 알고 있어야 합니다.
- Ether can be sent forcibly to a contract
- selfdestruct를 사용해서 폴백이 없는 컨트랙트 주소로도 이더를 강제로 보낼 수 있다는 점에 주의합니다. 나도 모르는 사이에 이더 잔고가 변경될 수 있다는 것입니다 . 잔고를 가지고 제약하는 로직이 있다면 문제가 됩니다.
Security analysis tools
- Securify
- An open source, online, and fully automated static analyzer tool for Solidity smart contracts. It scans the contract code for vulnerability patterns and generates a report. You just need to upload your contract code into the online tool and get the report generated in a few minutes.
- Slither
- An open source Solidity static analyzer that detects many common Solidity issues.
- Mythril
- An open source security analysis tool for EVM byte codes. It finds security vulnerabilities in smart contracts built on EVM compatible blockchains such as Ethereum, Quorum, Vechain, Rootstock, and Tron.
- MythX
- The platform and the ecosystem for Ethereum security tools. The tool also provides an extension for Truffle and Embark.
- SmartCheck
- This open source tool provides static analysis of the Solidity contract, detects vulnerabilities, and checks for best practices.