본문 바로가기
블록체인/솔리디티

솔리디티 문법 실행

by 혀닙 2022. 7. 11.

목차

  1. 셋팅
  2. 솔리디티 코드 작성
  3. 컴파일
  4. abi 변수 및 bytecode 변수 선언
  5. Tx 객체 생성 및 네트워크로 보내기
  6. contract 변수 선언
  7. instance 변수 선언
  8. 솔리디티 코드 배포 확인

 

 

오늘은 솔리디티 문법의 실행을 해보자.

사실 문법을 먼저 숙지하고 나중에 실행을 하는 것이 좋은 방법이긴 하지만,

문법의 숙지가 생각보다 쉽지 않기 때문에 오류가 난 지도 모르고 배울 수 있다.

 

 

 

솔리디티 언어

실행이 타 언어에 비해서 쉽지 않음

 

<참고> 수업이 끝났을 때 다음과 같은 것들을 할 수 있어야 함
코드 작성 후 컴파일러를 통해 바이트 코드로 변경
이더리움 네트워크 안에 바이트 코드를 넣어서 tx 발생시키기
마이닝이 됬을 때 작성한 코드가 실행시키기
만약 tx가 실행되지 않으면 마이닝이 됬는 지 아닌 지 확인할 수 있어야 함

 

 

 

 

<참고> 솔리디티 언어 공부 사이트
https://cryptozombies.io/ko/
챕터 2정도까지하면 무난한다고 한다.(선생님 왈 2시간 이내에 쌉 가능)

 

 

 

1. 셋팅

1-1. 프로젝트 및 파일 생성

프로젝트 하나를 생성해서,

Contracts라는 디렉토리 내에 확장자명이 .sol인 파일을 생성해보자

 

 

1-2. 솔리디티 확장 프로그램 설치

그 다음에는 sol 파일의 실행을 위해서 비쥬얼 스튜디오의 market에서 솔리디티 확장프로그램을 설치하자.

 

 

 

 

 

<참고> 컴파일러도 버전 정보가 있다
컴파일러는 자바스크립트와 다르게 단순하게 코드를 01010101의 byte 코드로 만들어주는 아이이다.

이더리움의 EVM을 해석 가능하게 해주는 byte코드만 만들어주는 기계(컴파일러)도 버전이 있다!

 

 

2. Solidity 작성

// root/Contract/helloWorld.sol

// SPDX License Identifier: MIT
pragma solidity ^0.8.15;	//버전 정보

contract HelloWorld {
    string text;    //상태 변수 or 멤버 변수
    
    constructor(){
        text = "Hello World";
    }
    function getText() public view returns(string memory){	//파란색은 예약어
        return text;
    }
    function setText(string memory value) public {
        text = value;
    }
}

 

<참고>
솔리디티는 기본적으로 객체지향 언어이다.
따라서 하나의 contract는 하나의 객체라고 보면된다.

 

3. 컴파일

3-1. Solidity Code Compile 방법: 다양한 방법론 존재

  • brew(mac)
  • solc(windows..)
  • npm install solc(노드 js 환경에서 컴파일 할 수 있게 하는 라이브러리)

3-2. 컴파일러 설치

$ npm init -y
$ npm install solc
$ npx solc [디렉토리/파일명]



3-3. 컴파일러 설치의 목적

  1. bytecode(.bin 파일) 생성
  2. ABI 파일 생성
<참고>
ABI: Application Binary Interface
컨트랙트가 배포되면 contract 인스턴스가 생성된다. ABI는 이러한 인스턴스를 프론트딴으로 가져오기 위한 코드의 인자값으로 사용된다.

블록의 tx 안에 스마트 컨트랙트가 있다. 사람이 읽을 수 없는 바이트 코드 형태로
그 바이트 코드를 실행할 수 있는 명령어가 있는데 그 명령어를 사람이 읽을 수 있는 내용으로 만들어 준것

bin
16진수 형식의 컨트랙트 바이트 코드. 컨트랙트를 '배포'하기 위해서는 바이트코드가 필요하다


3-4. 컴파일러 실행

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


3-5. 컴파일러 실행의 결과

  • .sol 확장자와 .bin 확장자를 가진 파일 2개가 생성됨
  • 바이트 코드로 컴파일된 확장자명 .bin 파일이 바로 컴퓨터가 해석 가능한 파일이며,
  • 이미 올라간 컨트랙트를 호출하기 위해서 abi 파일을 사용함

 

<참고> 솔리디티 코드 배포란?
작성한 코드를 이더리움 클라이언트 네트워크 즉, geth에 올리는 것

 

 

4. abi 변수와, bytecode 변수 설정

3번의 컴파일 결과 인 ABI 파일과 bin 파일의 내용을 각각 변수에 담아보자

 

bytecode = "0x..."	//빈 파일에서 복사한 내용을 bytecode 변수에 string 값으로 0x 작성 후 붙여넣어주자
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 파일의 내용을 abi 변수에 담아주자

 

