[Web3] Solidity 문법 기초 1

Gunter·2024년 7월 25일
0

Web3

목록 보기
2/5

Solidity : 이더리움에서 나온, 스마트 컨트랙트 개발과 발급에 특화된 객체 지향 언어.

스마트 컨트랙트 : 미리 정의된 조건이 충족이 될 경우 블록체인 안에 저장된 프로그램이 작동하는 것. (별도의 인증기관 없이 개인간의 계약이 이루어질 수 있도록 하는 기술)

 

보통 IDE는 Truffle을 사용하지만, 처음이니까 가볍게 시작하기 위해 Online IDE인 Remix 사용

 


Hello Solidity

solidity는 맨 윗줄에 라이센스를 명시해 주어야 에러가 나지 않음.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Hello{
    string public hi = "Hello solidity";
}

SPDX-License-Identifier: GPL-3.0 : 이 라이센스는 무조건 맨위에 명시 해주어야 함

pragma solidity >=0.7.0 <0.9.0; : 솔리디티의 컴파일 버전 명시 ( 즉 0.7 ~0.9 의 버전을 사용)

contract Hello{ : 스마트 컨트랙트 명시

string public hi = "Hello solidity"; : hi 라는 public 함수에 hello solidity 를 넣음( 타입/접근제한/변수명)
}

컴파일


deploy를 눌러서 배포


배포한 컨트랙트


hi를 누르면 Hello solidity가 출력됨

 


Data type

boolean, string, bytes,Integer ,address

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 < 0.9.0;
/*
  data type
  boolean, bytes, address, uint
  
  reference type
  string, Arrays, struct
  
  mapping type
*/
contract lec2{
    // bolean : true/false
    bool public b = false;
    
    // ! || == != &&
    bool public b1 = !false; //true
    bool public b2 = false || true; // true
    bool public b3 = false == true; //false
    bool public b4 = false != false; // false
    bool public b5 = false && true; // false
    
    //bytes 1~32
    bytes4 public bt = 0x12345678;
    bytes public bt2 = "STRING";
    
    //address 
    address public addr = 0xd9145CCE52D386f254917e481eB44e9943F39138;
    
    // int(음수 포함) Vs uint (음수 안 포함)
    
    //int8 : -2^7 ~ (2^7)-1
    int8 public it = -4;
    //uint8 : 0 ~ 2^8-1
    uint8 public it2 = 123;
    
    //uint256 : 0 ~ 2^256-1
    uint256 public it3 = 123;
}


1. boolean : true , false

  • ! (Not) ex) !true => false
  • && (AND) ex) true && false => false
  • || (OR) ex) true && false => false
  • == (equality) ex) true == true => true
  • != (inequality) ex) true != true => false

 

2. string : string을 쓸 땐 ""를 붙여서 쓰기

  • 하지만 솔리디티에선 string 쓰는 것을 지양. 가스를 더 소비하기 때문.
    (가스 : 스마트 컨트랙트를 운영시키는 연료)

솔리디티 입장에서 string을 받아서 다시 byte화 시켜서 이해를 합니다. string과 byte를 왔다갔다 변경하여 가스를 소비하는것보단, 솔리디티입장에서 편하게 byte를 받는것이 더 이득!

 

3. bytes : 솔리디티는 byte1 ~ byte32 까지 존재
뒤에 숫자에따라 byte의 크기 가 정해진다. e.g) byte32 로 쓰면 길이가 32 개.
byte의 크기를 안다면 크기에 맞게 지정해주시는 편이 낫다.

 

4. Integer : int, unit

  • int : 기호있는 integer
    int8 : -2^7 ~ 2^7-1
    int16: -2^15~2^15-1
    int32: -2^31~2^31-1
    int64: -2^63~2^63-1
    int128 : -2^127~2^127-1
    int256 (=int): -2^255~2^255-1

  • uint: 기호없는 integer
    uint8 : 0~2^8-1
    uint16: -0~2^16-1
    uint32: -0~2^32-1
    uint64: -0~2^64-1
    uint128 : -0~2^128-1
    uint256 (=uint): 0~2^256-1

 

