GetStorageAt vs Contract call (Query)

hop6·2022년 12월 13일
0
  • 직접 데이터가 저장된 slot의 데이터를 쿼리하는 StorageAt
  • Contract를 통한 데이터 쿼리

뭐가 더 빠를까?

jsonrpc call
[Contract call] 1000회 요청, 소요: 250828 ms
[StorageAt]     1000회 요청, 소요: 195994 ms
--> StorageAt이 27.9773 % 더 빠름

websocket call
[Contract call] 1000회 요청, 소요: 85121 ms
[StorageAt]     1000회 요청, 소요: 81735 ms
--> StorageAt이 4.1426 % 더 빠름

사실 jsonrpc는 호출 자체의 성능을 보는데 적합하지 않다. jsonrpc의 경우 실제 작업 수행 시간 외에 커넥션에 대한 작업 시간이 존재하기 때문에 노드의 상황에 따라 소요 시간에 차이가 있다. 따라서 websocket의 성능을 기준으로 판단한다.

4.1426% 차이로 StorageAt이 더 빠르지만 기대한 것 보다 효과가 적다.

성능의 차이는 EVM 실행 여부에서 온다.

실제 코드를 보면,

GetStorageAt 에서는 StateAndHeaderByNumberOrHash을 호출하여 statedb를 가져온 뒤, 키로 원하는 값을 바로 가져온다.

Contract call 같은 경우는, 동일하게 StateAndHeaderByNumberOrHash을 호출하지만 EVM을 생성하고 EVM을 실행시키는 과정도 존재한다.

때문에 GetStorageAt이 빠른 것은 당연한 결과다. 그러나 GetStorageAt이 사용되는 경우는 어떤 연산도 없이 값만 가져오는 경우일텐데, 이 경우에는 Contract call도 실행해야 할 opcode의 수가 적어 큰 차이가 없다.

GetStorageAt을 성능을 위하여 사용하는 것은 contract의 slot 번호를 계산하여 keccak을 연산하는 과정을 모두 생각해보면 그다지 효율이 좋지 않다.

GetStorageAt의 사용처는 링크와 같이 따로 contract에 쿼리 메서드를 구현하지 않고 고정된 slot 으로 가져올 수 있도록 주석을 다는 경우를 볼 수 있다. 해당 링크에서는 getter 함수를 admin 권한으로 만들고 클라이언트는 GetStorageAt을 이용하라고 안내한다. 아마 다른 contract에서 이를 호출하여 어딘가에 사용하는 것을 막으려는 의도로 보인다. 이렇게 구현하면 클라이언트는 contract 단에서 해당 값을 활용할 수 없고 rpc call로 값을 얻어와 사용해야 한다.

또한 여러 contract를 배포하여 운영을 하는 경우, 각 contract의 변수값을 구해야 하는 경우가 생기게 되고 ABI, ethers.Contract 오브젝트를 선언하여 관리하는 것은 의외로 번거롭다.

이러한 기능(여러 contract의 변수값을 조회)을 갖는 백오피스 서버나 스크립트 등을 작성해야 한다면 GetStorageAt을 이용하여 ABI 없이 provider 오브젝트 하나로 여러 컨트랙트에 대해 쿼리를 할 수 있다.

0개의 댓글