5. TX객체 생성 후 geth로 보내기

  • 일반적은 Tx객체와 달리 from과 to라는 두가지 속성을 넣어주면 스마트 컨트랙트를 넣을 수 있음
  • 일반적인 Tx에서는 to와 value가 필수적이지만 스마트 컨트랙트에서는 누가 어떤 코드를 배포하느냐가 중요하기 때문에 to와 value가 필수가 아님

 

 

tx 객체 생성 및 보내는 것은 우리가 잘 알고 있던 방법인 web3 또는 eht메서드를 통해서 진행하면된다.

 

geth 콘솔은 자바스크립트 엔진이 실행되기 때문에 변수 선언이 가능하다.

아래와 같이 콘솔에 tx객체 변수를 선언해서 Tx를 보내보자

//txObject라는 변수 선언해서 from과 data 정보 작성
txObject = {
from: eth.coinbase,
data: bytecode
}


//eth객체의 sendTransaction() 메서드로 txObject 보내기
eth.sendTransaction(txObject)


//반환값으로 나오는 TxHash 정보는 잘 가지고 있자
//0x17627d156d4e240f05112605bff1a656e79ca1183c8dd48106b285b609eef9ca

 

메서드를 통해 tx 객체를 보냈을 때 txHash 정보가 잘 나온다면

getTransaction()메서드 실행을 통해서 Tx 정보를 불러와서 확인해보자

 

주목할 점은 tx객체의 속성 중 input 속성에 내용이 생겼고, to 속성의 값이 null 값이라는 점이다.

만약, 어떤 tx 객체를 보았을 때 input 속성의 내용이 있는 tx라면

스마트 컨트랙트를 포함하는 객체라고 할 수 있다.

eth.getTransaction("0xfa7d0cf29cca1736bb175b61f5e368dcccd8aa4b8373be17d39236b90ea584a4")


//반환값
{
  blockHash: "0x8cd8b28868780b7240c46614f9214201b851a0c947fffad4b6de70b7efdbb250",
  blockNumber: 2392,
  from: "0xce40b436382a36c6edb42b1336a79a042c86967b",
  gas: 447229,
  gasPrice: 1000000000,
  hash: "0x17627d156d4e240f05112605bff1a656e79ca1183c8dd48106b285b609eef9ca",
  // 인풋 속성의 값 확인 가능
  input: "0x608060405...."	//일부 생략
  nonce: 37,
  r: "0xbd29350e94d0336325dcb23cd6004a710f9d14f28d1c248c6f777c304b34c337",
  s: "0x4f75001cc6a58f675c0954daed587032d4cefeb5c6371eec975cfce4bdfb1449",
  to: null,
  transactionIndex: 1,
  type: "0x0",
  v: "0x47ac",
  value: 0
}

 

 

6. contract 변수 생성 및 채굴

 

eth.contract()메서드를 통해 contract 생성 시, at, getData, new라는 메서드가 생긴 것을 확인할 수 있다.

contract = eth.contract(abi)

//반환값
{
//abi
  abi: [{
      inputs: [],
      stateMutability: "nonpayable",
      type: "constructor"
  }, {
      inputs: [],
      name: "getText",
      outputs: [{...}],
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}],
      name: "setText",
      outputs: [],
      stateMutability: "nonpayable",
      type: "function"
  }],
//eth
  eth: {
    accounts: ["0xce40b436382a36c6edb42b1336a79a042c86967b", "0x5a93f9ae09552b82e358f97f29fd4d6e53c43ff5"],
    blockNumber: 2393,
    coinbase: "0xce40b436382a36c6edb42b1336a79a042c86967b",
    compile: {
      lll: function(),
      serpent: function(),
      solidity: function()
    },
    defaultAccount: undefined,
    defaultBlock: "latest",
    gasPrice: 1000000000,
    hashrate: 0,
    maxPriorityFeePerGas: 1000000000,
    mining: false,
    pendingTransactions: [{
        blockHash: null,
        blockNumber: null,
        from: "0xce40b436382a36c6edb42b1336a79a042c86967b",
        gas: 26199,
        gasPrice: 1000000000,
        hash: "0xd6bcf6720c0605c287bc21ef438ea0f5f8bceff4983df1a3e64bb2be7b0dd724",
        input: "0x5d3a1f9d000000000000..."	//일부 생략
        nonce: 39,
        r: "0xb580abc06ea0e940988138e2572ef30336395c214bb6ba27834a2e1e8173a428",
        s: "0x4b102b3238a9eef4abda5d303fa806e1ff480186e1611b3b95d15432261d7dfc",
        to: "0x6e9d532cd7adaa9fd7825bd41d1b3040b15a5096",
        transactionIndex: null,
        type: "0x0",
        v: "0x47ab",
        value: 0
    }],
    protocolVersion: undefined,
    syncing: false,
    call: function(),
    chainId: function(),
    contract: function(abi),
    createAccessList: function(),
    estimateGas: function(),
    feeHistory: function(),
    fillTransaction: function(),
    filter: function(options, callback, filterCreationErrorCallback),
    getAccounts: function(callback),
    getBalance: function(),
    getBlock: function(),
	//...중략
  },
  at: function(address, callback),
  getData: function(),
  new: function()
}

 

 

