Last active
July 6, 2022 07:28
-
-
Save sbin0819/2029990c459ed676d09af4a1df27788a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Chapter 1 | |
Web3.js | |
## basic | |
### 컨트랙트 | |
```solidity | |
pragma solidity ^0.4.19; | |
contract HelloWorld { | |
} | |
``` | |
### 구조체 | |
```solidity | |
struct Person { | |
uint age; | |
string name; | |
} | |
``` | |
### 함수 | |
```solidity | |
uint[] numbers; | |
function _addToArray(uint _number) private { | |
numbers.push(_number); | |
} | |
``` | |
### 함수 제어자 | |
- 상태를 변화시키지 않음 `view` | |
- 함수가 앱에서 어떤 데이터도 접근하지 않는 것 `pure` | |
### 이벤트 | |
```solidity | |
event IntegersAdded(uint x, uint y, uint result); | |
function add(uint _x, uint _y) public { | |
uint result = _x + _y; | |
// 이벤트를 실행하여 앱에게 add 함수가 실행되었음을 알린다: | |
IntegersAdded(_x, _y, result); | |
return result; | |
} | |
``` | |
```js | |
YourContract.IntegersAdded(function(error, result) { | |
// 결과와 관련된 행동을 취한다 | |
}) | |
``` | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Chapter 2 | |
## 매핑과 주소 | |
`mapping`, `adress` | |
- 주소 | |
이더리움 블록체인의 주소 | |
- 매핑 | |
데이터를 저장하는 또다른 방법 | |
```solidity | |
// 금융 앱용으로, 유저의 계좌 잔액을 보유하는 uint를 저장한다: | |
mapping (address => uint) public accountBalance; | |
// 혹은 userID로 유저 이름을 저장/검색하는 데 매핑을 쓸 수도 있다 | |
mapping (uint => string) userIdToName; | |
``` | |
매핑은 기본적으로 키-값 (key-value) 저장소로, 데이터를 저장하고 검색하는 데 이용된다. 첫번째 예시에서 키는 address이고 값은 uint이다. 두번째 예시에서 키는 uint이고 값은 string이다. | |
## msg.sender | |
솔리디티에는 모든 함수에서 이용 가능한 특정 전역 변수들이 있지. 그 중의 하나가 현재 함수를 호출한 사람 (혹은 스마트 컨트랙트)의 주소를 가리키는 msg.sender이지. | |
참고: 솔리디티에서 함수 실행은 항상 외부 호출자가 시작하네. 컨트랙트는 누군가가 컨트랙트의 함수를 호출할 때까지 블록체인 상에서 아무 것도 안 하고 있을 것이네. 그러니 항상 msg.sender가 있어야 하네. | |
```solidity | |
mapping (address => uint) favoriteNumber; | |
function setMyNumber(uint _myNumber) public { | |
// `msg.sender`에 대해 `_myNumber`가 저장되도록 `favoriteNumber` 매핑을 업데이트한다 ` | |
favoriteNumber[msg.sender] = _myNumber; | |
// ^ 데이터를 저장하는 구문은 배열로 데이터를 저장할 떄와 동일하다 | |
} | |
function whatIsMyNumber() public view returns (uint) { | |
// sender의 주소에 저장된 값을 불러온다 | |
// sender가 `setMyNumber`을 아직 호출하지 않았다면 반환값은 `0`이 될 것이다 | |
return favoriteNumber[msg.sender]; | |
} | |
``` | |
이 간단한 예시에서 누구나 setMyNumber을 호출하여 본인의 주소와 연결된 우리 컨트랙트 내에 uint를 저장할 수 있지. | |
msg.sender를 활용하면 자네는 이더리움 블록체인의 보안성을 이용할 수 있게 되지. 즉, 누군가 다른 사람의 데이터를 변경하려면 해당 이더리움 주소와 관련된 개인키를 훔치는 것 밖에는 다른 방법이 없다는 것이네. | |
## require | |
```solidity | |
function sayHiToVitalik(string _name) public returns (string) { | |
// _name이 "Vitalik"인지 비교한다. 참이 아닐 경우 에러 메시지를 발생하고 함수를 벗어난다 | |
// (참고: 솔리디티는 고유의 스트링 비교 기능을 가지고 있지 않기 때문에 | |
// 스트링의 keccak256 해시값을 비교하여 스트링 값이 같은지 판단한다) | |
require(keccak256(_name) == keccak256("Vitalik")); | |
// 참이면 함수 실행을 진행한다: | |
return "Hi!"; | |
} | |
``` | |
## 상속 | |
`is` | |
```solidity | |
contract Doge { | |
function catchphrase() public returns (string) { | |
return "So Wow CryptoDoge"; | |
} | |
} | |
contract BabyDoge is Doge { | |
function anotherCatchphrase() public returns (string) { | |
return "Such Moon BabyDoge"; | |
} | |
} | |
``` | |
## import | |
## storage vs memory | |
Storage는 블록체인 상에 영구적으로 저장되는 변수를 의미하지. Memory는 임시적으로 저장되는 변수로, 컨트랙트 함수에 대한 외부 호출들이 일어나는 사이에 지워지지. 두 변수는 각각 컴퓨터 하드 디스크와 RAM과 같지. | |
`상태 변수(함수 외부에 선언된 변수)`는 초기 설정상 `storage`로 선언되어 블록체인에 영구적으로 저장되는 반면, `함수 내에 선언된 변수`는 `memory`로 자동 선언되어서 함수 호출이 종료되면 사라지지. | |
*하지만 이 키워드들을 사용해야 하는 때가 있지. 바로 함수 내의 구조체와 _배열_을 처리할 때지:* | |
```solidity | |
contract SandwichFactory { | |
struct Sandwich { | |
string name; | |
string status; | |
} | |
Sandwich[] sandwiches; | |
function eatSandwich(uint _index) public { | |
// Sandwich mySandwich = sandwiches[_index]; | |
// ^ 꽤 간단해 보이나, 솔리디티는 여기서 | |
// `storage`나 `memory`를 명시적으로 선언해야 한다는 경고 메시지를 발생한다. | |
// 그러므로 `storage` 키워드를 활용하여 다음과 같이 선언해야 한다: | |
Sandwich storage mySandwich = sandwiches[_index]; | |
// ...이 경우, `mySandwich`는 저장된 `sandwiches[_index]`를 가리키는 포인터이다. | |
// 그리고 | |
mySandwich.status = "Eaten!"; | |
// ...이 코드는 블록체인 상에서 `sandwiches[_index]`을 영구적으로 변경한다. | |
// 단순히 복사를 하고자 한다면 `memory`를 이용하면 된다: | |
Sandwich memory anotherSandwich = sandwiches[_index + 1]; | |
// ...이 경우, `anotherSandwich`는 단순히 메모리에 데이터를 복사하는 것이 된다. | |
// 그리고 | |
anotherSandwich.status = "Eaten!"; | |
// ...이 코드는 임시 변수인 `anotherSandwich`를 변경하는 것으로 | |
// `sandwiches[_index + 1]`에는 아무런 영향을 끼치지 않는다. 그러나 다음과 같이 코드를 작성할 수 있다: | |
sandwiches[_index + 1] = anotherSandwich; | |
// ...이는 임시 변경한 내용을 블록체인 저장소에 저장하고자 하는 경우이다. | |
} | |
} | |
``` | |
## 함수 접근 제어자 더 알아보기 | |
- internal | |
- external | |
```solidity | |
contract Sandwich { | |
uint private sandwichesEaten = 0; | |
function eat() internal { | |
sandwichesEaten++; | |
} | |
} | |
contract BLT is Sandwich { | |
uint private baconSandwichesEaten = 0; | |
function eatWithBacon() public returns (string) { | |
baconSandwichesEaten++; | |
// eat 함수가 internal로 선언되었기 때문에 여기서 호출이 가능하다 | |
eat(); | |
} | |
} | |
``` | |
## 인터페이스 | |
```solidity | |
contract LuckyNumber { | |
mapping(address => uint) numbers; | |
function setNum(uint _num) public { | |
numbers[msg.sender] = _num; | |
} | |
function getNum(address _myAddress) public view returns (uint) { | |
return numbers[_myAddress]; | |
} | |
} | |
``` | |
```solidity | |
contract NumberInterface { | |
function getNum(address _myAddress) public view returns (uint); | |
} | |
``` | |
## 인터페이스 활용 | |
```solidity | |
contract MyContract { | |
address NumberInterfaceAddress = 0xab38... | |
// ^ 이더리움상의 FavoriteNumber 컨트랙트 주소이다 | |
NumberInterface numberContract = NumberInterface(NumberInterfaceAddress) | |
// 이제 `numberContract`는 다른 컨트랙트를 가리키고 있다. | |
function someFunction() public { | |
// 이제 `numberContract`가 가리키고 있는 컨트랙트에서 `getNum` 함수를 호출할 수 있다: | |
uint num = numberContract.getNum(msg.sender); | |
// ...그리고 여기서 `num`으로 무언가를 할 수 있다 | |
} | |
} | |
``` | |
## 다수의 반환값 처리하기 | |
```solidity | |
function multipleReturns() internal returns(uint a, uint b, uint c) { | |
return (1, 2, 3); | |
} | |
function processMultipleReturns() external { | |
uint a; | |
uint b; | |
uint c; | |
// 다음과 같이 다수 값을 할당한다: | |
(a, b, c) = multipleReturns(); | |
} | |
// 혹은 단 하나의 값에만 관심이 있을 경우: | |
function getLastReturnValue() external { | |
uint c; | |
// 다른 필드는 빈칸으로 놓기만 하면 된다: | |
(,,c) = multipleReturns(); | |
} | |
``` | |
```solidity | |
contract ZombieFeeding is ZombieFactory { | |
address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d; | |
KittyInterface kittyContract = KittyInterface(ckAddress); | |
// 여기에 있는 함수 정의를 변경: | |
function feedAndMultiply(uint _zombieId, uint _targetDna) public { | |
require(msg.sender == zombieToOwner[_zombieId]); | |
Zombie storage myZombie = zombies[_zombieId]; | |
_targetDna = _targetDna % dnaModulus; | |
uint newDna = (myZombie.dna + _targetDna) / 2; | |
// 여기에 if 문 추가 | |
_createZombie("NoName", newDna); | |
} | |
function feedOnKitty(uint _zombieId, uint _kittyId) public { | |
uint kittyDna; | |
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId); | |
// 여기에 있는 함수 호출을 변경: | |
feedAndMultiply(_zombieId, kittyDna); | |
} | |
} | |
``` | |
## if 문 | |
자바스크립트 if 문과 동일 | |
```solidity | |
function eatBLT(string sandwich) public { | |
// 스트링 간의 동일 여부를 판단하기 위해 keccak256 해시 함수를 이용해야 한다는 것을 기억하자 | |
if (keccak256(sandwich) == keccak256("BLT")) { | |
eat(); | |
} | |
} | |
``` | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 솔리디티 고급개념 | |
## 가스(Gas) | |
### 가스 - 이더리움 DApp이 사용하는 연료 | |
함수를 실행하는 데에 얼마나 많은 가스가 필요한지는 그 함수의 로직(논리 구조)이 얼마나 복잡한지에 따라 달라지네. 각각의 연산은 소모되는 가스 비용(gas cost)이 있고, 그 연산을 수행하는 데에 소모되는 컴퓨팅 자원의 양이 이 비용을 결정하네. 예를 들어, storage에 값을 쓰는 것은 두 개의 정수를 더하는 것보다 훨씬 비용이 높네. 자네 함수의 전체 가스 비용은 그 함수를 구성하는 개별 연산들의 가스 비용을 모두 합친 것과 같네. | |
### 가스는 왜 필요한가? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment