How to SCORE #2

DB Abstraction(VarDB, ArrayDB, DictDB)

Joonyoung Choi
B!ock.Chain
18 min readApr 23, 2019

--

이번 시리즈를 이해하기 위해서는 Python 언어 및 ICON 이 제공하는 CLI 개발도구인 T-Bears 및 ICON SDK 활용법에 대한 약간의 사전지식이 필요합니다.

첫번째 파트에서는 SCORE 프로젝트 생성부터 멤버 변수 선언 및 초기화까지 살펴보았습니다. 혹시 아직 못보신 분이 있으시면 파트 1을 먼저 보시는 것을 권장합니다.

시리즈의 두번째 파트에서는 SCORE에서 데이터에 접근하기 위해 state DB 를 wrapping 하여 제공하는 DB Abstraction(VarDB, ArrayDB, DictDB)에 대해 살펴보겠습니다.

Table of Contents

DB Abstraction

  • LevelDB
  • Supported Data Types

VarDB

  • Create VarDB Instance
  • Methods

ArrayDB

  • Create ArrayDB Instance
  • ArrayDB vs list
  • Methods

DictDB

  • Create DictDB Instance
  • DictDB vs dict
  • Method

Hand-on Exercise

  • __init__
  • on_install
  • hello

DB Abstraction

LevelDB

ICON은 상태를 저장하기 위해 key-value방식의 NoSQL 데이터베이스인 LevelDB 를 사용하고 있습니다. 이러한 LevelDB 의 한가지 특징은 key-valuebyte array를 사용한다는 점입니다.

LevelDB에 대한 보다 자세한 내용은 구글에서 제공하는 문서를 통해 확인하실 수 있습니다.

만약 사용자가 LevelDB를 직접 사용할 경우 keyvalue를 모두 byte array로 입력 및 조회해야 되므로, 사용자들이 읽을 수 있는 문자 그대로 사용하기에는 다소 불편한 부분이 있습니다.

ICON은 데이터를 byte array로 변환하는 다소 불편한 과정을 Plyvel을 사용하여 구현한 VarDB, ArrayDB, DictDB 클래스와 같은 DB Abstraction 클래스들을 제공하는 것으로 내부적으로 해당 과정을 대신 수행합니다. 따라서 사용자들은 DB Abstraction 클래스들을 통해 데이터들을 byte array로 전환하지 않고 LevelDB를 활용할 수 있습니다.

Supported Data Types

ICON의 DB Abstraction 클래스들은 bytes, int, str, bool과 같은 Python의 자료형과, Address와 같은 ICON에서 제공하는 클래스를 지원합니다.

bool 타입의 경우 True -> 0x1, False -> 0x0 으로 변환되어 저장됩니다.

value_typeAddress, bytes, int, str, bool을 모두 지원하며, keybool을 제외한 Address, bytes, int, str을 지원합니다.

key 로 사용 가능한 types : int, str ,Address, bytes
value 로 사용 가능한 types : int, str, Address, bool, bytes

DB로 부터 데이터를 조회할 때 key에 해당하는 데이터가 없을 경우 설정되어 있는 value_type에 따라 반환되는 값이 달라집니다.

value_typeint 인 경우에는 0, str 인 경우에는 “”, bool인 경우에는 False, Address 또는 bytes 인 경우에는 None을 반환합니다.

Address클래스에 대해서는 추후 이어지는 시리즈에서 활용법 등과 함께 보다 자세히 살펴볼 예정입니다.

VarDB

key를 통해 데이터를 저장하고, value_type에 맞게 변환하여 반환되는 데이터를 조회할 수 있습니다.

Create VarDB Instance

var_key : VarDBkeyAddress, int, str, bytes 중 하나의 타입을 사용합니다. VarDB 인스턴스를 생성할때 var_key 값을 바탕으로 LevelDB와 연결되므로, var_key가 같은 경우 value_type이 다르더라도 동일한 데이터 소스를 사용하게 됩니다.

value_type : key에 해당하는 VarDBvalue_type으로 Address, int, str, bytes, bool 중 하나의 타입을 사용합니다.

Methods

  • get : var_key 를 바탕으로 정해진 데이터소스를 바라보는 VarDB 인스턴스를 생성하여 byte array로 저장된 데이터를 조회하고 value_type에 맞게 변환하여 결과를 반환합니다.

VarDB가 바라보는 데이터소스의 값이 b“Hello”와 같이 byte array로 설정되어 있다고 가정한다면 출력되는 결과는 다음과 같을 것입니다.

LevelDB에 최종적으로 저장된 데이터는 byte array형태로, DB Abstraction에서 데이터를 조회할 때 value_type에 따라 데이터를 변형하여 반환합니다.

byte array 로 부터 value_type에 맞는 데이터로 type 변환
  • set : var_key를 바탕으로 정해진 데이터소스를 바라보는 VarDB 인스턴스를 생성하고, 입력받은 데이터를 byte array로 변환하여 입력 및 수정합니다.
  • remove : var_key를 바탕으로 정해진 데이터소스를 바라보는 VarDB 인스턴스를 생성하고, 기존에 저장되어 있는 데이터를 삭제합니다.

ArrayDB

value-type을 통해 반환되는 데이터의 타입을 지정하며, Pythonlist 자료형과 유사하게 사용할 수 있습니다.

Create ArrayDB Instance

var_key : ArrayDBkeyAddress, int, str, bytes 중 하나의 타입을 사용합니다. ArrayDB 인스턴스를 생성할때 var_key 값을 바탕으로 LevelDB와 연결되므로, var_key가 같은 경우 value_type이 다르더라도 동일한 데이터 소스를 사용하게 됩니다.

