From 6486c323abdc5fda436edae7a28dbf3a913d2320 Mon Sep 17 00:00:00 2001 From: bun919tw Date: Tue, 14 Aug 2018 08:20:49 +0000 Subject: [PATCH] Add memory db in client --- plasma_cash/client/db/db_interface.py | 12 +++++ plasma_cash/client/db/memory_db.py | 13 +++++ plasma_cash/client/exceptions.py | 4 ++ plasma_cash/client/history.py | 36 ++++++++++++++ unit_tests/client/db/__init__.py | 0 unit_tests/client/db/test_memory_db.py | 19 +++++++ unit_tests/client/test_history.py | 69 ++++++++++++++++++++++++++ 7 files changed, 153 insertions(+) create mode 100644 plasma_cash/client/db/db_interface.py create mode 100644 plasma_cash/client/db/memory_db.py create mode 100644 plasma_cash/client/history.py create mode 100644 unit_tests/client/db/__init__.py create mode 100644 unit_tests/client/db/test_memory_db.py create mode 100644 unit_tests/client/test_history.py diff --git a/plasma_cash/client/db/db_interface.py b/plasma_cash/client/db/db_interface.py new file mode 100644 index 0000000..038e89f --- /dev/null +++ b/plasma_cash/client/db/db_interface.py @@ -0,0 +1,12 @@ +import abc + + +class DbInterface(abc.ABC): + + @abc.abstractmethod + def get_history(self, uid): + return NotImplemented + + @abc.abstractmethod + def save_history(self, uid, history): + return NotImplemented diff --git a/plasma_cash/client/db/memory_db.py b/plasma_cash/client/db/memory_db.py new file mode 100644 index 0000000..5be32d2 --- /dev/null +++ b/plasma_cash/client/db/memory_db.py @@ -0,0 +1,13 @@ +from .db_interface import DbInterface + + +class MemoryDb(DbInterface): + + def __init__(self): + self.uid = {} + + def get_history(self, uid): + return self.uid.get(uid) + + def save_history(self, uid, history): + self.uid[uid] = history diff --git a/plasma_cash/client/exceptions.py b/plasma_cash/client/exceptions.py index 252176e..ac3be2b 100644 --- a/plasma_cash/client/exceptions.py +++ b/plasma_cash/client/exceptions.py @@ -1,2 +1,6 @@ class RequestFailedException(Exception): """request failed without success http status""" + + +class TxHistoryNotFoundException(Exception): + """tx history is not found for specific block number""" diff --git a/plasma_cash/client/history.py b/plasma_cash/client/history.py new file mode 100644 index 0000000..511a8e3 --- /dev/null +++ b/plasma_cash/client/history.py @@ -0,0 +1,36 @@ +import rlp +from rlp.sedes import big_endian_int, binary, CountableList + +from .exceptions import TxHistoryNotFoundException + + +class History(rlp.Serializable): + EMPTY_TX = b'\x00' * 32 + + fields = [ + ('latest_tx_blk_num', big_endian_int), + ('tx_history', CountableList(binary)), + ('proofs', CountableList(binary)), + ('blk_num', CountableList(big_endian_int)) + ] + + def __init__(self, deposit_tx_blk_num, tx, proof): + self.latest_tx_blk_num = deposit_tx_blk_num + self.tx_history = [tx] + self.proofs = [proof] + self.blk_num = [deposit_tx_blk_num] + + def update_tx_history(self, blk_num, tx, proof): + if blk_num not in self.blk_num: + if tx != self.EMPTY_TX: + self.latest_tx_blk_num = max(self.latest_tx_blk_num, blk_num) + self.tx_history.append(tx) + self.proofs.append(proof) + self.blk_num.append(blk_num) + + def get_data_by_block(self, blk_num): + try: + idx = self.blk_num.index(blk_num) + except ValueError: + raise TxHistoryNotFoundException('tx history not found') + return self.tx_history[idx], self.proofs[idx] diff --git a/unit_tests/client/db/__init__.py b/unit_tests/client/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unit_tests/client/db/test_memory_db.py b/unit_tests/client/db/test_memory_db.py new file mode 100644 index 0000000..a87da2b --- /dev/null +++ b/unit_tests/client/db/test_memory_db.py @@ -0,0 +1,19 @@ +import pytest + +from plasma_cash.client.db.memory_db import MemoryDb + + +class TestMemoryDb(object): + @pytest.fixture(scope='function') + def db(self): + return MemoryDb() + + def test_save_and_get_history(self, db): + DUMMY_HISTORY = 'dummy history' + DUMMY_UID = 1 + db.save_history(DUMMY_UID, DUMMY_HISTORY) + assert db.get_history(DUMMY_UID) == DUMMY_HISTORY + + def test_history_not_found(self, db): + DUMMY_UID = 1 + assert db.get_history(DUMMY_UID) is None diff --git a/unit_tests/client/test_history.py b/unit_tests/client/test_history.py new file mode 100644 index 0000000..735e3e7 --- /dev/null +++ b/unit_tests/client/test_history.py @@ -0,0 +1,69 @@ +import pytest + +from plasma_cash.client.exceptions import TxHistoryNotFoundException +from plasma_cash.client.history import History + + +class TestHistory(object): + DUMMY_DEPOSIT_BLK_NUM = 1 + DUMMY_TX1 = 'dummy tx1' + DUMMY_PROOF1 = 'dummy proof1' + + @pytest.fixture(scope='function') + def history(self): + return History(self.DUMMY_DEPOSIT_BLK_NUM, self.DUMMY_TX1, self.DUMMY_PROOF1) + + def test_constructor(self): + history = History(self.DUMMY_DEPOSIT_BLK_NUM, self.DUMMY_TX1, self.DUMMY_PROOF1) + assert history.latest_tx_blk_num == self.DUMMY_DEPOSIT_BLK_NUM + assert history.tx_history == [self.DUMMY_TX1] + assert history.proofs == [self.DUMMY_PROOF1] + assert history.blk_num == [self.DUMMY_DEPOSIT_BLK_NUM] + + def test_update_history(self, history): + DUMMY_BLK_NUM = 2 + DUMMY_TX2 = 'dummy tx2' + DUMMY_PROOF2 = 'dummy proof2' + history.update_tx_history(DUMMY_BLK_NUM, DUMMY_TX2, DUMMY_PROOF2) + assert history.latest_tx_blk_num == 2 + assert history.tx_history == [self.DUMMY_TX1, DUMMY_TX2] + assert history.proofs == [self.DUMMY_PROOF1, DUMMY_PROOF2] + assert history.blk_num == [1, 2] + + def test_update_empty_history(self, history): + DUMMY_BLK_NUM = 2 + EMPTY_TX = b'\x00' * 32 + NON_INCLUSIVE_PROOF = 'non inclusion proof' + history.update_tx_history(DUMMY_BLK_NUM, EMPTY_TX, NON_INCLUSIVE_PROOF) + assert history.latest_tx_blk_num == 1 + assert history.tx_history == [self.DUMMY_TX1, EMPTY_TX] + assert history.proofs == [self.DUMMY_PROOF1, NON_INCLUSIVE_PROOF] + assert history.blk_num == [1, 2] + + def test_update_history_with_wrong_order(self, history): + DUMMY_BLK_NUM = 3 + DUMMY_TX3 = 'dummy tx3' + DUMMY_PROOF3 = 'dummy proof3' + history.update_tx_history(DUMMY_BLK_NUM, DUMMY_TX3, DUMMY_PROOF3) + assert history.tx_history == [self.DUMMY_TX1, DUMMY_TX3] + assert history.proofs == [self.DUMMY_PROOF1, DUMMY_PROOF3] + assert history.blk_num == [1, 3] + + DUMMY_BLK_NUM = 2 + DUMMY_TX2 = 'dummy tx2' + DUMMY_PROOF2 = 'dummy proof2' + history.update_tx_history(DUMMY_BLK_NUM, DUMMY_TX2, DUMMY_PROOF2) + assert history.tx_history == [self.DUMMY_TX1, DUMMY_TX3, DUMMY_TX2] + assert history.proofs == [self.DUMMY_PROOF1, DUMMY_PROOF3, DUMMY_PROOF2] + assert history.blk_num == [1, 3, 2] + + def test_get_data_by_block(self, history): + DUMMY_BLK_NUM = 1 + tx, proof = history.get_data_by_block(DUMMY_BLK_NUM) + assert tx == history.tx_history[0] + assert proof == history.proofs[0] + + def test_get_data_by_block_failed(self, history): + DUMMY_BLK_NUM = 2 + with pytest.raises(TxHistoryNotFoundException): + history.get_data_by_block(DUMMY_BLK_NUM)