일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- #국제채권시장 #유로본드 #유로커런시 #유로달러 #외국채 #금융중개기관 #간접금융 #거래비용#다우존스공업평균지수 #나스닥종합지수 #FTSE100 #DAX #CAC40 #straittimes #항생지수 #거래비용 #유동성 #위
- 자료구조 #알고리즘
- vp #vc #did #신원인증 #블록체인
- html #js #parsing
- 미쉬킨의화폐와금융 #미쉬킨 #화폐금융론 #화폐와금융 #경제학 #교양 #경제지식 #경제공부
- 페이스북유니버시티 #마케팅교육 #마케팅캠프
- #경제상식 #화폐 #금융 #화폐금융론 #경제학 #경제기본 #경제지식 #경제근육 #투자지식 #경제공부 #경제학전공 #금융이란 #화폐란 #금융시장 #금융시장역할 #화폐역할 #화폐역기능 #금융역기능 #
- 블록체인 #layer2 #레이어2 #이더리움스케일링
- Today
- Total
평행우주 : world 1
[크립토좀비] Solidity Path : 1. 좀비 공장 만들기 본문
컨트랙트
완전 기초부터 시작하기:
솔리디티 코드는 컨트랙트 안에 싸여 있음.
컨트랙트는 이더리움 애플리케이션의 기본적인 구성 요소로, 모든 변수와 함수는 어느 한 컨트랙트에 속한다.
컨트랙트는 모든 프로젝트의 시작 지점과 같음.
* 비어 있는 HelloWorld 컨트랙트
contract HelloWorld {
}
Version Pragma
모든 솔리디티 소스 코드는 "version pragma"로 시작
왜?
해당 코드가 이용해야 하는 솔리디티 버전을 선언하여 이후에 새로운 컴파일러 버전이 나와도 기존 코드가 깨지지 않도록 예방
ex) pragma solidity ^0.4.19;
* 컨트랙트 초기 뼈대
pragma solidity ^0.4.19;
contract HelloWorld {
}
상태 변수 & 정수
상태 변수는 컨트랙트 저장소에 영구적으로 저장된다.
즉, 이더리움 블록체인에 기록된다는 뜻으로 데이터베이스에 데이터를 쓰는 것과 동일한 개념
contract Example {
// 이 변수는 블록체인에 영구적으로 저장된다
uint myUnsignedInteger = 100;
}
[myUnsignedInteger라는 uint를 생성하여 100이라는 값을 배정]
부호 없는 정수: uint
uint 자료형은 부호 없는 정수로, 값이 음수가 아니어야 한다.
부호가 있는 경우, 정수를 위한 int 자료형 사용
참고: 솔리디티에서 uint는 실제로 uint256, 즉 256비트 부호 없는 정수의 다른 표현.
uint8, uint16, uint32 등과 같이 uint를 더 적은 비트로 선언할 수도 있지만,
특수한 경우가 아니라면 일반적으로 단순히 uint를 사용한다.
수학 연산
대부분의 프로그래밍 언어의 수학 연산과 동일
- 덧셈: x + y
- 뺄셈: x - y,
- 곱셈: x * y
- 나눗셈: x / y
- / 나머지: x % y
지수 연산 ("x의 y승", x^y) : x ** y
uint x = 5 ** 2; // 즉, 5^2 = 25
구조체
솔리디티 구조체를 통해 여러 특성을 가진, 보다 복잡한 자료형을 생성할 수 있다.
struct Person {
uint age;
string name;
}
스트링은 임의의 길이를 가진 UTF-8 데이터를 위해 활용
배열
솔리디티에는 _정적_ 배열과 _동적_ 배열 존재.
// 2개의 원소를 담을 수 있는 고정 길이의 배열:
uint[2] fixedArray;
// 또다른 고정 배열으로 5개의 스트링을 담을 수 있다:
string[5] stringArray;
// 동적 배열은 고정된 크기가 없으며 계속 크기가 커질 수 있다:
uint[] dynamicArray;
구조체의 배열을 생성할 수도 있다. 위 챕터의 Person 구조체를 이용하면:
Person[] people; // 이는 동적 배열로, 원소를 계속 추가할 수 있다.
- 상태 변수는 블록체인에 영구적으로 저장될 수 있기 때문에,
- 이처럼 구조체의 동적 배열을 생성하면 마치 데이터베이스처럼 컨트랙트에 구조화된 데이터를 저장하는 데 유용
Public 배열
public으로 배열을 선언할 수 있고, 솔리디티는 이런 배열을 위해 getter 메소드를 자동적으로 생성한다
Person[] public people;
- 그러면 다른 컨트랙트들이 이 배열을 읽을 수 있게 된다 (쓸 수는 없음).
- 이는 컨트랙트에 공개 데이터를 저장할 때 유용
함수 선언
솔리디티 함수 선언
function eatHamburgers(string _name, uint _amount) {
}
참고: 함수 인자명을 언더스코어(_)로 시작해서 전역 변수와 구별하는 것이 관례 (의무는 아님).
함수 호출
eatHamburgers("vitalik", 100);
구조체와 배열 활용하기
새로운 구조체 생성하기
위 의 Person 구조체 예시 활용
struct Person {
uint age;
string name;
}
Person[] public people;
새로운 Person를 생성하고 people 배열에 추가하는 방법
// 새로운 사람을 생성한다:
Person satoshi = Person(172, "Satoshi");
// 이 사람을 배열에 추가한다:
people.push(satoshi);
위 두 코드 조합
people.push(Person(16, "Vitalik"));
참고
array.push()는 무언가를 배열의 끝에 추가해서 모든 원소 순서 유지
uint[] numbers;
numbers.push(5);
numbers.push(10);
numbers.push(15);
// numbers 배열은 [5, 10, 15]과 같다.
Private / Public 함수
솔리디티에서 함수는 기본적으로 public으로 선언.
- 즉, 누구나 (혹은 다른 어느 컨트랙트가) 컨트랙트 함수를 호출하고 코드를 실행할 수 있다
- 이는 컨트랙트를 공격에 취약하게 만들 수 있기 때문에,
- 기본적으로 함수를 private으로 선언하고, 공개할 함수만 public으로 선언하는 것이 좋다
private 함수 선언 방법
uint[] numbers;
function _addToArray(uint _number) private {
numbers.push(_number);
}
- private는 컨트랙트 내의 다른 함수들만이 이 함수를 호출하여 numbers 배열로 무언가를 추가할 수 있다는 것을 의미
- private 키워드는 함수명 다음에 적고, 함수 인자명과 마찬가지로 private 함수명도 언더바(_)로 시작하는 것이 관례
함수 더 알아보기
반환값
string greeting = "What's up dog";
function sayHello() public returns (string) {
return greeting;
}
솔리디티에서 함수 선언은 반환값 종류를 포함한다 (예문 : string)
함수 제어자
위에서 sayHello()는 솔리디티에서 상태를 변화시키지 않는 함수. 즉, 어떤 값을 변경하거나 무언가를 쓰지 않는다.
이 경우에는 함수를 데이터를 보기만 하고 변경하지 않는다는 뜻을 가진 view 함수로 선언한다.
function sayHello() public view returns (string) {
솔리디티의 pure 함수는 함수가 앱에서 어떤 데이터도 접근하지 않는 것을 의미
function _multiply(uint a, uint b) private pure returns (uint) {
return a * b;
}
이 함수는 앱에서 읽는 것도 하지 않음
다만 반환값이 함수에 전달된 인자값에 따라서 달라진다.
참고: 솔리디티 컴파일러는 어떤 제어자를 써야 하는지 경고 메시지를 통해 알려준다
Keccak256과 형 변환
_generateRandomDna 함수의 반환값이 (반) 랜덤인 uint가 되기를 원할 때
- 이더리움은 SHA3의 한 버전인 keccak256를 내장 해시 함수로 가진다
- 해시 함수는 기본적으로 입력 스트링을 랜덤 256비트 16진수로 매핑
- 스트링에 약간의 변화라도 있으면 해시 값은 크게 달라짐
- 해시 함수는 이더리움에서 여러 용도로 활용되지만, 여기서는 의사 난수 발생기(pseudo-random number generator)로 이용
예시:
//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256("aaaab");
//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256("aaaac");
입력값의 한 글자가 달라졌음에도 불구하고 반환값은 완전히 달라진다
참고: 블록체인에서 안전한 의사 난수 발생기는 매우 어려운 문제로, 이 방법은 안전하지는 않지만, 보안이 최우선순위가 아닐 때 이용
형 변환
자료형 간 형 변환
uint8 a = 5;
uint b = 6;
// a * b가 uint8이 아닌 uint를 반환하기 때문에 에러 메시지가 난다:
uint8 c = a * b;
// b를 uint8으로 형 변환해서 코드가 제대로 작동하도록 해야 한다:
uint8 c = a * uint8(b);
위의 예시에서 a * b는 uint를 반환
이 반환값을 uint8에 저장하려고 하면, 잠재적으로 문제를 야기할 수 있다.
반환값을 uint8으로 형 변환하면 코드가 제대로 작동하고 컴파일러에서도 에러 메세지가 뜨지 않는다.
이벤트
이벤트는 컨트랙트가 블록체인 상 앱의 사용자 단에서 무언가 액션이 발생했을 때 의사소통하는 방법
컨트랙트는 특정 이벤트가 일어나는지 "귀를 기울이고" 그 이벤트가 발생하면 행동한다.
예시:
// 이벤트를 선언한다
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;
}
그러면 앱의 사용자 단은 해당 이벤트가 일어나는지 살핀다
자바스크립트로 구현한 경우:
YourContract.IntegersAdded(function(error, result) {
// 결과와 관련된 행동을 취한다
})
Web3.js
솔리디티 컨트랙트를 완성한 후,
이 컨트랙트와 상호작용하는 사용자 단의 자바스크립트 코드를 작성해야 한다.
이더리움은 Web3.js라고 하는 자바스크립트 라이브러리를 가지고 있음.
Web3.js가 구축된 컨트랙트와 어떤 방식으로 상호작용하는지에 대한 샘플 코드
// 여기에 우리가 만든 컨트랙트에 접근하는 방법을 제시한다:
var abi = /* abi generated by the compiler */
var ZombieFactoryContract = web3.eth.contract(abi)
var contractAddress = /* our contract address on Ethereum after deploying */
var ZombieFactory = ZombieFactoryContract.at(contractAddress)
// `ZombieFactory`는 우리 컨트랙트의 public 함수와 이벤트에 접근할 수 있다.
// 일종의 이벤트 리스너가 텍스트 입력값을 취한다:
$("#ourButton").click(function(e) {
var name = $("#nameInput").val()
// 우리 컨트랙트의 `createRandomZombie`함수를 호출한다:
ZombieFactory.createRandomZombie(name)
})
// `NewZombie` 이벤트가 발생하면 사용자 인터페이스를 업데이트한다
var event = ZombieFactory.NewZombie(function(error, result) {
if (error) return
generateZombie(result.zombieId, result.name, result.dna)
})
// 좀비 DNA 값을 받아서 이미지를 업데이트한다
function generateZombie(id, name, dna) {
let dnaStr = String(dna)
// DNA 값이 16자리 수보다 작은 경우 앞 자리를 0으로 채운다
while (dnaStr.length < 16)
dnaStr = "0" + dnaStr
let zombieDetails = {
// 첫 2자리는 머리의 타입을 결정한다. 머리 타입에는 7가지가 있다. 그래서 모듈로(%) 7 연산을 하여
// 0에서 6 중 하나의 값을 얻고 여기에 1을 더해서 1에서 7까지의 숫자를 만든다.
// 이를 기초로 "head1.png"에서 "head7.png" 중 하나의 이미지를 불러온다:
headChoice: dnaStr.substring(0, 2) % 7 + 1,
// 두번째 2자리는 눈 모양을 결정한다. 눈 모양에는 11가지가 있다:
eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
// 셔츠 타입에는 6가지가 있다:
shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
// 마지막 6자리는 색깔을 결정하며, 360도(degree)까지 지원하는 CSS의 "filter: hue-rotate"를 이용하여 아래와 같이 업데이트된다:
skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
zombieName: name,
zombieDescription: "A Level 1 CryptoZombie",
}
return zombieDetails
}
그런 다음,자바스크립트 코드가 위의 zombieDetails에서 생성된 값을 받아
웹 브라우저 기반 자바스크립트의 기능(Vue.js 등)을 활용하여 이미지를 변경하고 CSS 필터를 적용하면 된다
'텃밭 1 : BlockChain > Solidity' 카테고리의 다른 글
[Solidity] Faucet을 구현하는 솔리디티 컨트랙트 분석 (0) | 2022.03.27 |
---|---|
[Solidity] Data type (0) | 2022.03.25 |
[실습 | 블록체인] Mnemonic Wallet 개발하기 (0) | 2022.03.17 |
[크립토좀비] Solidity Path : 3. 고급 솔리디티 개념 (0) | 2022.02.22 |
[크립토좀비] Solidity Path : 2. 좀비가 희생물을 공격하다 (0) | 2022.02.19 |