value_type : key에 해당하는 ArrayDBvalue_type으로 Address, int, str, bytes, bool 중 하나의 타입을 사용합니다.

ArrayDB vs list

  • iterable : ArrayDB 는 순서를 가지며, iterable한 클래스로 Pythonlist와 같이 iterating을 통해 element를 모두 조회할 수 있습니다.
  • length : len 메소드를 통해하여 Pythonlist와 같이 ArrayDB에 들어있는 element의 수를 확인할 수 있습니다.
  • insert : Pythonlist와 같이 특정 indexelement를 끼워넣는 insertArrayDB에서는 지원하지 않습니다.
  • pop : ArrayDBpop은 마지막으로 입력된 element를 뽑아내어 반환합니다. Pythonlist와 같이 특정 indexelement를 뽑아내는 popArrayDB에서는 지원하지 않습니다.

제한되는 기능들을 살펴보니 Pythonlist 보다는 stack과 유사한 기능을 제공하는 것 같습니다.

Methods

  • get : ArrayDB로 부터 특정 index의 데이터를 조회하고 value_type에 맞게 변환하여 결과를 반환합니다. index-1을 입력하는 경우 마지막 element를 조회합니다.
  • pop : ArrayDB로 부터 마지막으로 입력된 데이터를 조회하고 value_type에 맞게 변환하여 결과를 반환하는 것과 동시에 제거합니다. Python list의 특정 index를 입력하지 않은 pop과 같은 기능을 수행합니다.
  • put : ArrayDB에 데이터를 추가합니다. Python listappend와 같은 기능을 수행합니다.

DictDB

value-type을 통해 반환되는 데이터의 타입을 지정하며, Pythondict 자료형과 유사하게 사용할 수 있습니다.

Create DictDB Instance

var_key : DictDBkeyAddress, int, str, bytes 중 하나의 타입을 사용합니다. DictDB 인스턴스를 생성할때 var_key 값을 바탕으로 LevelDB와 연결되므로, var_key가 같은 경우 value_type이 다르더라도 동일한 데이터 소스를 사용하게 됩니다.

value_type : key에 해당하는 DictDBvalue_type으로 Address, int, str, bytes, bool 중 하나의 타입을 사용합니다.

depth : DictDB에 저장된 데이터를 조회할 때 사용할 key들의 수 입니다. DictDB의 경우 DictDB[key]와 같은 방식으로 key에 해당하는 데이터를 조회할 수 있습니다. 만약 depth의 값이 2 이상인 경우 DictDB[key]depth1만큼 차감된 새로운 DictDB를 반환합니다.

DictDB vs dict

  • Nested Dictionary : ICON의 DictDB는 입력 가능한 value_type이 정해져 있어 depth를 통해 PythonNested Dictionary와 유사한 기능을 제공합니다.
DictDB 클래스의 __setitem__ 메소드

depth1이 아닌 경우 keyvalue를 설정할 수 없습니다.

  • keys : Pythondict와 같이 value가 할당되어 있는 key들을 한번에 조회하는 keysDictDB에서는 지원하지 않습니다.

Method

  • remove : depth1DictDB로 부터 해당 key의 데이터를 제거합니다.

Hands-on Exercise

지난 파트 1에서 DB Abstraction에 대한 이해 과정을 생략하고 샘플을 따라 일단 VarDB를 사용해 보았습니다. 이번에는 파트 1 에서 작성한 코드에 이어서 DictDB, ArrayDB를 사용하는 부분을 추가로 작성해봅시다.

이전 파트 1 에서 작성한 샘플 코드

__init__

DictDB를 사용할 멤버 변수를 self._dict_db와 같이 선언합니다.

ArrayDB의 경우 내부적인 버그로 인해 잠시동안 __init__에서의 변수 선언이 아닌 property로 별도로 선언하여, 사용시 마다 ArrayDB 인스턴스를 생성하여 사용하도록 합니다.

on_install

DictDBkey-value“Jin” : “Developer”, “nanaones” : “Developer”, “ICON” : “Blockchain”, “SCORE” : “Smart Contract” 를 입력합니다.

DictDBkey를 순회하며 value를 조회하기 위해 ArrayDBDictDBkey들을 입력합니다.

hello

VarDB, ArrayDB, DictDB 로 부터 데이터를 조회한 데이터를 가공하여 str 형태로 반환해 봅시다.

[el for el in self._array_db]ArrayDB에 저장한 key들을 순회하며 맞춰 el 로 가져와 value_type에 맞게 변형하여 list에 추가하고, 최종적으로 생성된 list를 결과로 반환합니다.

self._dict_db[key]DictDB로 부터 key에 해당하는 value들을 조회하고 value_type에 맞게 변형하여 반환합니다.

샘플 코드의 [(el, self_dict_db[el]) for el in self._array_db]ArrayDB로 부터 가져온 key들을 순회하며 DictDB로 부터 key에 해당하는 value들을 불러와 keyvaluetuple형태로 묶어 list에 추가하고, 최종적으로 생성된 list를 결과로 반환합니다.

파트 2 샘플 코드
샘플코드 hello 메소드 호출 결과

이것으로 How to SCORE 시리즈의 두번째 파트를 마치겠습니다.

다음 파트에서는 fallback 메소드와 @payable 데코레이터, ICX 전송과 예외 처리에 대해 알아보도록 하겠습니다.

ICON 과 관련된 추가적인 질문사항이 있는 경우, ICON 의 공식 개발자포럼 혹은 페이스북 그룹에 질문하시면 답변을 얻으실 수 있습니다.

아이콘 공식 개발자포럼

Dive into ICON 페이스북 그룹

ICON Developers 유튜브 채널

--

--

Joonyoung Choi
B!ock.Chain

Blockchain / Java / Python / Developer / Researcher