[Solidity] 크립토 좀비로 공부하기 - 챕텨2

오늘은 조금더 심화 과정으로 들어갑니다.

한번 정리해보겠습니다.


1. 주소(address)
  • 모든 이더리움 계정은 ETH 잔액을 가집니다.
  • 계정을 통해 다른 계정과 이더를 주고 받을 수 있습니다.
  • "주소는 특정 유저(혹은 스마트 컨트랙트)가 소유한다"라는 점을 이해하고 넘어가면 될 것 같습니다.
2. 매핑(mapping)
  • struct와 비슷하게 솔리디티에서 구조화된 데이터를 저장하는 또다른 방법입니다.
  • HashMap 또는 Hashtable 이라고 생각하면 편합니다.(key - value 구조)
  • 매핑은 기본적으로 키-값 (key-value) 저장소로, 데이터를 저장하고 검색하는 데 이용됩니다.
// 금융 앱용으로, 유저의 계좌 잔액을 보유하는 uint를 저장한다: 
mapping (address => uint) public accountBalance;
// 혹은 userID로 유저 이름을 저장/검색하는 데 매핑을 쓸 수도 있다 
mapping (uint => string) userIdToName;
3. Msg.sender
  • 솔리디티에는 모든 함수에서 이용 가능한 특정 전역 변수들이 있습니다.
  • 그 중의 하나가 현재 함수를 호출한 사람 (혹은 스마트 컨트랙트)의 주소를 가리키는 msg.sender 입니다.
  • 솔리디티에서 함수 실행은 항상 외부 호출자에서 시작됩니다. 컨트랙트는 누군가가 컨트랙트의 함수를 호출할 때까지 블록체인 상에서 아무 것도 하지 않습니다.
  • 그렇기 때문에 항상 msg.sender는 있다고 생각하시면 됩니다.
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];
}
4. Require(조건문 같은 느낌!)
  • require은 특정 조건이 참이 아닐 때 함수가 에러 메시지를 발생하고5 실행을 멈추게 됩니다.
function sayHiToVitalik(string _name) public returns (string) {
  // _name이 "Vitalik"인지 비교한다. 참이 아닐 경우 에러 메시지를 발생하고 함수를 벗어난다
  // (참고: 솔리디티는 고유의 스트링 비교 기능을 가지고 있지 않기 때문에 
  // 스트링의 keccak256 해시값을 비교하여 스트링 값이 같은지 판단한다)
  require(keccak256(_name) == keccak256("Vitalik"));
  // 참이면 함수 실행을 진행한다:
  return "Hi!";
}
5. 상속
  • 컨트랙트는 상속이 가능합니다.
  • java/c#의 상속과 동일한 개념입니다.
  • 문법은 is를 사용하게 됩니다.
  • BabyDoge는 Doge에 정의된 public 함수는 모두 접근이 가능합니다.
contract Doge {
  function catchphrase() public returns (string) {
    return "So Wow CryptoDoge";
  }
}

contract BabyDoge is Doge {
  function anotherCatchphrase() public returns (string) {
    return "Such Moon BabyDoge";
  }
}
6. Import
  • 다른 파일을 불러오는 기능입니다.
import "./someothercontract.sol";

contract newContract is SomeOtherContract {

}
7. Storage vs Memory
  • 솔리디티에는 변수를 저장할 수 있는 공간으로 storage와 memory 두 가지가 있습니다.
  • Storage는 블록체인 상에 영구적으로 저장되는 변수를 의미합니다.
  • Memory는 임시적으로 저장되는 변수로, 컨트랙트 함수에 대한 외부 호출들이 일어나는 사이에 지워집니다.
  • 솔리디티가 알아서 처리해 주기 때문이지 대부분의 경우에 이 키워드들을 이용할 필요가 없습니다.
  • 상태 변수(함수 외부에 선언된 변수)는 초기 설정상 storage로 선언되어 블록체인에 영구적으로 저장되는 반면, 함수 내에 선언된 변수는 memory로 자동 선언되어서 함수 호출이 종료되면 사라지게 됩니다.
  • 하지만 이 키워드들을 사용해야 하는 경우가 있습니다. 바로 함수 내의 구조체와 배열을 처리할 때!!
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;
    // ...이는 임시 변경한 내용을 블록체인 저장소에 저장하고자 하는 경우이다.
  }
}
8. 함수 접근 제어자 더 알아보기
  • private으로 선언된 함수는, 상속받은 컨트랙트에서 접근할 수 없다.
  • internal 접근제어자 : internal은 함수가 정의된 컨트랙트를 상속하는 컨트랙트에서도 접근이 가능하다 점을 제외하면 private과 동일합니다.
  • external 접근제어자 : external은 함수가 컨트랙트 바깥에서만 호출될 수 있고 컨트랙트 내의 다른 함수에 의해 호출될 수 없다는 점을 제외하면 public과 동일합니다.
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();
  }
}
9. Interface(다른 컨트랙트와 상호작용하기)
  • 블록체인 상에 있으면서 우리가 소유하지 않은 컨트랙트와 우리 컨트랙트가 상호작용을 하려면 우선 인터페이스를 정의해야합니다.
  • interface 정의를 할 때에도 contract 명령어를 이용하여 정의한다.