자, 그럼 tx를 EVM에 보내기 위해서 채굴을 해보자

// 마이닝 시작
miner.start(1)

// 채굴이 되었다면
miner.stop()

 

채굴 완료 후 TxReceipt를 확인하는 메서드를 실행해보자

txReceipt 객체의 속성값 중 CA 속성의 값이 생긴 것을 확인할 수 있다.

 

eth.getTransactionReceipt('0x17627d156d4e240f05112605bff1a656e79ca1183c8dd48106b285b609eef9ca')
   //CA: 0x6e9d532cd7adaa9fd7825bd41d1b3040b15a5096

//반환값
{
  blockHash: "0x8cd8b28868780b7240c46614f9214201b851a0c947fffad4b6de70b7efdbb250",
  blockNumber: 2392,
  //CA 속성 값 확인 가능
  contractAddress: "0x6e9d532cd7adaa9fd7825bd41d1b3040b15a5096",
  cumulativeGasUsed: 894458,
  effectiveGasPrice: 1000000000,
  from: "0xce40b436382a36c6edb42b1336a79a042c86967b",
  gasUsed: 447229,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x1",
  //to 속성이 null 값
  to: null,
  transactionHash: "0x17627d156d4e240f05112605bff1a656e79ca1183c8dd48106b285b609eef9ca",
  transactionIndex: 1,
  type: "0x0"
}

 

 

 

이더리움 계정은 두가지가 있다

1. EOA - value를 송금하기 위한 계정
2. CA - 스마트 컨트랙트가 발생할 떄 생성되는 계정, 컨트랙트의 고유한 키값이라고 보면 됨

CA는 일종의 컨트랙트의 Primary key라고 보면 된다.
따라서 업데이트가 불가한 값이며, 혹시라도 코드를 수정해야 된다면 새로운 CA를 생성해야 한다.

 


7. 인스턴스 생성

contract 객체의 at 메서드의 매개변수로 CA 계정을 작성하여 해당 컨트랙트의 primary key값에 접근할 수 있는 Instance 변수를 생성하였다.

instance = contract.at('CA계정')
CA = '0x6e9d532cd7adaa9fd7825bd41d1b3040b15a5096'
instance = contract.at('0x6e9d532cd7adaa9fd7825bd41d1b3040b15a5096')

{
//abi
  abi: [{
      inputs: [],
      stateMutability: "nonpayable",
      type: "constructor"
  }, {
      inputs: [],
      name: "getText",
      outputs: [{...}],
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}],
      name: "setText",
      outputs: [],
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: "0x6e9d532cd7adaa9fd7825bd41d1b3040b15a5096",
  transactionHash: null,
  allEvents: function bound(),
  getText: function bound(),	//솔리디티 언어로 작성한 메서드
  setText: function bound()		//솔리디티 언어로 작성한 메서드
}

 

instance.getText({from:eth.coinbase})
//"0x7c48412fc1d08f52a4c139ec4691f1c25b835da45b8198104f4c46936f7fe686"

 

8. 확인

메서드 호출을 통해 코드 배포를 확인해보자

 

 

8-1. getText 함수 확인

instance.getText.call()
//"Hello World"

 

8-2. setText 메서드 확인

instance.setText('hello ingoo',{from: eth.coinbase}) //여기가 중요

 

8-3. transaction 배포

instance = contract.new(txObject) //transaction 배포



9. txpool 확인
10. miner.start(1), miner.stop()
11. instance.getText.call() 확인

instance.getText.call()
//"hello ingoo"

 

 

지금까지 진행한 솔리디티 코드 실행을 쉽게 도와주는 프레임 워크/프로그램 들이 있다.

Truffle, HardHat , remix IDE...

다음 시간에는 이러한 프레임 워크를 사용해서 코드 실행을 할 수 있는 방법도 알아보자.

 

 

<참고>
- 트랜잭션에 코드를 보낼 수 있다! 는 점이 이더리움과 비트코인의 가장 큰 차이이다.
- 코드 작성 시, 최소한의 용량을 사용하게끔 하는 것이 중요하다. 용량이 높아지면 가스비도 높아진다...
- 컨트랙트 정보를 불러오는 메서드는 코드 실행 시 수수료가 발생하지 않지만 컨트랙트 정보를 변경시키는 메서드는 코드 실행 시 수수료가 발생한다.
- 즉, 스마트 컨트랙트의 내용을 변경 시에는 수수료가 발생한다.

'블록체인 > 솔리디티' 카테고리의 다른 글

ERC20토큰  (0) 2022.07.21
스마트컨트랙트에 결제 기능 넣기  (0) 2022.07.20
address 타입의 분류: address / address payable  (0) 2022.07.20

댓글