Exemplo n.º 1
0
class PendingTxDbProxy:
    def __init__(self, db: IconScoreDatabase):
        self._last_pending_tx_id_db = VarDB(LAST_TX_ID, db, int)
        self._pending_tx_list = DictDB(PENDING_TX, db, str, 1)
        self._pending_tx_id_list_db = VarDB(PENDING_TX_ID_LIST, db, str)

    def add(self, account_id, token_type, contract_addr, to, amount,
            dids) -> str:
        """

        :param account_id:
        :param token_type:
        :param contract_addr:
        :param to:
        :param amount:
        :param dids:
        :return:
        """
        # get need data
        last_tx_id = self._last_pending_tx_id_db.get() + 1

        pending_tx_id_list_as_str = self._pending_tx_id_list_db.get()
        if pending_tx_id_list_as_str == "":
            pending_tx_id_list_as_str = json_dumps([])

        pending_tx_id_list = json_loads(pending_tx_id_list_as_str)

        # create pending tx
        pending_tx = {
            "id": last_tx_id,
            "tokenType": token_type,
            "contractAddr": contract_addr,
            "from": account_id,
            "to": to,
            "amount": amount,
            "dids": dids
        }

        # update db
        pending_tx_as_str = json_dumps(pending_tx)
        self._pending_tx_list[last_tx_id] = pending_tx_as_str
        self._last_pending_tx_id_db.set(last_tx_id)
        pending_tx_id_list.append(last_tx_id)
        self._pending_tx_id_list_db.set(json_dumps(pending_tx_id_list))
        return pending_tx_as_str

    def get(self, tx_id: int) -> dict:
        if self._pending_tx_list[tx_id] != "":
            return json_loads(self._pending_tx_list[tx_id])
        return {}

    def remove(self, tx_id: int):
        del self._pending_tx_list[tx_id]
        pending_tx_id_list = json_loads(
            self._pending_tx_id_list_db.get())  # type: List
        pending_tx_id_list.remove(tx_id)
        self._pending_tx_id_list_db.set(json_dumps(pending_tx_id_list))

    def update(self, pending_tx: dict):
        self._pending_tx_list[pending_tx["id"]] = json_dumps(pending_tx)
Exemplo n.º 2
0
    def _var_db_perfomance(self, range_cnt: int, _create_db_func: callable):
        self._setup(range_cnt, _create_db_func)

        var_db = VarDB(VAR_DB, self.db, value_type=Address)
        var_db.set(0)

        start = time.time()

        # LOGIC
        for i in range(range_cnt):
            a = var_db.get()

        print(f"_var_db_perfomance [{_create_db_func.__name__} {range_cnt} :",
              time.time() - start)

        self._tear_down()
    def test_pending_transaction(self):
        """ GIVEN account with did_list not empty
        WHEN call transfer with transferable info
        THEN a transaction will be pending
        """
        # GIVEN
        self.__setup_processing_pending_tx()

        # THEN
        def PendingMock(_self, pending_tx: str):
            print(pending_tx)
            pending_tx_as_dict = json.loads(pending_tx)
            self.assertEqual(1, pending_tx_as_dict["id"])
            self.assertEqual(0, pending_tx_as_dict["from"])
            self.assertEqual("hx" + "1" * 40, pending_tx_as_dict["to"])
            self.assertEqual("icx", pending_tx_as_dict["tokenType"])
            self.assertEqual("", pending_tx_as_dict["contractAddr"])
            self.assertEqual(500, pending_tx_as_dict["amount"])
            self.assertEqual(["kakao", "chainId"], pending_tx_as_dict["dids"])

        SmartWallet.Pending = PendingMock

        # WHEN
        self.smart_wallet.transfer(account_id=0,
                                   token_type="icx",
                                   contract_addr="",
                                   to="hx" + "1" * 40,
                                   amount=500)

        # THEN
        pending_tx_db = DictDB(PENDING_TX, self.smart_wallet.db, str, 1)
        pending_tx_as_dict = json.loads(pending_tx_db[1])
        self.assertEqual(1, pending_tx_as_dict["id"])
        self.assertEqual(0, pending_tx_as_dict["from"])
        self.assertEqual("hx" + "1" * 40, pending_tx_as_dict["to"])
        self.assertEqual("icx", pending_tx_as_dict["tokenType"])
        self.assertEqual("", pending_tx_as_dict["contractAddr"])
        self.assertEqual(500, pending_tx_as_dict["amount"])
        self.assertEqual(["kakao", "chainId"], pending_tx_as_dict["dids"])

        pending_tx_list = json.loads(
            VarDB(PENDING_TX_ID_LIST, self.smart_wallet.db, str).get())
        self.assertEqual(1, len(pending_tx_list))
        self.assertEqual(1, pending_tx_list[0])

        last_tx_id = VarDB(LAST_TX_ID, self.smart_wallet.db, int).get()
        self.assertEqual(1, last_tx_id)