5. address : address는 20 bytes 의 길이

  • 스마트 컨트랙트를 배포한다고 할 때, 배포된 스마트 컨트랙트는 주소를 얻는다.
  • 이와 마찬가지로, 디지털 지갑의 계정마다 각자의 주소를 할당 받는다.
  • 이 주소를 통해 디지털 코인을 보내기도 하고, 스마트 컨트랙트를 불러오기도 함.(쉽게, 주소 = 이더 같은 디지털 코인을 주고 받는 은행 계좌번호)


여기서 address를 확인 가능

컴파일 해서 새롭게 배포 하면 스마트 컨트랙트 주소와 달라짐.

 


Ether, Gwei, Wei

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 < 0.9.0;
/*
    1 ether = 10^9 gwei = 10^18wei
    0.000000000000000001 = 1^-18 =1wei
    0.01 ether = 10^16 gwei
*/
contract lec2{
    uint256 public value = 1 ether;
    uint256 public value2 = 1 wei;
    uint256 public value3 = 1 gwei;
}


1 ether = 10^9 Gwei = 10^18 wei 입니다.
다시 말하자면 1^18 wei 는 1 이더를 나타냅니다.

Gwei는 주로 가스를 소비했을때, 사용되는 단위

  • 사용하고자 하는 스마트 컨트랙 안에 정의된 코드의 길이에 따라 가스 비용이 책정됨. 길이가 짧을수록 소비되는 가스가 적어짐.
  • 스마트 컨트랙 안에 무엇으로 정의 되냐에 따라 가스 소비하는 비용이 달라짐. e.g) string, modifer를 사용하는경우 가스가 더 많이 들어감

가스는 왜 만들었을까?

이더리움에 의하면, 가스를 만든이유는 DDoS(Distributed Denial of Service) 공격에서 좀 더 자유로워 지기 위해서
만들었다고 합니다. 예를 들어, 해커가 고의적으로 블록체인 네트워크를 다운 시킬려고, 스마트 컨트랙을 지속적으로 작동하게 반복 시켜 과부화를 준다고 가정 했을때, 해커는 작동을 반복시킬때마다 Gas 비용을 지불해야하죠.

 


Function

정의

function 함수이름() 접근제한  읽기/쓰기 returns(리턴 타입) {
    // 함수 내용 정의
}
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 < 0.9.0;


contract lec4{
    /*
    function 이름() public { // (public,private,internal,external) 변경가능 
        // 내용
    }
    */
   
   uint256 public a = 3;
   //1. parameter 와 return 값이 없는 function 
   function changeA1() public{
       a = 5;
   }
   
   //2. parameter 값이 있는 function 
   function changeA2(uint256 _value) public{
       a = _value;
   }
   
   //3. return 값이 있는 function
   function changeA3() public view returns(uint256){
       return a;
   }
   //4. parameter 와 return 값이 있는 function 
   function changeA4(uint256 _value) public returns(uint256){
       a = _value;
       return a;
   }
}

 

public, private, internal, external

  • Public: 모든 컨트랙트 및 계정에서 호출 가능

  • Private : 오직 컨트랙트 안에 정의된 함수에서만 사용 가능 (private이 정의된 현재 이 컨트랙트를 상속받은 자식 컨트랙트도 접근 불가)

  • Internal : internal 함수를 상속받은 컨트랙트 안에서 사용 가능(private에서 한가지 기능(상속받은 자식 접근 가능)이 더 추가)

  • External : 오직 다른 컨트랙트나 계정에 의해서만 호출 가능

  • 상태변수는 public, private, internal에서 선언 가능(external에서는 불가)

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 < 0.9.0;

contract lec5{
    
    //1.public
    uint256 public a = 3;
    
    //2.private
    uint256 private a2 = 5;
    
    
}


contract Public_example {
    uint256 public a = 3;
    
    function changeA(uint256 _value) public {
        a =_value;
    }
    function get_a() view public returns (uint256)  {
        return a;
    }
}

