Solidity 시작하기

707·2022년 7월 11일
1

솔리디티

목록 보기
1/5
post-thumbnail

💬 솔리디티란?

솔리디티(Solidity)는 이더리움 등 블록체인 플랫폼에서 스마트 컨트랙트 작성과 구현에 사용되는 계약 지향 프로그래밍 언어이다.

이더리움이 비트코인과 다른 가장 큰 특징은 트랜잭션에 코드를 담을 수가 있다는 점일 것이다. 트랜잭션에 담긴 코드는 대부분 계약서의 형태로 동작하게 된다. 기존의 계약 시스템에서는 중요한 거래가 있을 때에 법원에서 공증을 받아서 그 효력을 인정받았던 것과 달리, 오직 코드만으로 자동화된 처리가 가능해짐으로써 믿을 수 있는 거래가 가능해진 것이다. 이를 스마트컨트랙트라고 부른다.

이 기능을 이용하면 우리는 블록체인에 과거에 일어났던 일이 아닌 미래에 일어날 일을 기록할 수 있게된다. 또한 법원이나 은행 등과 같은 외부기관의 개입 없이도 신뢰성있는 개인간의 거래가 가능해진다.

(❗️공증 세대와 스마트컨트랙트 세대 👈 읽어보세요 )

이 과정에서 필수적으로 알아야하는 개념이 바로 그 계약을 쓰는 언어인 솔리디티와 그 컨트랙트 코드가 실행되는 독립적인 실행공간 EVM이다.

솔리디티 언어는 컴파일러solc에 의해 바이트코드로 컴파일되고, 컴파일된 바이트코드는 트랜잭션에 담겨 블록에 저장되게 된다.


💬 Solidity vs Typescript

1. Typescript로 class 작성

기존에 써왔던 타입스크립트로 클래스 하나를 만들어보자

class HelloWorld {
	public text: string;
	
	constructor() {
		this.text = 'Hello World';
	}

	getText(): string {
		return this.text;
    }
  	
  	setText(_text: string): void {
      	this.text = _text;
    }
}
  1. text가 담긴 인스턴스를 생성하고
  2. 해당 text를 리턴하는 getText 메소드와
  3. text를 바꿔주는 setText 메소드를 가지고 있는

간단한 HelloWorld 클래스를 만들었다.

그러면 이 typescript코드를 solidity로 바꾸면서 어떤 점이 다른지 확인해보자.

2. Solidity로 Contract 작성

위에서도 언급했듯 Solidity는 객체지향 언어이다. 하나의 contract는 곧 하나의 객체로 볼 수 있다.

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

contract HelloWorld {
  string text;

	constructor() {
		text = "Hello World";
	}

	function getText() public view returns(string memory) {
		return text;
	}

  	function setText(string memory value) public {
   		text = value;
  	}
}

상단에 solidity의 버전을 명시해줘야하며,
세미콜론이 반드시 있어야한다는 점이나,
this를 사용하지 않는 점,
contract 내부에서 함수를 정의할 때에 function 키워드를 포함해야 한다는 점, memory의 사용 등이 눈에 띄는 JS/TS와의 차이점이다.

또한 string, number 등으로 타입을 지정했던 TS와 다르게
솔리디티에서는 트랜잭션 가스비(수수료)가 코드가 필요로 하는 메모리자원 등에 의해 결정되는 점에 따라 효율적인 메모리 배정을 위하여 uint16 ~ uint256 등으로 타입이 더 세분화되어있다는 차이점도 있다!

솔리디티의 더 자세한 문법과 사용법은 앞으로 차차 공부해갈 예정이니 일단 이 정도만 정리하였다. 아직 잘 모름 ㅎㅎ...


💬 컨트랙트 배포해보기

컨트랙트의 작성 및 배포는 다음과 같은 순서로 이루어진다.

  1. solidity 코드 작성 (.sol)
  2. 컴파일하기
  3. geth 및 콘솔 실행
  4. 콘솔에서 abi, bytecode로 txObject 만들어 트랜잭션보내기
  5. 마이닝 하여 트랜잭션풀에 담긴 트랜잭션을 블록에 넣기
  6. getTransactionReceipt로 contractAddress 확인하기
  7. contract와 instance 생성하기
  8. 작성했던 contract의 메소드 사용해보기
  9. setText로 컨트랙트의 상태 변경하는 트랜잭션 보내기
  10. 마이닝하여 9번의 트랜잭션을 블록에 넣기
  11. 변경된 컨트랙트의 상태 확인하기

1. solidity코드 작성

루트디렉토리 내에 Contracts 디렉토리 생성 후 내부에 HelloWorld.sol 작성
vscode에서 확장프로그램 solidity 검색하면 syntax hightlight가 된다.
내용은 위의 2. Solidity로 Contract 작성 파트의 코드와 동일.

2. 컴파일하기

solidity의 컴파일러를 설치하는 방법에는 여러가지가 있지만 현재 nodejs 런타임에서 사용하고 있으니 간단하게 npm을 이용해 컴파일러를 설치할 수 있다.

npm install solc

아래와 같은 코드로 컴파일을 진행한다.

npx solc --bin --abi ./Contracts/HelloWorld.sol

컴파일의 결과로

  1. .sol파일을 바이너리코드로 변환한 .bin파일과
  2. 컨트랙트 객체의 구조를 담은 .abi파일이 생성된다.

