본문 바로가기
블록체인 기술사업 교육/Solidity

블록체인 기술사업 교육 8&9일차

by Mecodata 2023. 4. 12.

솔리디티(Solidity)

정의

- 블록체인 플랫폼에서 Smart Contract 작성과 구현에 사용되는 계약 지향 프로그래밍 언어

특징

- 정적 타입 언어(Statically Typed) = 컴파일 시 변수의 타입이 결정되는 언어 => 프로그래머가 변수에 들어갈 값의 형태에 따라 직접 타입을 명시

- EVM(Ethereum Virtual Machine) = 이더리움 블록체인 네트워크의 참여자(노드)가 공유하는 하나의 가상 머신이자 이더리움 전체를 작동하는 엔진

- 튜링 완전성 = 가능한 모든 형태의 거래를 코드로 작성할 수 있음 + 컴퓨터 코드 작업마다 수수료인 가스(Gas)를 부과해 악의적인 공격을 방어함

Smart Contract 기본 구조

// SPDX-License-Identifier: GPL-3.0 => SPDX 라이선스 식별자(GPL 3.0 버전 라이선스 하에 있다는 것을 의미)

// Solidity 버전 선언
pragma solidity >=0.8.2 <0.9.0; // 0.8.2 이상 0.9.0 미만 버전 사용

// 컨트랙트 코드 작성
contract A {

}

SPDX 라이선스 식별자 = 라이선스 버전 표시 (맨 윗줄에)

- pragma solidity = 솔리디티 버전을 선언

- contract = 배포할 컨트랙트 코드를 작성

- ABI, 컨트랙트 주소는 유출되면 안되는 정보

ABI(Application Binary Interface) = 두 개의 바이너리 프로그램 모듈 사이의 인터페이스

- 조회 기능을 실행할 때는 가스 발생 X

변수 선언 후 끝에 ;(세미콜론) 입력 필수

 

데이터 타입

Boolean

- bool로 입력

- 참/거짓

- &&, ||, !, ==, !=

Integer

- int(정수), uint(0&양수)로 입력

- Solidity는 소숫점이 있는 숫자(실수) 미지원

- +,-,*,/,%,**

- 정의 없이 선언만 하면 0 반환 => 0이 기본값

- 범위에 따라 8, 16, 32, 64, 128, 256을 붙여 입력가능(int = int256, uint = uint256)

Address

- address로 입력

- 계정의 주소

- 20bytes로 크기 고정

string

- 문자열

- 정의 없이 선언만 하면 빈 문자열 반환 => ""이 기본값 

bytes

- byte1~byte32로 크기 지정 가능

 

함수(function)

선언방법

1. parameter와 return값이 없는 경우 => function 함수명 () 접근제어자 {실행문}

2. parameter는 있고 return값이 없는 경우 => function 함수명 (타입 변수명) 접근제어자 {실행문}

3. parameter와 return값이 는 경우 => function 함수명 (타입 변수명) 접근제어자 returns(반환할 데이터 타입) {실행문}

함수 parameter는 전역변수와의 구별을 위하여 parameter명 앞에 _를 붙이는 것이 관례

함수 parameter로 string이나 구조체(Struct)를 사용하기 위해서는 memory라는 키워드를 함께 입력해야 함

변수 활용 범위 설정

- view = 함수 밖의 변수들을 읽을 수 있으나 변경 불가능

- pure = 함수 밖의 변수들을 읽지 못하고, 변경도 불가능

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

contract View_example{
    uint public a = 1; // 함수 밖 변수 활용 가능
    function read_a() public view returns(uint256){
        return a+2;
    } 
}

contract Pure_example{
    function read_a() public pure returns(uint256){
        uint a = 1; // 함수 안에 있는 변수만 활용 가능
        return a+2;
    } 
}

접근제어자

- public = 어디서든 접근 가능

- private = private이 정의된 스마트 컨트랙트에서만 접근가능 => private인 함수는 함수명 앞에 _를 붙이는 것이 관례

- external = 외부 스마트 컨트랙트에서만 접근 가능

- internal = internal이 정의된 스마트 컨트랙트 내에서, 상속받은 자식 스마트 컨트랙트에서만 접근 가능

배열(array)

- [타입[] 접근제한자 변수명] 형식으로 생성

- push() = 배열 맨 뒷 순서에 원소 추가

- pop() = 배열 마지막 원소 제거 + 배열 길이 1 감소

- delete = 원하는 인덱스에 해당하는 원소 제거 (제거된 원소의 인덱스에는 기본값(0, "") 자동 입력 => 배열 길이 유지)

// SPDX-License-Identifier:GPL-30
pragma solidity >= 0.7.0 < 0.9.0;
 
contract lec18{
    uint256[] public arr; // 동적 배열 생성
    uint256[10] public fixedSizeArr; // 고정 배열 생성
  
    function getLength() public view returns(uint256) {
        return ageArray.length; // 배열 길이
    }
    function push(uint256 _age) public {
        ageArray.push(_age); // 배열 원소 추가
    }
    function change(uint256 _index, uint256 _age) public {
        ageArray[_index] = _age; // 배열 원소 수정
    }
    function get(uint256 _index) public view returns(uint256) {
        return ageArray[_index]; // 배열 원소 조회
    }
    function pop() public {
        ageArray.pop(); // 배열 마지막 원소 삭제 및 배열 길이 1 감소
    }
    function delete(uint256 _index) public {
        delete ageArray[_index]; // 배열 원소 삭제
    }
}

매핑(mapping)

- 키(key):값(value) 형태로 저장되고 제공된 키를 가지고 값을 얻어낼 수 있음

- length를 구할 수 없음

- [mapping(의 타입 =>의 타입) 접근제한자 변수명] 형식으로 정의

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

contract Map{
    mapping(uint=>string) private foodList;
        
    function setList(uint _index, string memory _food) public {
        foodList[_index] = _food;
    }
    
    function getFood(uint _index) public view returns(string memory){
        return foodList[_index];
    }
}

구조체(struct)

- 특별한 타입 생성에 이용

- [struct 구조체명 {타입 변수명, 타입 변수명, ...}] 형식으로 생성

- [구조체명.변수명]을 통해 데이터 호출 

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

contract Movie{
    struct Character{
        uint age;
        string name;
        bool completed;
    }
    
     function create(uint _age, string _name) public {
        Character A = Character(_age, _name, false);
        Character A = Character({age: _age, name: _name, completed: false});
		
        uint old = 2;
        A.age = old;
    }
    
}

생성자(constructor)

- 스마트 컨트렉트가 생성, 배포, 인스턴스화 될 때 파라미터를 입력받아 초기값을 설정해주는 용도로 사용

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Base contract X
contract X {
    string public name;

    constructor(string memory _name) {
        name = _name;
    }
}

enum

- 개발자에 의해 정의된 상수세트 타입

- enum enum명 {상수1, 상수2, ...} 형식으로 생성

- 한개의 enum당 256개까지 저장(인덱스는 0~255)

- uint로 변환해서 사용 가능

 

상속

- [contract 컨트랙트명 is 상위 컨트랙트명] 형식으로 상위 컨트랙트를 상속받음

- 상위 컨트랙트를 하나만이 아닌 두 개 이상 입력하여 상속받을 수 있음

=> 상위 컨트랙트가 두 개 이상일 경우 마지막에 입력된 컨트랙트를 우선적으로 상속함 (상속받은 최신순)

- super = 하위 컨트랙트에서 상위 컨트랙트의 함수를 사용할 때 이용 

오버라이딩

- 상위 컨트랙트로부터 상속 받은 메서드를 재정의하여 사용하는 것

- 상위 컨트랙트에 있는 오버라이딩 함수에 virtual 입력되어 있어야 함

- 하위 컨트랙트에서는 메서드 정의 시 접근제어자 다음으로 override를 입력하여 메서드를 재정의하면 됨  

- 상속하는 상위 컨트랙트가 두 개 이상일 경우에는 override(컨트랙트명1, 컨트랙트명2, ...)으로 입력해줘야 함

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// 최상위 컨트랙트
contract A {
    event Log(string message);
    function foo() public virtual {
        emit Log("A.foo called");
    }

    function bar() public virtual {
        emit Log("A.bar called");
    }
}
// B가 A를 상속
contract B is A {
    function foo() public virtual override {
        emit Log("B.foo called");
        A.foo();
    }

    function bar() public virtual override {
        emit Log("B.bar called");
        super.bar(); // A의 bar 적용
    }
}
// C가 A를 상속
contract C is A {
    function foo() public virtual override {
        emit Log("C.foo called");
        A.foo();
    }

    function bar() public virtual override {
        emit Log("C.bar called");
        super.bar(); // A의 bar 적용
    }
}
// D가 B,C를 상속(우선순위는 C > B)
contract D is B, C {
    function foo() public override(B, C) {
        super.foo(); // C의 foo가 적용
    }

    function bar() public override(B, C) {
        super.bar(); // C의 bar가 적용
    }
}

 

이벤트

- 블록체인 네트워크의 블록에 특정값을 기록하는 것

- [event 이벤트명 (타입 변수명)] 형식으로 입력

- 이벤트를 활용할 함수의 실행문에서 [emit 이벤트명(파라미터1, 파라미터2, ...)] 형식으로 입력하여 함수 실행 시 이벤트 출력 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract Event {
    event Log(address indexed sender, string message);
    event AnotherLog();

    function test() public {
        emit Log(msg.sender, "Hello World!");
        emit AnotherLog();
    }
}

에러 처리

- assert(조건문) = gas를 다 소비한 후, 특정한 조건에 부합하지 않으면 에러 발생
- revert("에러메시지") = 조건없이 에러 발생 + gas 환불 
- require(조건문, "에러메시지") = 특정한 조건에 부합하지 않으면 에러 발생 + gas 환불

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

contract assertPractice{
    function assertNow() public pure{
        assert(false); // 가스 모두 소모 후 조건 비만족시 에러 발생
    } 
}

contract revertPractice{
	revert("Revert!"); // 에러 발생 + 가스 환불
}

contract requirePractice{
	require(owner == msg.sender, "Your not manager!"); // 조건 미만족시 에러 발생
}

인터페이스

- 다른 컨트랙트와 상호작용 가능

- 함수 선언만 가능하고 구현 불가 (실행문 미입력)

- 선언한 함수는 반드시 external이어야 함

- Java처럼 implements를 따로 입력할 필요없이 컨트랙트 내에서 인터페이스의 함수의 실행문을 마저 입력하면 됨

- enum과 struct 사용 가능

- 변수, 생성자 사용 불가능

- 코드 없이 이미 배포된 컨트랙트를 인터페이스를 사용하여 호출할 수 있음

 

balance, msg, payable, onlyOwner

- 주소.balance = 참조한 주소의 현재 이더 잔액

- msg.sender = 현재 함수를 호출한 사람 혹은 스마트 컨트랙트의 주소를 나타내는 변수

- msg.value = 송금액

- payable = 함수가 이더(Either)를 전송할 수 있도록 하는 키워드

- onlyOwner = 소유자만 접근 가능하도록 하는 제어자

- keccak256() = 해시함수

 

modifier

- 함수 호출 전후에 실행할 수 있는 코드 설정 (주로 require를 이용한 사전체크에 사용)

- 문법 마지막에 _; (이 부분에 함수를 넣는다는 것을 의미)를 사용

- 어떤 함수에 특정 모디파이어를 적용하려면 함수의 접근제한자 바로 뒤에 입력

// 파라미터 값이 없는 경우   
   modifier 모디파이어명{
         require 혹은 revert
         _;
    }
 
 // 파라미터 값이 없는 경우
    modifier 모디파이어명(파라미터){
         require 혹은 revert
         _;
    }

 

'블록체인 기술사업 교육 > Solidity' 카테고리의 다른 글

Truffle  (0) 2023.05.17
블록체인 기술사업 교육 11일차 (Solidity)  (0) 2023.04.17

댓글