class SampleScore(IconScoreBase):
    def __init__(self, db: 'IconScoreDatabase') -> None:
        super().__init__(db)
        self._db_field = VarDB("field", db, value_type=int)

    def on_install(self) -> None:
        pass

    def on_update(self) -> None:
        pass

    def get_owner(self,
                  score_address: Optional['Address']) -> Optional['Address']:
        return None

    @eventlog(indexed=2)
    def SampleEvent(self, i_data: bytes, address: Address, data: bytes,
                    text: str):
        pass

    @external
    def transfer(self):
        self.icx.transfer(self.msg.sender, 10)

    @external
    def set_db(self, size: int):
        data = b'1' * size
        self._db_field.set(data)

    @external
    def get_db(self):
        get = self._db_field.get()

    @external(readonly=True)
    def query_db(self) -> bytes:
        get = self._db_field.get()
        return get

    @external(readonly=True)
    def hash_readonly(self, data: bytes) -> bytes:
        return sha3_256(data)

    @external
    def hash_writable(self, data: bytes) -> bytes:
        return sha3_256(data)
Exemplo n.º 5
0
    def __init__(self,
                 key,
                 db: IconScoreDatabase,
                 value_type: type,
                 with_flush: bool = False) -> None:
        self.__base_db = db
        self.__prefix = str(key)
        self.__value_type = value_type

        if not (issubclass(value_type, IterableDictDB)
                or issubclass(value_type, PropertiesDB)):
            self.__db = DictDB(self._sub_prefix("_dict"), db, value_type)

        # TODO using AutoExpand for __db_keys
        self.__db_keys = VarDB(self._sub_prefix("_keys"), db, value_type=str)
        self.__with_flush = with_flush
        self.__cache = {}  # cache of db
        self.__keys = []
        self.__is_loaded_keys = False
        self.__add = {}
        self.__remove = {}
        self.__update = {}
Exemplo n.º 6
0
    def _create_new_db(self, range_cnt: int):
        self.db = self._create_plyvel_db(range_cnt)
        self._context = IconScoreContext(IconScoreContextType.DIRECT)
        self._context.current_address = self.db.address
        self._context.revision = REVISION
        ContextContainer._push_context(self._context)

        ## LOGIC

        var_db = VarDB(VAR_DB, self.db, value_type=int)
        array_db = ArrayDB(ARRAY_DB, self.db, value_type=Address)
        dict_db1 = DictDB(DICT_DB1, self.db, value_type=Address)
        dict_db2 = DictDB(DICT_DB2, self.db, value_type=int)

        index: int = 0
        for index in range(range_cnt):
            addr: 'Address' = create_address()
            array_db.put(addr)
            dict_db1[index] = addr
            dict_db2[addr] = index
        var_db.set(index)

        ContextContainer._pop_context()
    def test_approval(self):
        """ GIVEN account with two dids, and pending one tx from that account,
        WHEN call approval twice
        THEN first approval remove dids in pending tx, second remove pending tx
        with TransferSuccess event
        """
        # GIVEN
        self.__setup_processing_pending_tx()
        SmartWallet.Pending = lambda _self, pending_tx: None

        self.smart_wallet.transfer(account_id=0,
                                   token_type="icx",
                                   contract_addr="",
                                   to="hx" + "1" * 40,
                                   amount=500)

        # first WHEN
        def FirstApprovalMock(_self, tx_id, did):
            self.assertEqual(1, tx_id)
            self.assertEqual("kakao", did)

        SmartWallet.Approval = FirstApprovalMock
        self.smart_wallet.approval(1, "kakao", "true")

        # first THEN
        pending_tx_db = DictDB(PENDING_TX, self.smart_wallet.db, str, 1)
        pending_tx_as_dict = json.loads(pending_tx_db[1])
        self.assertEqual(["chainId"], pending_tx_as_dict["dids"])

        # second WHEN
        def SecondApprovalMock(_self, tx_id, did):
            self.assertEqual(1, tx_id)
            self.assertEqual("chainId", did)

        SmartWallet.Approval = SecondApprovalMock
        SmartWallet.TransferSuccess = lambda _self, account_id, token_type, contract_addr, to, amount: None

        self.smart_wallet.approval(1, "chainId", "true")

        # second THEN
        self.assertEqual("", pending_tx_db[1])
        self.assertEqual(
            json.dumps([]),
            VarDB(PENDING_TX_ID_LIST, self.smart_wallet.db, str).get())
