체인의정석

Solidity 0.8.0 버전에서 HashStruct안에 UUID 넣는 법 본문

블록체인/Solidity

Solidity 0.8.0 버전에서 HashStruct안에 UUID 넣는 법

체인의정석 2022. 7. 21. 16:57
728x90
반응형

 일단 해당 게시글은 hashStruct안에 UUID를 넣고 싶은 상황에서 오류가 나서 해결하기 위해 고민한 결과를 담고 있다.

 

먼저 테스트를 위해서 UUID를 만들어야 했다.

그 부분은

https://it-timehacker.tistory.com/317?category=1006911 

 

typescript로 UUID 만들기

오더북에 들어갈 각 정보를 임의로 넣기 위해서 UUID를 자동으로 생성해주는 모듈을 찾아서 써보기로 하였다. https://www.uuidgenerator.net/dev-corner/typescript Generate a UUID in TypeScript Generate a UU..

it-timehacker.tistory.com

여기를 보면 알 수 있다.

 

그 다음 차례는 string 자료형을 추가하는 것이였는데 에러가 났다.

원인을 찾을 수 가 없어 UUID가 아닌 자료 형을 넣어보기도 하고 uint256형을 추가하기도 했는데 string 형태가 나오면 오류가 나는 것을 확인할 수 있었다.

 

결국 다시 원문으로 돌아와서 고민을 하였다.

 

https://issuecloser.com/blog/ethersjs-signing-eip712-typed-structs

 

ethers - EthersJS - Signing EIP712 Typed Structs

Heya! In this post we're going to go a quick look into using EthersJS API for the EIP712 standard. Also, before we dive in, I would like to point out that if your use case is simple as a single message, you likely do not need to complicate it with EIP712.

issuecloser.com

이런식으로 구조체를 만들고 안에다가 문자열이 있으면 잘 되었는데 자세히 보면 해당 구조체는 해시스트럭트를 만들때 구조체 자체를 해시한것을 볼 수 있었다. 

 

그리고 결정적인 단서는 EIP712 문서를 보고 알았다.

https://eips.ethereum.org/EIPS/eip-712

 

EIP-712: Ethereum typed structured data hashing and signing

 

eips.ethereum.org

보면 분명 string 형으로 된 name같은 자료형이 지원되는것을 볼 수 있었는데

여기에 나온 해시스트럭트 예시가 힌트가 되었다.

function hashStruct(Mail memory mail) pure returns (bytes32 hash) {
    return keccak256(abi.encode(
        MAIL_TYPEHASH,
        mail.from,
        mail.to,
        keccak256(mail.contents)
    ));
}

여기서 mail 의 contents는 string 자료형이다. 결국 hashStruct를 만드는 규칙에서 uint256이나 address는 그냥 넣으면 되지만 string의 경우 keccack256을 한번 해주어서 bytes32로 바꾸어 주어야 한다는 것을 알 수 있었다.

 

struct도 마찬가지로 keccack을 해주어야 한다.

 

하지만 또 이대로 하면 에러가 발생한다.

 

TypeError: Invalid type for argument in function call. Invalid implicit conversion from string memory to bytes memory requested. This function requires a single bytes argument. Use abi.encodePacked(...) to obtain the pre-0.5.0 behaviour or abi.encode(...) to use ABI encoding.

 

이러한 에러가 발생하는 이유는 EIP712 공식문서가 오래되었고 문법이 바뀌었기 때문인데 경고문에 뜬것과 같이 abi.encodePacked를 먼저 한 후에 keccack256을 하면 문자형을 해시스트럭트에 넣을 수 있다.

  function hashStruct(StructA memory structA)
      public
      view
      returns (bytes32)
  {
      return
        keccak256(
          abi.encode(
          TYPEHASH,
          .
          .
          .
          ,
          keccak256(abi.encodePacked(UUID))
         )
        );
  }

그리고 테스트를 돌려본 결과 잘 통과하였다.

 

UUID를 넣어서 해시 스트렉트에서 관리하니 데이터베이스와 연결하기는 좋아진거 같다.

다만, 내가 사용하는 체인은 이더리움이 아닌 evm 계열 체인이기 때문에 이런식으로 가스비 절감보다는 오프체인과의 편한 연동을 위주로 코딩을 하느라 오프체인을 사용하는 고객사 입장에서 최대한 편리하게 맞추고 있지만

 

이게 이더리움의 경우라면 UUID같은걸 넣고 다시 해시하는 과정이 연산량이 들어가기 때문에 bytes32로 넣지 않았을까 싶다. 오픈씨도 보면 구조체 자체가 엄청 거대하고 이를 최적화 하고 너무 거대한 로딩을 피하기 위하여 바이트코드 레벨까지 들어가서 구조체의 부분부분을 끊어서 검증하는 로직으로 사용하고 있는데, 최적화를 더 하다보면 이런식으로 UUID를 직접 넣지 않을지 모르지만 일단 넣는 방법은 구현할 수 있었다.

 

교훈 : 정말 막힐때는 공식문서로 되돌아가자. 공식문서의 예시나 애초에 내가 하려는 시도가 지원이 되는 케이스라면 무엇이 잘못된건지 차근차근히 짚어야 한다. 특히 EIP가 적용된 부분은 EIP문서를 계속해서 들여다보면 답이 나오는 경우가 있는거 같다.

728x90
반응형
Comments