From 54a3b505bb7e5955d45b70db2eaa79628b4616f2 Mon Sep 17 00:00:00 2001 From: dapiguabc Date: Sat, 23 Apr 2022 01:44:37 +0800 Subject: [PATCH 1/2] add blockservice driver --- contracting/db/driver.py | 49 +++++++++ tests/unit/test_blockservice_driver.py | 141 +++++++++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 tests/unit/test_blockservice_driver.py diff --git a/contracting/db/driver.py b/contracting/db/driver.py index b3ec3b0c..7157e685 100644 --- a/contracting/db/driver.py +++ b/contracting/db/driver.py @@ -715,3 +715,52 @@ def get_contract_keys(self, name): # self.pending_writes[key] = None +class BlockserviceDriver(Driver): + # conn_str see https://www.mongodb.com/docs/manual/reference/connection-string/ + def __init__(self, conn_str="mongodb://localhost:27017", db='lamden', collection='currentState'): + self.client = pymongo.MongoClient(conn_str) + self.db = self.client[db][collection] + + def get(self, item: str): + v = self.db.find_one({'rawKey': item}) + if v is None: + return None + + if isinstance(v['value'], dict): + return decode(encode(v['value'])) + + if decode(v['value']) is None: + return v['value'] + + return decode(v['value']) + + def set(self, key, value): + # Do nothing to keep readonly. + pass + + def iter(self, prefix: str, length=0): + cur = self.db.find({'rawKey': {'$regex': f'^{prefix}'}}) + + keys = [] + for entry in cur: + keys.append(entry['rawKey']) + if 0 < length <= len(keys): + break + + keys.sort() + return keys + + def keys(self): + k = [] + for entry in self.db.find({}): + k.append(entry['rawKey']) + k.sort() + return k + + def __delitem__(self, key: str): + # Do nothing to keep readonly. + pass + + def flush(self): + # Do nothing to keep readonly. + pass \ No newline at end of file diff --git a/tests/unit/test_blockservice_driver.py b/tests/unit/test_blockservice_driver.py new file mode 100644 index 00000000..3db7eec0 --- /dev/null +++ b/tests/unit/test_blockservice_driver.py @@ -0,0 +1,141 @@ +from unittest import TestCase +from contracting.db.driver import BlockserviceDriver +from contracting.db.encoder import encode, MONGO_MAX_INT +from contracting.stdlib.bridge.time import Datetime, Timedelta +from contracting.stdlib.bridge.decimal import ContractingDecimal +import random + +SAMPLE_STRING = 'beef' +SAMPLE_INT = 123 +SAMPLE_BIGINT = MONGO_MAX_INT +SAMPLE_DATETIME = Datetime(year=2022, month=1, day=1) +SAMPLE_CONTRACTING_DECIMAL = ContractingDecimal(123.123) +SAMPLE_TIMEDELTA = Timedelta(weeks=1, days=1, hours=1) +SAMPLE_BYTES = bytes(b'0xbeef') +SAMPLE_DICT = { + 'a': SAMPLE_INT, + 'b': False, + 'c': SAMPLE_BIGINT, + 'd': SAMPLE_DATETIME, + 'e': SAMPLE_CONTRACTING_DECIMAL, + 'f': SAMPLE_TIMEDELTA, + 'g': SAMPLE_BYTES, + 'h': SAMPLE_STRING, + 'x': None +} + +TEST_DATA = [ + SAMPLE_STRING, SAMPLE_INT, SAMPLE_BIGINT, SAMPLE_DATETIME, + SAMPLE_CONTRACTING_DECIMAL, SAMPLE_TIMEDELTA, SAMPLE_BYTES, SAMPLE_DICT +] + +class TestBlockserviceDriver(TestCase): + + def setUp(self): + self.d = BlockserviceDriver() + self.d.db.drop() + + def dbset(self, key, value): + v = encode(value) + self.d.db.update_one({'rawKey': key}, {'$set': {'value': v}}, upsert=True, ) + + def test_get(self): + for v in TEST_DATA: + self.dbset('b', v) + + b = self.d.get('b') + + self.assertEqual(v, b) if not isinstance(v, dict) else self.assertDictEqual(v, b) + + def test_iter(self): + + prefix_1_keys = [ + 'b77aa343e339bed781c7c2be1267cd597', + 'bc22ede6e6fb4046d78bf2f9d1f8afdb6', + 'b93dbb37d993846d70b8a92779cbfbfe9', + 'be1a2783019de6ea7ef169cc55e48a3ae', + 'b1fe8db32b9185d628f4c346f0455023e', + 'bef918f83b6a0d1e4f980013342807cf8', + 'b004cb9235acb5f689d20904692bc026e', + 'b869ff9519d67354816af90867f4a5425', + 'bcd8e9100dcb601f65e849c147e3e972e', + 'b0111919a698f9816862b4ae662a6ed06', + ] + + prefix_2_keys = [ + 'x37fbab0bd2e60563c79469e5be41e515', + 'x30c6eb2ad176773b5ce6d590d2472dfe', + 'x3d4fc9480f0a07b28aa7646d5066b54d', + 'x387c3d4ab7f0c1c6ef549198fc14b525', + 'x5c74dc83e132e435e8512599e1075bc0', + 'x1472425d0d9bb5ff511e132896d54b13', + 'x2cedb5c52163c22a0b5f179001959dd2', + 'x6223f65e553280cd25cadeac6657555c', + 'xeae18af37c223dde92a71fef55e64afe', + 'xb8810784ffb360cd3ffc57b1d088e537', + ] + + keys = prefix_1_keys + prefix_2_keys + random.shuffle(keys) + + for k in keys: + self.dbset(k, k) + + p1 = [] + + for k in self.d.iter(prefix='b'): + p1.append(k) + + prefix_1_keys.sort() + p1.sort() + + self.assertListEqual(prefix_1_keys, p1) + + p2 = [] + + for k in self.d.iter(prefix='x'): + p2.append(k) + + prefix_2_keys.sort() + p2.sort() + + self.assertListEqual(prefix_2_keys, p2) + + def test_keys_returns_all_keys(self): + prefix_1_keys = [ + 'b77aa343e339bed781c7c2be1267cd597', + 'bc22ede6e6fb4046d78bf2f9d1f8afdb6', + 'b93dbb37d993846d70b8a92779cbfbfe9', + 'be1a2783019de6ea7ef169cc55e48a3ae', + 'b1fe8db32b9185d628f4c346f0455023e', + 'bef918f83b6a0d1e4f980013342807cf8', + 'b004cb9235acb5f689d20904692bc026e', + 'b869ff9519d67354816af90867f4a5425', + 'bcd8e9100dcb601f65e849c147e3e972e', + 'b0111919a698f9816862b4ae662a6ed06', + ] + + prefix_2_keys = [ + 'x37fbab0bd2e60563c79469e5be41e515', + 'x30c6eb2ad176773b5ce6d590d2472dfe', + 'x3d4fc9480f0a07b28aa7646d5066b54d', + 'x387c3d4ab7f0c1c6ef549198fc14b525', + 'x5c74dc83e132e435e8512599e1075bc0', + 'x1472425d0d9bb5ff511e132896d54b13', + 'x2cedb5c52163c22a0b5f179001959dd2', + 'x6223f65e553280cd25cadeac6657555c', + 'xeae18af37c223dde92a71fef55e64afe', + 'xb8810784ffb360cd3ffc57b1d088e537', + ] + + keys = prefix_1_keys + prefix_2_keys + random.shuffle(keys) + + for k in keys: + self.dbset(k, k) + + keys.sort() + + got_keys = self.d.keys() + + self.assertListEqual(keys, got_keys) \ No newline at end of file From f990d7ac8a4b53292efa482f1dbda1ca8499ff24 Mon Sep 17 00:00:00 2001 From: dapigu Date: Mon, 30 Jan 2023 23:11:29 +0800 Subject: [PATCH 2/2] update for blockservice driver --- contracting/db/driver.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/contracting/db/driver.py b/contracting/db/driver.py index 7157e685..3fd45cac 100644 --- a/contracting/db/driver.py +++ b/contracting/db/driver.py @@ -728,11 +728,21 @@ def get(self, item: str): if isinstance(v['value'], dict): return decode(encode(v['value'])) - - if decode(v['value']) is None: - return v['value'] - - return decode(v['value']) + + if isinstance(v['value'], int): + return v['value'] + + if isinstance(v['value'], list): + return v['value'] + + try: + res = decode(v['value']) + if res is None: + return v['value'] + return res + except Exception as e: + logging.exception(e) + return v['value'] def set(self, key, value): # Do nothing to keep readonly.