// 임의의 contract
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];
  }
}

// LuckyNumber을 참조하기 위하여 interface 선언
contract NumberInterface {
  function getNum(address _myAddress) public view returns (uint);
}
// 크립토kitty의 공개함수(external로 선언되어 외부에서만 호출할 수 있다.)
// solidity는 그리고 아래 함수처럼 한번에 여러 값을 반환 할 수 있다.
function getKitty(uint256 _id) external view returns (
    bool isGestating,
    bool isReady,
    uint256 cooldownIndex,
    uint256 nextActionAt,
    uint256 siringWithId,
    uint256 birthTime,
    uint256 matronId,
    uint256 sireId,
    uint256 generation,
    uint256 genes
) {
    Kitty storage kit = kitties[_id];

    // if this variable is 0 then it's not gestating
    isGestating = (kit.siringWithId != 0);
    isReady = (kit.cooldownEndBlock <= block.number);
    cooldownIndex = uint256(kit.cooldownIndex);
    nextActionAt = uint256(kit.cooldownEndBlock);
    siringWithId = uint256(kit.siringWithId);
    birthTime = uint256(kit.birthTime);
    matronId = uint256(kit.matronId);
    sireId = uint256(kit.sireId);
    generation = uint256(kit.generation);
    genes = kit.genes;
}
10. Interface 연동(다른 컨트랙트와 연동 방법)
  • 다른 컨트랙트의 주소를 입력하여 참조를 할 수 있다.
// NumberInterface는 위 9.번 내용 소스 참조
contract MyContract {
  address NumberInterfaceAddress = 0xab38...
  // ^ 이더리움상의 FavoriteNumber 컨트랙트 주소이다
  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress)
  // 이제 `numberContract`는 다른 컨트랙트를 가리키고 있다.

  function someFunction() public {
    // 이제 `numberContract`가 가리키고 있는 컨트랙트에서 `getNum` 함수를 호출할 수 있다:
    uint num = numberContract.getNum(msg.sender);
    // ...그리고 여기서 `num`으로 무언가를 할 수 있다
  }
}
11. 다수의 반환 값 처리
  • 다수의 값을 반환하는 방법은 "return (1, 2, 3);" 와 같은 방법을 사용한다.
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();
}
12. if문
  • if문은 여느 언어의 사용법과 동일합니다.
  • 스트링 간의 동일 여부를 판단하기 위해 keccak256 해시 함수를 이용해야 합니다.
function eatBLT(string sandwich) public {
  // 스트링 간의 동일 여부를 판단하기 위해 keccak256 해시 함수를 이용해야 한다는 것을 기억하자 
  if (keccak256(sandwich) == keccak256("BLT")) {
    eat();
  }
}
Sort:  

[US$140.00](▼54%)샤오미 드리미 V10 무선 청소기 / 유럽버전! / 6개월무료A/S / 무료배송/

WWW.QOO10.COM

음... 역시 쓸말이 없군요! ㅋ
즐거운 한주 보내세요^^

외국인 만난 느낌이 ㅎㅎ

댓글들 반응이 ㅎㅎ

눈에 쏙 들어옵니다.
회색바탕에 검은글씨 ㅎㅎㅎㅎ

@happyberrysboy transfered 23 KRWP to @krwp.burn. voting percent : 85.80%, voting power : 82.80%, steem power : 1884924.10, STU KRW : 1200.
@happyberrysboy staking status : 7450 KRWP
@happyberrysboy limit for KRWP voting service : 22.35 KRWP (rate : 0.003)
What you sent : 23 KRWP
Refund balance : 0.649 KRWP [46078746 - 23fd6e4ab6c1d282e6c2d15804f436e458f9f649]