• Home
  • About
    • Jiwon Jeong photo

      Jiwon Jeong

      끊임없이 배우며 성장하는 엔지니어

    • Learn More
    • Email
    • Github
  • Posts
    • All Posts
    • All Tags
    • All Categories
  • Projects

View & Pure

15 Sep 2019

Reading time ~4 minutes

View와 Pure 가스소모에 대한 진실

  1. external : 다른 account 사용자가 해당 코드에 접근가능

  2. internal : 코드 안에서만 동작하게 함

  3. public : (external+internal)

  4. pure func : state를 바꾸지않는 함수

  5. view func : state를 읽는 함수

  • Pure와 View 함수는 함수가 external 일때, 즉 외부에서 함수가 호출되었을 때 Gas가 소모되지 않음

  • 하지만, 다른 함수에서 내부적으로 호출하면 가스 비용 발생


contract PureFunctionTest {

   uint state;

    function addNumbers(uint a, uint b) public pure returns (uint) {
       return a +b ;
   }

   function updateState(uint a, uint b) public {

     uint c = addNumbers(a,b);
     state = c;
   }

   function addThreeNumbers(uint a, uint b, uint c) public pure returns (uint) {

       uint temp = addNumbers(a,b);
       uint num  = addNumbers(temp,c);
       return num;
   }
}
  1. addNumbers : gas 소모 X
  2. updateState : 해당 함수 내에서 addNumbers 호출하기 떄문에 gas 비용 발생
  3. addThreeNumbers : gas 소모 X

Event 처리

  • front 단에서 event 호출하는 함수 실행 시 receipt를 보고 해당 로그 반영 가능
  • 이 event가 발생되었을 때 알림을 받으려면 eventSubscribe를 호출하면됨
myContract.events.MyEvent({
    filter: {myIndexedParam: [20,23], myOtherIndexedParam: '0x123456789...'}, // Using an array means OR: e.g. 20 or 23
    fromBlock: 0
}, function(error, event){ console.log(event); })
.on("connected", function(subscriptionId){
    console.log(subscriptionId);
})
.on('data', function(event){
    console.log(event); // same results as the optional callback above
})
.on('changed', function(event){
    // remove event from local database
})
.on('error', function(error, receipt) { // If the transaction was rejected by the network with a receipt, the second parameter will be the receipt.
    ...
});
  • indexed가 포함되면 검색할 수 있음(DB의 index와 동일)
    • 특정 키로 검색하여 빠르게 인덱싱 가능
    • 만약 index가 없다면 filter 없이 무조건 다 받고 처리하겠다.

Modifier

  • 파이썬에서 function decorator와 비슷
  • _의 의미
    • modifier가 붙어있는 함수에 대한 내용을 실행시켜라 (c언어에서 go to와 같음)
    • 컴파일 시 modifier가 붙어있는 함수에 require()문을 붙여서 같이 컴파일 시킴
      • pickWinner 함수 컴파일 시 require(manager==msg.sender); 구문을 붙여 컴파일
    function pickWinner() public restricted{
        uint index=random()%players.length;
        players[index].transfer(address(this).balance);
    }
    
    modifier restricted{
        require(manager==msg.sender, "Caller is not manager");
        _;
    }

msg.sender

  • 트랜잭션 서명을 가지고 와서 복호화를 해서 나오는 값
    • 메타마스크에서 Tx confirm 버튼을 누르는 행위가 브라우저에 저장된 메타마스크 개인키를 가지고 서명을 한 것
    • 이 때, 서명을 하면 v,r,s가 생성이 되어서 tx 안에 들어가고 이를 컨트랙트가 처리할 때는 v,r,s를 가지고 from을 만들어냄
      • 이 from이 msg.sender 이다!

Require

  • require는 파이썬의 assert와 비슷 => 조건 맞지 않으면 throw error 반환
  • require 조건 맞지 않으면, 해당 Tx은 아예 없었던 것으로 됨
    • 해당 Tx에 있었던 모든 State 변이가 모두 revert됨
    • 아래 if 문과 동일한 문법
  require(manager==msg.sender, "Caller is not manager");

  if(msg.sender != manger) {
    revert("Caller is not manager")
  }

변수의 Private

  • 만약, 변수에 private을 선언하면 해당 데이터를 스토리지에서 보지 못할까?
    • 볼 수 있다!
  • 아래 ownwer 데이터는 CA 어카운트 내 storage의 첫번째 슬롯에 이 값을 넣겠다고 코드가 작성이 되어 있는 것.
    • 어? 이 배포된 컨트랙 주소 뭐야?
    • 이 주소의 첫번째 슬롯에 저장된 값이 뭐지? 하면 바로 나옴
    • 따라서 컨트랙트 짤 때 변수에 private을 넣으면 privacy가 보장된다? => No!!
contract Owner{
  address private owner;
}
  • 만약, public 으로 선언하면, 자동으로 getter 메소드를 만들어준다!
    • 리믹스에서 파란색으로 자동으로 owner 함수 만들어짐
    • 인터페이스가 많아지기 때문에, 배포 시 Gas 비용이 높아짐!

Return

  • return 되는 타입 명시해줄 때, 임시변수를 할당해주면 body에서 return을 해주지 않아도 된다
    • 임시변수를 할당하면, 나중에 dApp 단을 설계할 때 인터페이스 통일 시켜줄 수 있어 가독성이 높아진다.
    uint256 number;

    /**
     * @dev Store value in variable
     * @param num value to store
     */
    function store(uint256 num) public {
        number = num;
    }

    /**
     * @dev Return value 
     * @return value of 'number'
     */
    function retrieve() public view returns (uint256){
        return number;
    }

    function retrieve2() public view returns (uint256 num){
        num = number;
    }

    function retrieve3() public view returns (uint256 num){ // 이렇게 return까지 해주는게 제일 CLean Code!
        num = number;
        return num;
    }

Data Location

  • storage, memory, calldata 중 하나를 명시해야하는 data type이 있음
    • uint, address, bytes32, bool 같은 것들은 primitive type이기 때문
mapping(address => Voter) public voters;

struct Voter {
    uint weight; 
    bool voted;  // if true, that person already voted
    address delegate; // person delegated to
    uint vote;   // index of the voted proposal
}

function getWeightOfVoter(address voterAddress) public view returns (uint256 weight){
  weight = voters[voterAddress].weight;
  return weight
}

  • 위 코드 변형
    • Voter voter = voters[voterAddress]; 하면 에러남(data location 필요하다고)
  • 아래 코드를 보면서 이해하자
    • storage : 해당 data type의 값이 변경될 때
    • memory : 해당 data type의 값이 변경되지 않고, 다른 값을 그냥 copy해서 대입할때
mapping(address => Voter) public voters;

struct Voter {
    uint weight; 
    bool voted;  // if true, that person already voted
    address delegate; // person delegated to
    uint vote;   // index of the voted proposal
}

function getWeightOfVoter(address voterAddress) public view returns (uint256 weight){
  Voter memory voter = voters[voterAddress]; // memory 영역에 voter 변수를 위한 공간을 할당해주세요. 그리고 Storage 영역인 voters에서 해당 값을 읽어 카피해주세요 => 읽어들이는 것이기 때문에 copy하는게 맞음
  weight = voter.weight;
  return weight
}

function setWeightOfVoter(address voterAddress) public returns (uint256 weight){
  Voter storage voter = voters[voterAddress]; // 
  voter.weight += 1;
  weight = voter.weight;
  return weight
}




BlockChainHyperledger Fabric Share Tweet +1