위 코드를 변환한 abi파일은 다음과 같다.

[
   {
      "inputs":[
         
      ],
      "stateMutability":"nonpayable",
      "type":"constructor"
   },
   {
      "inputs":[
         
      ],
      "name":"getText",
      "outputs":[
         {
            "internalType":"string",
            "name":"",
            "type":"string"
         }
      ],
      "stateMutability":"view",
      "type":"function"
   },
   {
      "inputs":[
         {
            "internalType":"string",
            "name":"value",
            "type":"string"
         }
      ],
      "name":"setText",
      "outputs":[
         
      ],
      "stateMutability":"nonpayable",
      "type":"function"
   }
]

abi는 Application Binary Interface로,
abi에는 contract 객체가 constructor 함수, getText 함수, setText 함수로 이루어져 있으며 각 함수의 input, output의 변수명과 타입 등에 대한 인터페이스 정보가 담겨있다.

3. geth 및 콘솔 실행

geth --datadir node --http --http.addr "0.0.0.0" --http.port 9000 
--http.corsdomain "" --http.api "admin,eth,debug,miner,net,txpool,personal,web3" 
--syncmode full --networkid 707 --port 30300 
--ws --ws.addr "0.0.0.0" --ws.port 9005 --ws.origins "" 
--ws.api "miner,eth,net,web3" 
--allow-insecure-unlock --unlock "0,1" 
--password "./node/password"

지난 explorer 제작 프로젝트에 사용했던 geth private network를 이용했으며 몇가지 옵션을 추가해주었다.

  • --allow-insecure-unlock : 디폴트로는 account를 이용해 트랜잭션을 발생시키려고 할 때 보안을 위해 lock이 걸려있는 상태이므로 매번 lock을 풀어줄 필요 없도록 해주는 옵션
  • --unlock "0,1" : eth.accounts의 배열 인덱스. 0번과 1번 인덱스의 account를 unlock상태로 만들어줌
  • --password "./node/password" : 위 계정을 unlock시키기 위한 account의 비밀번호 파일을 해당 경로에 미리 만들어둠. (별도의 양식 없이 비밀번호에 해당하는 텍스트만 입력해두면 됨)

콘솔 실행

geth attach http://127.0.0.1:9000


4. 콘솔에서 트랜잭션 보내기

> bytecode = "0x"+ ".bin파일내용"
> abi = ".abi파일내용"
> txObject = {from: eth.coinbase, data: bytecode}
> eth.sendTransaction(txObject)

컴파일링한 solidity파일의 바이트코드를 트랜잭션의 data에 담아 트랜잭션을 발생시킨다.


> txpool
> miner.start(4)
...
> miner.stop()

보낸 트랜잭션이 풀에 잘 담겨있는지 확인 후 블록을 마이닝하여 트랜잭션이 블록에 담기도록 해준다.

👍 스마트 컨트랙트의 배포가 끝났다!



5. Contract Address 확인 후 인스턴스 생성

> eth.getTransactionReceipt("트랜잭션 해시") // Contract Address 확인
> contract = eth.contract(abi)
> instance = contract.at("컨트랙트 어드레스")

sendTransaction을 하면 해당 트랜잭션의 해시를 리턴한다.
그 트랜잭션 해시를 이용하여 Contract Address를 확인한다.


❗️ EOA와 CA

이더리움에는 2가지 유형의 계정이 존재한다.

EOA

외부소유계정(Externally Owned Accounts)
공개 이더리움 주소와 개인키 조합의 일반적으로 알고 있는 지갑 주소.
메타마스크, 카이카스 등과 같은 지갑에서 생성한 계정이다.

CA

컨트랙트계정(Contract Account)
컨트랙트는 외부소유계정과 달리 별도의 개인키가 존재하지 않는다.
CA는 스마트컨트랙트를 블록체인에 배포하면 생성되며 다른 계정이 이 컨트랙트에 접근하고자 할 때 사용하는 계정이다.


이 CA와 컴파일링의 결과물인 abi를 사용하여 인스턴스를 생성할 수 있고
이 인스턴스로 컨트랙트에 만들어 둔 메소드에 접근할 수 있다.

> instance.getText.call() // hello World

text의 값인 'Hello World'가 출력된다.

6. 컨트랙트의 상태 변경하기

> instance.setText('hello 707', {from: eth.coinbase})

컨트랙트의 상태를 변경하는 메소드인 setText를 실행한다.
상태를 변경하기 위해서는 트랜잭션이 발생하여야 한다. 즉, 두번째 인자로 트랜잭션을 발생시키는 계정을 입력해야 한다.

3번 과정에서 geth를 열 때 별도의 unlock 없이도 코인베이스 계정이 자유롭게 트랜잭션을 보낼 수 있게 해두었기 때문에 비밀번호의 입력 없이 위처럼만 입력하면 트랜잭션이 발생된다.

이후로는 해당 트랜잭션이 블록에 추가될 수 있도록 마이닝을 진행하고,
블록이 마이닝이 될 때 채굴자의 EVM에서 코드가 실행되며 컨트랙트의 상태가 변경된다.

마이닝이 끝났다면 getText함수를 실행하여 바꾼 내용이 잘 반영되었는지 확인해본다.

> instance.getText.call() // hello 707 

참조

0개의 댓글