contract Public_example_2 {
    
    Public_example instance = new Public_example();

    function changeA_2(uint256 _value) public{
      instance.changeA(_value);
    }
    function use_public_example_a() view public returns (uint256)  {
        return instance.get_a();
    }
}

contract private_example {
    uint256 private a = 3;
    
    function get_a() view public returns (uint256)  {
        return a;
    }

}

contract external_example {
    uint256 private a = 3;
    
    function get_a() view external returns (uint256)  {
        return a;
    }

}

contract external_example_2 {
    
    external_example instance = new external_example();

    function external_example_get_a() view public returns (uint256)  {
        return instance.get_a();
    }
}

 

View, Pure

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 < 0.9.0;
/*
view : function 밖의 변수들을 읽을수 있으나 변경 불가능
pure : function 밖의 변수들을 읽지 못하고, 변경도 불가능
viwe 와 pure 둘다 명시 안할때: function 밖의 변수들을 읽어서, 변경을 해야함.이 정의된 현재 이 컨트랙을 상속받은 자식 컨트랙도 접근가능)
*/
contract lec6{
     uint256 public a = 1;
    
    function viewExample() public view returns(uint256){
        return a+2;
    }
    
    function readAndChangeA() public returns(uint256){
        a = 3;
        return a+2;
    } 
    
    function pureExample() pure public returns(uint256){
        uint256 a2 = 3;
        return a2+2;
    } 
}

view : storage state 를 읽을 수 있지만, 그 state 값을 변경할 수 없다.
function의 밖에 있는 것들은 storate에 저장이 되니까 이 예제에서는 a가 storage state.
read_a()라는 간단히 a값을 리턴하는 함수를 만들었으니, storage state를 읽었다고 볼 수 있다. 그렇기 때문에 view를 넣어야 함.

pure : storage state 를 읽으면 안되고, 그 state값을 변경할 수 도 없다.
pure는 storage state를 읽지 못하고, 변경도 불가하니 함수 밖의 외부의 값을 가져온다.
그러니 함수 내에 정의된 로컬변수들과 논다.

 


storage, memory, calldata, stack

solidity 는 storage, memory, calldata ,stack 이렇게 4개의 저장 영역으로 나뉘어 있다.

storage : 대부분의 변수, 함수들이 저장되며, 영구적으로 저장이되어 가스 비용이 비싸다.

memory: 함수의 파라미터, 리턴값, 레퍼런스 타입이 주로 저장이 된다. 함수가 실행을 마칠 때 사라지는 단기 휘발성 메모리.

Calldata : 주로 external function 의 파라메터에서 사용 된다. 예를 들어 함수를 실행할 때 파라메터의 값 자체를 calldata로 받을 수 있습니다. calldata로 받게 된다면, 값은 변경할 수 없고 읽기만 가능합니다. (모든 입력 함수의 인자와 실행 데이터를 저장하는 곳)

stack: EVM (Ethereum Virtual Machine) 에서 stack data를 관리할때 쓰는 영역인데 1024Mb 1024개의 data를 제한적으로 저장해 사용할 수 있다. 예를 들어, 함수를 실행할 때 로컬 변수와 같은것들을 잠시 기억할 때 EVM이 사용된다.

 

Memory vs Calldata

CallData와 memory라는 접두사는 오직 Solidity에만 존재하는 접두사이다.

  • Memory : 함수 호출 시에만 존재하는 휘발성 데이터가 위치하는 곳
  • CallData : Call에 사용되는 Data, 함수 호출 시 인자로 포함된 데이터들이 위치하는 공간
  • Memory와 CallData의 차이점은 Memory는 수정이 가능, CallData는 수정이 불가
  • CallData는 CallData에 포함된 데이터를 사용, Memory는 CallData에서 데이터를 가져와서 별도의 카피본을 만들어서 사용한다.
  • Memory를 사용하면 CallData에 비해서 가스비가 더 많이 발생함
  • 두 접두사의 사용
    • Memory : 읽기와 수정이 필요하지만 블록체인 상태 업데이트는 필요 없는 경우
    • CallData : 함수의 파라미터에 사용, 가스비를 절약할 수 있음

0개의 댓글