Exemplo n.º 8
0
 def __init__(self, db: 'IconScoreDatabase') -> None:
     super().__init__(db)
     self._db_field = VarDB("field", db, value_type=int)
Exemplo n.º 9
0
 def __init__(self, db: IconScoreDatabase):
     self._last_pending_tx_id_db = VarDB(LAST_TX_ID, db, int)
     self._pending_tx_list = DictDB(PENDING_TX, db, str, 1)
     self._pending_tx_id_list_db = VarDB(PENDING_TX_ID_LIST, db, str)
Exemplo n.º 10
0
class IterableDictDB(ABC):
    def __init__(self,
                 key,
                 db: IconScoreDatabase,
                 value_type: type,
                 with_flush: bool = False) -> None:
        self.__base_db = db
        self.__prefix = str(key)
        self.__value_type = value_type

        if not (issubclass(value_type, IterableDictDB)
                or issubclass(value_type, PropertiesDB)):
            self.__db = DictDB(self._sub_prefix("_dict"), db, value_type)

        # TODO using AutoExpand for __db_keys
        self.__db_keys = VarDB(self._sub_prefix("_keys"), db, value_type=str)
        self.__with_flush = with_flush
        self.__cache = {}  # cache of db
        self.__keys = []
        self.__is_loaded_keys = False
        self.__add = {}
        self.__remove = {}
        self.__update = {}

    @property
    def base_db(self) -> IconScoreDatabase:
        return self.__base_db

    @abstractmethod
    def raw_to_object(self, raw):
        pass

    @abstractmethod
    def object_to_raw(self, obj):
        pass

    @property
    def _base_db(self) -> IconScoreDatabase:
        return self.__base_db

    @property
    def _prefix(self) -> str:
        return self.__prefix

    def _sub_prefix(self, prefix: str) -> str:
        if self.__prefix is None:
            raise Exception("not initialized")
        if prefix is None:
            raise Exception("invalid prefix")
        return '|'.join([self.__prefix, prefix])

    def flush(self):
        if self.__with_flush:
            if issubclass(self.__value_type, IterableDictDB) or issubclass(
                    self.__value_type, PropertiesDB):
                for key in self.__add:
                    v = self.__add[key]
                    v.flush()
                for key in self.__update:
                    v = self.__update[key]
                    v.flush()
                for key in self.__remove:
                    v = self.__remove[key]
                    v.flush()
            else:
                for key in self.__add:
                    self.__db[key] = self.object_to_raw(self.__add[key])
                for key in self.__update:
                    self.__db[key] = self.object_to_raw(self.__update[key])
                for key in self.__remove:
                    self.__db.remove(key)

            if len(self.__add) + len(self.__remove) > 0:
                self._flush_keys()

    def _flush_keys(self) -> None:
        serialized = ",".join(self.__keys)
        self.__db_keys.set(serialized)

    def _load_keys(self) -> list:
        if not self.__is_loaded_keys:
            serialized = self.__db_keys.get()
            if len(serialized) > 1:
                self.__keys = serialized.split(",")
            self.__is_loaded_keys = True
        return self.__keys

    def _add_key(self, key: str) -> None:
        # TODO [TBD] encode with escape for delimiter(',')
        if "," in key:
            raise Exception('key could not contains comma')
        self._load_keys()
        self.__keys.append(key)
        if not self.__with_flush:
            self._flush_keys()

    def _remove_key(self, key: str) -> int:
        self._load_keys()
        index = self._index_key(key)
        self.__keys.pop(index)
        if not self.__with_flush:
            self._flush_keys()
        return index

    def _index_key(self, key: str) -> int:
        self._load_keys()
        for i in range(len(self.__keys)):
            if self.__keys[i] == key:
                return i
        return -1

    def keys(self) -> list:
        self._load_keys()
        return self.__keys

    def at(self, index: int):
        keys = self.keys()
        if len(keys) > index:
            return self._get(keys[index])
        else:
            raise Exception("out of range")

    def _cache(self, key: str):
        if key in self.__cache:
            return self.__cache[key]
        else:
            if self._contains(key):
                if issubclass(self.__value_type, IterableDictDB):
                    raw = self.raw_to_object(key)
                elif issubclass(self.__value_type, PropertiesDB):
                    raw = self.raw_to_object(key)
                else:
                    raw = self.__db[key]
                self.__cache[key] = raw
                return raw
            else:
                return None

    def _set(self, key: str, value) -> None:
        if key in self.__add:
            self.__add[key] = value
        elif key in self.__update:
            self.__update[key] = value
        elif key in self.__remove:
            self.__remove.pop(key)
            self.__update[key] = value
            self._add_key(key)
        else:
            raw = self._cache(key)
            if raw is None:
                self.__add[key] = value
                self._add_key(key)
            else:
                self.__update[key] = value
        if not self.__with_flush:
            if not (issubclass(self.__value_type, IterableDictDB)
                    or issubclass(self.__value_type, PropertiesDB)):
                self.__db[key] = self.object_to_raw(value)

    def _get(self, key: str):
        if key in self.__add:
            return self.__add[key]
        elif key in self.__update:
            return self.__update[key]
        elif key in self.__remove:
            return None
        else:
            raw = self._cache(key)
            if raw is None:
                return None
            else:
                if not (issubclass(self.__value_type, IterableDictDB)
                        or issubclass(self.__value_type, PropertiesDB)):
                    return self.raw_to_object(raw)
                else:
                    return raw

    def remove(self, key) -> None:
        key = str(key)
        if key in self.__add:
            self.__add.pop(key)
            return
        elif key in self.__remove:
            return
        elif key in self.__update:
            self.__update.pop(key)

        v = self._cache(key)
        if v is None:
            return

        self._remove_key(key)
        self.__remove[key] = v
        self.__cache.pop(key)

        if isinstance(v, IterableDictDB) or isinstance(v, PropertiesDB):
            v.remove_all()
        else:
            if not self.__with_flush:
                self.__db.remove(key)

    def remove_all(self):
        for k in self.keys():
            self.remove(k)

    def _contains(self, key: str) -> bool:
        index = self._index_key(key)
        if index < 0:
            return False
        else:
            return True

    def __setitem__(self, key, value) -> None:
        key = str(key)
        if value is None:
            self.remove(key)
        else:
            self._set(key, value)

    def __getitem__(self, key):
        key = str(key)
        return self._get(key)

    def __delitem__(self, key):
        key = str(key)
        return self.remove(key)

    def __contains__(self, key):
        key = str(key)
        return self._contains(key)

    def __iter__(self):
        return self.keys().__iter__()

    def __len__(self):
        return self.keys().__len__()

    def to_dict(self) -> dict:
        d = {}
        for k in self.keys():
            v = self._get(k)
            d[k] = v
        return d

    def __repr__(self):
        return self.dump()

    def dump(self, depth: int = 0):
        t1 = '\t' * (depth * 2)
        s = f'{t1}{self.__prefix}[\n'
        t = '\t' * (depth * 2 + 1)
        for k in self.keys():
            el = self._get(k)
            v = ''
            if isinstance(el, IterableDictDB):
                v += el.dump(depth + 1)
                s += f'{t}[key:{k}, value:\n{v}{t}]\n'
            elif isinstance(el, PropertiesDB):
                v += el.dump(depth + 1)
                s += f'{t}[key:{k}, value:\n{v}{t}]\n'
            else:
                s += f'{t}[key:{k}, value:{v}]\n'
        s += f'{t1}]\n'
        return s