1. 기본 구조
Solidity 는 "contracts" 안에 캡슐화 되어 있다. 하나의 Contract는 하나의 기본 블럭이며 모든 변수들과 함수들은 이 Contract 안에 들어 있다.
contract 작성 전 Pragma version을 작성해주어야 한다. 컴파일러 버전이 업그레이드되며 다르게 적용되는 규칙으로 나오는 에러를 예방할 수 있다.
2. 변수
State variables은 영원히 contract storage에 저장된다. 즉, 이 변수들은 Ethereum blockchain 상에 적히게 된다는 뜻 ! 블록체인에 적힌다는 것이 곧 영원히(?) 유지되기 때문
Solidity에서 uint (unsigned integers) 는 256-bit unsigned integer 이다. uint8, uint16, uint32으로 선언할 수 있지만 일반적으로 uint를 사용한다. (특이한 케이스 제외)
struct은 여러개의 속성을 가진 데이터 타입을 만들어 낸다.
struct Zombie {
string name;
utin dna;
}
3. 배열
solidity에는 두 가지의 arrays 종류가 있다.
- fixed : 요소의 수가 고정된 배열
- dynamic : 요소의 수가 유연한 배열
uint[2] fixedArray; // 2개의 수를 가지는 고정 배열
string[5] stringArray; // 5개의 string 값을 가지는 고정 배열
uint[] dynamicArray; // 고정되지않고 계속해서 값이 커질 수 있는 배열
Zombie[] zombieArray; // Zombie struct 로도 타입을 지정할 수 있다.
public Arrays - "public"이 배열에 붙게 된다면 solidity는 자동적으로 "getter" 매서드를 생성할 것이다.
4. 함수
Functions
solidity에서 함수는 아래와 같이 선언한다.
function eatHamburgers(string memory _name, uint _amount) public {
}
함수의 이름 : eatHamburgers
함수 공개 여부 : public
인자값 2개
- 첫번째 매개변수 : _name (type = string, _name, 변수가 저장되는 위치 = memory)
- 두번째 매개변수 : _amount (type = uint, _amount)
* 매개변수의 이름 정하는 convention 은 보통 "_" underscore를 앞에 붙이는 것!
* 변수가 저장되는 위치는 타입이 reference types = arrays, structs, mappings, strings인 경우 정해주어야 한다.
그 이유는.... By value : solidity 컴파일러가 파라미터 값의 새로운 복사본을 만들어 함수에 전달한다. 최초의 파라미터 값이 변할 걱정이 없다.
By reference : 함수가 기존의 변수를 참조하는 값으로 불려지므로 만약 함수가 이 값을 변경시키는 코드가 있다면 기존 값 또한 달라지게 된다.
지금까지의 내용과 위 만든 struct Zombie로 좀비를 생성해서 zombies 배열에 push, 담기 코드 👇👇
pragma solidity >=0.5.0 <0.6.0;
contract ZombieFactory {
uint dnaDigits = 16;
uint dnaModulus = 10 ** dnaDigits;
struct Zombie {
string name;
uint dna;
}
Zombie[] public zombies;
function createZombie(string memory _name, uint _dna) public {
zombies.push(Zombie(_name, _dna));
}
}
이제 위 코드에 계속해서 배우는 내용을 덧붙일 예정이다
Pivate vs Public Functions
public 🗣 어디에 계신 누구나 이 함수를 호출하고 실행시켜도 됩니다~~~
private 🗣 이 함수가 포함된 contract 내에 있는 함수들만 Only 호출하고 실행가능입니다~~~ 아 그리고 Private 함수는 함수명 앞에 "_" 붙여주세요~~~오옥
solidity에서 함수는 디폴트값으로 public이어서 누구나 (또는 다른 contract도) 해당 함수를 call하고 실행시킬 수 있다. 오남용을 줄이기위해 습관적으로 함수 작성할 때 private로 하고 대외적으로 만들고 싶은 경우에만 public으로 작성하기 !
값을 return 하는 함수
solidity에서 함수는 return하는 값의 타입도 함께 표시해준다.
string greeting = "What's up dog";
function sayHello() public returns (string memory) {
return greeting;
}
Function modifiers
view & pure
greeting을 return하는 위의 sayHello 함수는 in the app, 앱 안에서 어떠한 데이터에 변화를 주지 않는다. 접근하고 읽기는 하되 Update Or Delete, 수정 또는 삭제는 없다. 이런 경우 위의 함수를 view (그냥 보는) modifier 로 표시할 수 있다.
function sayHello() public view returns (string memory) {
하지만 다른 곳 In the app 에서 데이터를 읽어오지도, 접근조차하지 않는 함수라면 ? pure modifier로 표시를 해준다.
function _multiply(uint a, uint b) private pure returns (uint) {
return a * b;
}
위의 _multiply 함수는 private 함수여서 함수명 앞에 "_"가 붙었다. 이 함수의 매개변수 a, b 를 받고 둘을 곱한 값을 return한다. 이 함수는 본인이 받는 매개변수로만 값을 리턴하고 다른 함수를 호출하거나 데이터를 읽어오거나 하지 않으므로 pure 이다.
5. keccak256
Ethereum은 "keccak256"이라는 (SHA3 버전의) 해시 함수가 빌트인으로 있는데 이 함수는 input값을 랜덤한 256bit의 16진수의 수로 변환시킨다. Input값의 아~주 작은 차이라도 결과값은 180도 달라진다. keccak256은 input값으로 bytes타입의 단 하나의 매개변수를 필요로 하기 때문에 우리가 매개변수를 pack 시켜서 주어야한다.
//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256(abi.encodePacked("aaaab"));
//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256(abi.encodePacked("aaaac"));
"b" / "c" 만 다른데 결과값은 아예 다르다.
6. typecasting
데이터 타입을 변경시키는 기능이다.
uint8 a = 5;
uint b = 6;
uint8 c = a * b;
// throws an error because a * b returns a uint, not uint8
uint8 c = a * uint8(b);
// we have to typecast b as a uint8 to make it work
a는 uint8이고 b는 아무것도 안쓴 디폴트값으로 256으로 설정되어 있다. unit8 타입인 c에 a * b를 하려니 에러가 난다. b의 값이 uint256이기 때문이다. 이 경우 uint8(b) 로 데이터의 타입을 맞춰주면 에러가 나지 않는다.
7. Events
event란 contract를 작성해서 배포한 Blockchain 상에서 일어난 일을 app front-end에게 어떤 "이벤트"가 생겼다고 알려주는 것입니다. 무언가 일이 생기면 프론트엔드가 해당 사건 "듣고" 바로 "take actions" 어떤 액션을 취할 수 있도록!
example ) solidity smartcontract
// declare the event
event IntegersAdded(uint x, uint y, uint result);
function add(uint _x, uint _y) public returns (uint) {
uint result = _x + _y;
// fire an event to let the app know the function was called:
emit IntegersAdded(_x, _y, result);
return result;
}
코드를 보면 emit IntegersAdded(_x,_y,result); 는 그냥 위에 event를 emit 시키는 것뿐이다. 블록체인 상에서는 어떤 변화가 생기는 것이 아니고 프론트엔드에게 알려 해당 이벤트에 맞는 변화를 주라고 알려주는... 존재
frontend 코드
YourContract.IntegersAdded(function(error, result) {
// do something with result
})
크립토 좀비 Lesson 1 최종 코드
pragma solidity >=0.5.0 <0.6.0;
contract ZombieFactory {
event NewZombie(uint zombieId, string name, uint dna);
uint dnaDigits = 16;
uint dnaModulus = 10 ** dnaDigits;
struct Zombie {
string name;
uint dna;
}
Zombie[] public zombies;
function _createZombie(string memory _name, uint _dna) private {
uint id = zombies.push(Zombie(_name, _dna)) - 1;
emit NewZombie(id, _name, _dna);
}
function _generateRandomDna(string memory _str) private view returns (uint) {
uint rand = uint(keccak256(abi.encodePacked(_str)));
return rand % dnaModulus;
}
function createRandomZombie(string memory _name) public {
uint randDna = _generateRandomDna(_name);
_createZombie(_name, randDna);
}
}
위의 전체코드 해석은
이전에 자세하게 뜯어보고 공부한 여정(?)을 담은 글을 참조하시면 좋을 것 같습니다!
댓글