본문 바로가기
프로그래밍/solidity

[220711] 솔리디티코드로 스마트 컨트랙트 작성하기

by 한코코 2022. 7. 4.

1. 솔리디티 코드로 스마트 컨트랙트 작성

2. 컴파일해서 ABI, BIN 파일 만들기

3. Geth로 트랜젝션 발동시키기

4. CA를 사용해 필요한 정보 가져오기

5. 스마트 컨트랙트 흐름 한 눈에 보기

 

 


1.   솔리디티 코드로 스마트 컨트랙트 작성

1.1   솔리디티 코드가 실행되는 원리

코드 -> 컴파일러 -> 바이트코드 -> tx 일으킴

우선 솔리디티 언어는 스마트 컨트랙트를 일으키기 위해서 만들어진 고급언어다.

그래서 이더리움 네트워크에서 코드를 해석하는 EVM이 이해하려면 저수준의 바이트코드로 번역(컴파일)되어야한다.

일단 컴파일되면 고유한 contract 생성 tx를 사용하여 이더리움 네트워크에 배포된다.

그리고 마이닝을 해야 그제서야 코드가 이동된다.

 

1.2   솔리디티 코드 기본형

// SPDX-License-Identifier: MIT //이거 작성 안하면 노란줄뜸
pragma solidity ^0.8.15; //솔리디티 코드 버젼 기술

contract HelloWorld{ }

 

타입스크립 형태와 거의 비슷해서 그렇게 낯설지는 않다.

솔리디티 언어도 객체지향적 언어기 때문에 그렇다.

// 타입스크립트
class helloworld = contract helloworld{
  public text:string

  constructor(){
    this.text = 'Hello World'
  }

  public getText():string{
    return this.text
  }
}
const obj = new Helloworld()
console.log(obj.getText())

 

 

타입스크립트 코드를 솔리디티 코드로 바꾼 코드

하나의 컨트랙트 = 하나의 객체

솔리디티는 세미콜론(;)이 필수다.

여기서도 문법이 맞지 않으면 빨간줄이 뜨는데 보통 빨간 줄 위의 코드가 문제가 있다는 뜻이다.

// 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;
  }
}

 

 

 

 

 

 

2.   컴파일해서 ABI, BIN 파일 만들기

2.1   솔리디티 언어를 컴파일하기

보통 코드를 컴퓨터가 읽을 수 있도록 0101...로 만들어주는데 버젼별로 다르다.

이더리움 네트워크에 있는 evm이 알아들을 수 있는 bytecode로 바꿔주는 버젼이 있다.

 

 

컴파일러 solc 설치

$ npm init -y
$ npm install solc

 

컴파일러 사용하기

$ npx solc [옵션] [디렉토리/파일명]
$ npx solc --bin --abi ./Contracts/HelloWorld.sol
// abi파일과 bin파일을 추출하는 코드

 

 

2.2   솔리디티 언어를 컴파일하는 목적

 

1. Bytecode를 만들기 위해서

    이더리움에 있는 EVM은 저수준 언어인 bytecode만 읽기때문에 솔리디티 언어를 바꿔줘야한다.

2. ABI(Application Binary Interface)를 만들기 위해서

    사용자가 이더리움 네트워크에 객체 형태로 묶어 보낼 방법에 대한 파일

    이미 올라가있는 컨트랙트 파일을 불러서 사용할때 쓰는 파일

 

abi 파일 : json 형태

 

bin 파일 : bytecode 형태

 

 

 

 

3.   GETH로 트랜잭션 발동시키기

3.1   배포 : 블록체인과 이더리움의 차이

블록체인

기본적인 트랜젝션(tx)을 만들때는 From(누가), To(누구에게), Value(무엇을), Data(나머지 정보)를 만들어서 넣었었다.

input, output를 UTXO로 관리를 해서 보낸 입금의 처리

 

이더리움

스마트 컨트랙트를 발생시킬때는 From(누가), Data(bytecode로 어떤 코드를 보낼거냐)만 넣어서 배포해도 충분하다.

To(누구에게), value(무엇을)는 필수사항이 아니라서 넣지 않아도 된다.

tx가 발생되면 스마트 컨트랙트에 대한 tx hash만 발생되지 금액거래에 대한건 생성되지 않는다.

즉 트랜젝션 내용을 봤을때 to가 없으면 금액전송에 대한 내용이 아니라 스마트 컨트랙트에 대한 내용이다-라고 알 수 있다.

 

 

 

3.2   블록체인에서 keystore 파일과 비밀번호의 상관관계

블록체인 방법으로 tx를 발생시키려고할때 비밀번호를 입력했었던 이유.

eth.unlockAccount('','')
personal.sendTransaction({from:coinbase,to:'0x...', value:091992929},'1234')

geth/keystore 디렉토리 안에는 개인키 정보가 담겨있는 파일이 있다.

개인키를 그대로 넣기에는 보안상 위험하니까 양방향 암호화를 한 상태로 파일로 저장되어있다.

