ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SmartContract Transaction에 대하여
    BlockChain Tech 2020. 6. 7. 00:47

    STAY....!!!! STAY!!!!

     GroundX Klip에서 가입 이벤트로 50Klay를 지급하였다. 하지만, '50 Klay'의 출처에 대한 이야기가 올라오기 시작 했고, '아이스크림 내기'를 만들며 살펴보았던 Contract에 대하여 설명하고 싶어 글을 적었다. 하지만, 글을 작성하기 위해 검증을 하다보니 다시금 의문에 빠져버렸다. 글에서 Internal Transaction과 nonce에 대하여 언급했는데 기존에 내가 가지고 있던 개념이 틀렸다는 것을 깨닫고, 다시 그것을 공부하다 나름대로? 많은 것을 깨닫고 재미있었기에 글로 정리해보려고 한다.

     

    시작하기전에

     Klip에서 지급하는 50Klay 출처를 찾기 위해, 꽤나 많은 시도를 했다. 처음에는 내가 만든 Contract와 비슷한 기능(토큰 송금 그 외 기록)을 하고 있다고 믿었기 때문에 '현재 Klaytn Scope에서 Internal Transaction을 볼 수 없어요!'를 사람들에게 말해주고 싶었다. 하지만, 검증을 하면 할 수록 내가 기존에 가지고 있던 잘못 된 지식과 충돌하게 되었고, 어떤 복잡한 문제가 있더라도, 초기 이벤트 물량이 이동한 Transaction은 존재할 것이라 믿고, 그것을 찾아 해맸다.

     

    결론적으로 현재 정리 된 것은 다음과 같다.

     

    [검증 완료]

    (1) Klip Contract에 Klaytn이 예치 되었었다.

    이벤트 중간에 잔액이 있던 모습 (현재는 0)

     

    (2) Klip Contract에서 유저에게 Internal Transaction으로 유저에게 송금한다.

    - 파악하기로는 하나 이상의 컨트랙트가 연결 되어있다. (0xb26e09db6656b998d2913f13870e06c151c37900)

    - Input Data로는 아래와 같은 데이터를 전송한다.

    0x000000000000000000000000a04db5b3746dc8002d6a10ed540a99e5fdcf818a 유저 주소
    0000000000000000000000000000000000000000000000000000000000007c09   31753 (웰컴 카드 index)
    00000000000000000000000000000000000000000000000000000000000000a0   160
    000000000000000000000000000000000000000000000002b5e3af16b1880000   50000000000000000000 (50 Klay)
    0000000000000000000000000000000000000000000000000000000000007b39   31545 (Contract Nonce)
    0000000000000000000000000000000000000000000000000000000000000016   22
    636172645f77656c636f6d655f6b6c69702e6a736f6e00000000000000000000   card_welcome_klip.json (string)

    0xa2138c038bcf725f3f8ed95c809014c38af5d25f (Klip 가입시 발생 되는 첫 Contract)

     

    (3) Contract에서 유저들에게 전송 되는 Internal Transaction은 아직 Scope에서 기능 제공을 하지 않기 때문에 볼 수 없다.

    - 아래의 사진은 Test로 Contract -> address 로 0.000001 Klay를 지급한 것이다.

    - Transaction이 없음에도 잔액이 존재하는 것이 이러한 이유다. 또, 이 문제로 내가 여기까지 오게 되었다..ㅎㅎ

     

     

    [검증 미완료]

    (1) 이벤트 Contract에 예치한 물량의 출처

    - 사실 이 문제를 제외하고, 다른 부분은 '감'으로 느끼고 있었다. Contract에서 유저에게 Internal Transaction으로 Klay를 지급하고 있었고, 유저 지갑에서 SmartContract 호출이 아닌 Klip 계정에서 유저 지갑 주소를 인자값으로 SmartContract를 호출 하는 등. 간단하게 Scope와 caver를 통하여 찾아볼 수 있었다. 그 외, 이해하지 못하는 방식은 사실 명확한 코드를 보지 않는 이상 '이렇게 까지 해야되나?'를 논하기에는 이르다고 판단해서 깊게 생각하고 싶진 않았다.

     

    - 하지만, Internal Transaction이 조회가 불가능 하더라도 GroundX -> Klip SmartContract 에 예치한 내역을 보고 싶었지만 결국 포기했다. 내가 이것을 조회할 수 없었던 이유를 글로 적어볼 예정이다.

     

    마지막에 하다하다 안되서 Contract 생성 이후 Block에 있는 value 0이 아닌 Transaction을 다 기록하다 정신 차리고 멈췄다.

     

    아무쪼록..

     2018년 블록체인을 공부하면서 '하.. 틀려도 일단 내 생각을 올리고 조언을 구하자.' 라는 생각이 짙어졌는데. 이번에도 틀려서 창피했지만, 많은 분들이 가이드를 해주셔서 난 또, 성장함을 느꼈다.

     

     

    #1 Transaction Input Data

     

    Transaction Data 살펴보기 (feat. ABI)

     Transaction을 구성하는 여러가지 요소들이 있다. 대부분 쉽게 이해할 수 있는 반면, Data라는 친구는 명확하게 어떤 것을 해주는 항목인지 알기 힘들다. 오늘은 Transaction의 Data가 어떤 역할을 하는�

    ryublock.tistory.com

    예전에 이와 관련 된 글을 적은 적 있다. 하지만 오래 되기도 하고, 다시 한번 살펴보자!

     

    Klip 가입 당시 발생한 Transaction

    저 찬란한 16진수가 무엇을 의미할까?

     

    Transaction 구성요소를 살펴보면 Input Data는 `가변길이의 바이너리 데이터`를 의미한다.

    (1) 일반 적인 Transfer에서는 메모장이 될 수 있다.

    (2) Contract를 호출할 때에는 명령을 의미한다. (어떤 함수에 어떤 인자를 넣어줘!)

     

    우리가 살펴보아야할 것은 (2)의 경우이다. 저 데이터에서 어디까지가 함수를 말하는지, 어디까지가 인자값을 의미할까?

     

    0xcd7e53cc000000000000000000000000df8bf23fd5ae02d9577ced552426e3d24b0f0f5e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016636172645f77656c636f6d655f6b6c69702e6a736f6e00000000000000000000

     

    0xcd7e53cc [0x 제외 8자리]

    - 호출할 함수를 의미한다.

    - Klaytn은 따로 찾아보지 않았지만, 이더리움에서는 함수의 인터페이스를 아래와 같이 정의하고 이것이 Method ID가 된다.

    - 즉 0xcd7e53cc 는 호출할 Method ID를 의미할 것이다.

     

    bytes4(keccak256('transferFrom(address,address,uint256)'))
    => 0xfce353f6

     

    000000000000000000000000df8bf23fd5ae02d9577ced552426e3d24b0f0f5e [64자리]

    - Method ID 다음 부터는 64자리씩 끊어서 차례대로 arg1(argument1), arg2, ~~~ 인자 값을 의미한다.

    - 이것이 어떤 것을 의미하는 지는 Contract ByteCode 가 아닌, ABI가 필요하다.

     

    여기서 잠깐 ABI? ByteCode?

    블록체인은 무엇이든 결국 블록위에 기록이 되고, 그것을 누구나 조회할 수 있다. Contract Code를 조회할 수 있음을 의미한다. 그렇게 caver나, ethereum의 web3로 .getCode(Contract Address)를 때리면 byte code를 회득할 수 있다.

    우웍.. 우웁...

    그런데. 사실 이런 바이트 코드를 디컴파일 시켜도, 큰 흐름은 이해할 수 있지만 어떤 데이터가 들어가고 어떻게 처리되는 지 정확한 구도를 파악하기는 힘들다. 그렇기 때문에 현재 이더리움 etherscan에서는 Source Code를 올리기 권장하고, 이를 통하여 ABI도 회득할 수 있다. 물론, 이런 것들은 블록체인에 기록 되는 것이 아닌, etherscan이 제공하는 하나의 서비스일 뿐이다.

     

    그렇게 contract byte code (블록체인에 존재) === 소스코드 -> 컴파일 의 결과를 비교하여 코드를 검증하고, 다른 블록체인 참여자들이 보다 쉽게 해석할 수 있게 한다.

     

    아무튼, 이런 ABI가 공개 된다면, 위에 난해한 16진수를 보다 더 쉽게 해석할 수 있을 것이다.

    하지만, ABI가 없는 상태에서는 HEX To String / HEX To Decimal 등으로 눈치 껏 타입을 추측해서 해독할 수 있다. 그렇게 Transaction의 Input Data 만으로 어떤 행동이 발생되는지 우리는 알아낼 수 있다.

     

    (1) 이 Method ID를 실행 시켜줘!!

    0xcd7e53cc

     

    (2) [arg1] address

    000000000000000000000000df8bf23fd5ae02d9577ced552426e3d24b0f0f5e

    > 0xdf8bf23fd5ae02d9577ced552426e3d24b0f0f5e

     

    (3) [arg2] unknown type

    0000000000000000000000000000000000000000000000000000000000000040

    > 64

     

    (4) [arg3] unknown type

    0000000000000000000000000000000000000000000000000000000000000016

    > 22

     

    (5) [arg4] string

    636172645f77656c636f6d655f6b6c69702e6a736f6e00000000000000000000

    > card_welcome_klip.json

     

    0xcd7e53cc(0xdf8bf23fd5ae02d9577ced552426e3d24b0f0f5e, 64, 22, "card_welcome_klip.json")

     

    우린 이렇게 Transaction Input Data를 하나하나 살펴볼 수 있다!

     

    * 테스트를 해보다 찾은 것은 `Contract 호출 또는 payable 함수(value transfer할 때 자동 호출) 호출`에서는 Method ID가 붙지 않았다. 그렇기 때문에 우리는 Method ID 부분이 없을 때 이런 상황을 의심해볼 수도 있다.

     

     

    #2 Internal Transaction

    약 1년 하고도 더 먼 훗날. Transaction에는 두 가지의 종류가 있다고 공부했다.

    Address는 두 종류가 존재한다.
    유저 지갑 - 외부 소유 계정 (External Owned Account)
    컨트랙트 주소- 계약 계정 (Contract Account)

     

    (1) `유저 지갑 -> 유저 지갑 | 컨트랙트 주소` 에서 일어나는 것은 Transaction

    - 유저가 발생시키는 것은 Transaction

     

    (2) `컨트랙트 주소 -> 유저 지갑 | 컨트랙트 주소` 에서 일어나는 것은 Internal Transaction

    - Contract가 발생시키는 것은 Internal Transaction

     

    TIP. 참고로 컨트랙트는 Private Key가 없다. 즉, 서명을 할 수 없으니. Transaction을 만들 수 있나 의심해볼 필요가 있다.

     

    내가 Klip Contract에서 찾고 싶었던 것은 `Klip Contract -> User 50Klay`였다. 이는 위 (2)번 Internal Transaction에 해당 된다. 하지만, 해당 Transaction ID는 caver.js를 사용하여 아무리 눈을 씻고 찾아봐도 나오지 않았다.

    으악.. 내 눈... 이 영수증은 유저가 회원 가입을 하고, 50Klay를 받는 Transaction의 것이다.

    - 위 Transaction의 logs를 살펴 보자. 이것이 Internal Transaction을 의미한다고 생각하면 되는데. Transaction Hash 값이 모두 같다.

     

    여기까지 찾다보니 기존 이더리움에서는 어떻게 이루어지고, 어떻게 기록 되는지 살펴보고 싶어졌다.

    나의 443일 전 기록..

    - 해당 트랙잭션은 고양이를 거래소에서 구매 신청을 하는 Transaction이다.

    - `류기혁 지갑 -> Contract 호출` 이기 때문에 이것은 Transaction이다.

    - 하지만, 내부 로직을 타면서, (1)판매자에게 송금(2)크립토키티 팀 수수료 송금이 이루어진다.

     

    (1)판매자에게 송금, (2)크립토키티 팀 수수료 송금는 `Contract -> `에서 발생 되기 때문에 Internal Transaction이다.

    하지만 두 개의  Internal Transaction의 Transaction ID는 고양이를 거래소에서 구매 신청을 하는 Transaction의 ID와 같다.

     

    즉, Internal Transaction은 고유의 Transaction ID를 갖지 않는다.

    펀하고, 쿨하고, 섹시한 이유는 딱 말할 수 없지만.. 위의 TIP에서 언급한 Contract는 Private Key가 없어 서명할 수 없다와 관련있다고 생각한다.

     

    #3 Account Nonce

    블록체인에서 nonce라고 하면, 채굴을 하기 위한 정답이라고 생각할 수 있지만 블록 nonce 외에 Account 마다 nonce가 존재한다. `이중지불`을 방지 할 수 있고 서비스 개발자 입장에서는 Transaction 호출의 순번을 정해준다? 정도로 생각해볼 수 있다.

     

    [문제]

    - 유저1이 버튼을 클릭할 때, 회사 Account에서 Transaction을 발생 시킨다.

    - 동시에 유저2가 버튼을 눌렀다.

     

    nonce가 같다면 한 개의 Transaction은 누락 될 것이다.

     

    [해결]

    - 현재 회사 Account Nonce를 받아온다. (3이라고 하자)

    - 유저1 버튼 클릭시 nonce 4로 transaction을 생성하고 보낸다.

    - 유저2 버튼 클릭시 nonce 5로 transaction을 생성하고 보낸다. 

     

    이 외에 아직 내가 모르는 여러 문제를 해결하기 위해 존재할 것이다.

     

    돈을 보내는데.. Nonce 0? 돈을 받은 Transaction은?

    위 상황은 `클립 가입 후 10KLAY를 내 개발자 계좌로 보내는 모습이다`
    nonce 0 이라는 소리는 해당 계좌에서 일어난 첫 번째 Transaction이라는 것을 의미한다.
    하지만, 이미 돈이 있었고 첫 번째 Transaction이 돈을 보내는 것이라니..

     

    여기서 우리가 알 수 있는 점은 `송신은 nonce가 증가 되지만, 수신은 nonce가 증가 되지 않는다.`는 것이다.

    제발 그만해..

    이 문제도 간단하게 생각 해보면 이해가된다.

     

    EX. A가 B에게 송금했다.

    TXID : 0x~~~~
    To : B
    From : A
    Value : 20KLAY

    위 예제에서 A의 계좌를 조회해도 또, B의 계좌를 조회해도 같은 Transaction ID 가 적혀있고, 결국 그 데이터는 하나일 것이다.

    또, 해당 트랜잭션은 A가 발생 시켰기 때문에 A의 서명이 들어갔고, A의 계좌의 nonce가 증가 되었을 것이다.

     

     

    #4 결론

     EtherScan 외 익스플로어 사이트들을 사용하면서 블록체인을 너무 쉽게 생각했었던 것 같다. 막연하게 "블록에 저장 되고, 누구나 볼수 있습니다!"라고 말하고, 나도 언제든지 마음만 먹으면 조회를 할 수 있을 것이라 믿었다. 하지만 막상 조회를 해보니, 약 2년 전 블록체인 따라 만들기를 해보며 getBalance, getTransaction을 구현 하기 위해 0번째 블록 부터 for문을 돌린 기억이 났다.

    Internal Transaction 조회도 만들 수 있고, User 계좌를 조회 할 때 관련 된 모든 TXID를 보여주는 기능 또한 물론 만들 수 있다. 하지만, 이를 만들기 위해서는 많은 데이터들을 조회 해야할 것이고, 또 연관 된 Account들과 함께 저장 해야할 것 이다. 아마, 현재는 이 부분을 node들이 대신 해주고 있을 것이라 조심스레 추측해본다.

     

    뭐.. 이런 것들을 통하여 파생 되는 수 많은 개념들이 있었다. 하지만, 이번 경험에서 얻어가는 것은 이정도 까지가 좋은 것 같다. 또, 많은 것들을 적다보니 너무 길어졌고, 아무도 읽지 않을 것 같지만.. 글을 적으며 정리가 되어 만족감이 생겼다.

     

    힘내자..

    댓글

Developer RyuK