양방향 암호화는 복호화가 가능하므로 암호를 넣으면 개인키를 추출할 수 있다.

그래서 비밀번호를 아는 사람만 사용가능하도록 unlock이 되어있었다.

 

 

 

3.3   GETH 실행

저번에 미리 만들어두었던 geth 접속 프로그램을 켜서 geth를 실행시킨다.

( 블로그 주소 )

$ source ~/.bash_profile
$ 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 7722 --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"

 

attach 실행

  $ source ~/.bash_profile
  $ geth attach http://127.0.0.1:9000

 

bin, abi 파일 저장

컴파일로 생긴 bin, abi 파일 내용을 각각 변수에 저장한다.

$ bytecode="0x[bin 코드 작성]" // 바이트코드
$ abi = [abi 코드 작성]        // 객체형태

 

 

 

3.4   트랜잭션 발동시키기

만들어준 내용으로 트랜젝션을 보내보자.

스마트 컨트랙트에서는 From, Data 정보만 있으면 배포가 가능하다고했었으니까 객체를 만들어서 보내주자.

$ txObject={ from : eth.coinbase, data : bytecode }
$ eth.sendTransaction(txObject)

트랜젝션 해시가 성공적으로 생겼고, 아직 채굴을 하지 않았으므로 txpool에 pending 상태로 담겨있다.

채굴을 해주면 txpool에 있던 내용이 담긴 블럭이 생성되면서 txpool이 비워진다.

 

eth.getTransaction('tx hash') //input이 생김
eth.getTransactionReceipt('tx hash') //contractAddress가 생김 = CA

 

 

 

 

4.   CA를 사용해 필요한 정보 가져오기

4.1  EOA와 CA의 차이

EOA

돈을 입금할때 사용했던 계정

 

CA

  • 스마트 컨트랙트가 생성될때 생기는 계정.
  • 컨트랙트가 보유한 고유한 키값이라고 생각하면 편하다.
  • 그래서 해당 트랜지션의 내용을 부르거나 수정할때 사용할 수 있다.
  • updata문이 없어서 코드를 수정하려면 다시 생성해야한다.
  • EOA와 달리 계정의 주소를 통제할 수 있는 개인키가 없어서 직접 트랜젝션을 발생시킬 수 없다.

 

 

객체를 받아올 형태(=abi)를 contract에 저장해서 보면 eth객체에 abi객체가 추가된 형태다.

$ contract = eth.contract(abi)

 

마지막에 보면 처음보는 속성인 at, getData, new가 추가되어있는 것을 볼 수 있다.

 

 

해당 contract address의 고유키값에 접근할때 at을 사용한다.

CA를 통해서 접근한 내용을 넣은 intance에는 솔리디티 파일로 작성했던 코드가 담겨있다.

그래서 만들어두었던 getText()메소드를 사용할 수 있다.

$ instance = contract.at('ca')
$ instance.getText({from:eth.coinbase})
$ instance.getText.call()

// 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;
  }
}

 

그럼 instance는 언제 생성되어 있던걸까.

bytecode가 이더리움 네트워크에 있는 CA가 만들어지기 직전,  evm이 실행되면서 instance가 생성되어서 tx에 들어간다.

tx는 인스턴스가 한번만 생성되는 싱글톤 객체라는걸 잊지말자. (중복객체 생성 못 함)

 

 

 

메서드 call() vs send()

  • call : 데이터를 가져오는 메서드, gas 비용 없음
  • send : 상태변수를 바꾸는 메서드, gas 비용 필요

블록체인에서는 단순하게 상태변수를 바꾸는거라고 생각하면 안된다.

블록체인에서 상태변수도 엄연히 그 안에서 부피를 차지하고있는 데이터다.

한 블록에서 데이터를 변경하게되면 연결된 모든 블록에서도 내용을 변경해야한다.

블록 하나가 갖고있는 공간이 한정적이기때문에 쉽게 수정하지 못하게 비용을 지불하게 만들었다.

비용을 계산하려면 반드시 EVM을 거쳐야하고 EVM은 tx로 계산하기때문에 매개변수를 변경하려면 반드시 tx를 사용해야한다.

솔리티디에서 유독 uint 종류가 많은 이유도 정확하 사용량을 계산해서 비용을 줄이기 위해서다.

 

그래서 스마트 컨트랙트에서 tx는 두가지 종류로 나뉜다.

1. 배포할때 최초로 tx에 데이터 넣을때

2. 스마트 컨트랙트에서 내용변경할때

 

 

 

 

 

5. 스마트 컨트랙트 흐름 한 눈에 보기

1. 솔리디티 코드 재작성
2. 컴파일 다시 작업
3. abi, bin 변수 재설정
4. txObject 만들기
5. contract 변수 다시 만들고
6. instance 변수 다시 만들기
7. miner.start() miner.stop
8. instance 변수 확인
9. instance.getText.call() // 변경전 텍스트
10. instance.setText('change up',{from:eth.coinbase})
11. txpool 확인
12. instance.getText.call() // 변경후 텍스트

 

댓글