Skip to content

Commit

Permalink
Merge branch 'release/v1.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
quvox committed Oct 21, 2018
2 parents 1f62a2d + 4467424 commit 8d7e1d3
Show file tree
Hide file tree
Showing 127 changed files with 2,869 additions and 3,456 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
Change log
======

## v1.1
* ID truncation (ID length less than 256-bit) support
* X509 certificate for public key
* KeyPair class in bbclib.py can receive X509 self-signed certificate
* ECC Prime-256 v1 support for private/public key
* libbbcsig is decoupled to https://github.com/beyond-blockchain/libbbcsig
* default config is introduced
* search count upper limit is configurable
* Extend transaction search functions (#94)
* Buf fixes

## v1.0.1
* Bug fixes
* pip install bug is fixed but pipenv install still has some troubles.
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
Core system of BBc-1 (Beyond Blockchain One)
===========================================
![travisCI](https://travis-ci.org/beyond-blockchain/bbc1.svg?branch=develop)

This project is a Python-based reference implementation of BBc-1, a trustable system of record keeping beyond blockchains.

Expand All @@ -27,9 +26,9 @@ Some documents are available in docs/.
* [BBc-trust_ja.pdf](docs/BBc-trust_ja.pdf)
* [BBc-1_design_paper.pdf](docs/BBc-1_design_paper.pdf)
* [BBc1_design_document_v1.0_ja.pdf](docs/BBc1_design_document_v1.0_ja.pdf)
* [How_BBc1_works_v1.0_ja.pdf](docs/How_BBc1_works_v1.0_ja.pdf)
* [How_BBc1_works_v1.0.2_ja.pdf](docs/How_BBc1_works_v1.0.2_ja.pdf)
* Usage
* [How_to_use_BBc1_v1.0_ja.pdf](docs/How_to_use_BBc1_v1.0_ja.pdf)
* [How_to_use_BBc1_v1.0.2_ja.pdf](docs/How_to_use_BBc1_v1.0.2_ja.pdf)
* [BBc1_core_tutorial_installation_ja.md](docs/BBc1_core_tutorial_installation_ja.md)
* [how_to_use_in_nat_environment.md](docs/how_to_use_in_nat_environment.md)
* [libbbcsig_dll_build_for_Windows_x64_ja.md](docs/libbbcsig_dll_build_for_Windows_x64_ja.md)
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ Some documents are available in docs/.
* [BBc-trust_ja.pdf](docs/BBc-trust_ja.pdf)
* [BBc-1_design_paper.pdf](docs/BBc-1_design_paper.pdf)
* [BBc1_design_document_v1.0_ja.pdf](docs/BBc1_design_document_v1.0_ja.pdf)
* [How_BBc1_works_v1.0_ja.pdf](docs/How_BBc1_works_v1.0_ja.pdf)
* [How_BBc1_works_v1.0.2_ja.pdf](docs/How_BBc1_works_v1.0.2_ja.pdf)
* Usage
* [How_to_use_BBc1_v1.0_ja.pdf](docs/How_to_use_BBc1_v1.0_ja.pdf)
* [How_to_use_BBc1_v1.0.2_ja.pdf](docs/How_to_use_BBc1_v1.0.2_ja.pdf)
* [BBc1_core_tutorial_installation_ja.md](docs/BBc1_core_tutorial_installation_ja.md)
* [how_to_use_in_nat_environment.md](docs/how_to_use_in_nat_environment.md)
* [libbbcsig_dll_build_for_Windows_x64_ja.md](docs/libbbcsig_dll_build_for_Windows_x64_ja.md)
Expand Down
55 changes: 48 additions & 7 deletions bbc1/core/bbc_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,17 +162,17 @@ def _make_message_structure(self, cmd):
cmd (bytes): command type defined in bbclib.MsgType class
"""
self.query_id = ((int.from_bytes(self.query_id, 'little') + 1) % 65536).to_bytes(2, 'little')
if cmd not in MESSAGE_WITH_NO_RESPONSE:
if self.use_query_id_based_message_wait:
if self.query_id not in self.callback.query_queue:
self.callback.create_queue(self.query_id)
msg = {
KeyType.command: cmd,
KeyType.domain_id: self.domain_id,
KeyType.source_user_id: self.user_id,
KeyType.query_id: self.query_id,
KeyType.status: ESUCCESS,
}
if cmd not in MESSAGE_WITH_NO_RESPONSE:
msg[KeyType.query_id] = self.query_id
if self.use_query_id_based_message_wait:
if self.query_id not in self.callback.query_queue:
self.callback.create_queue(self.query_id)
return msg

def _send_msg(self, dat):
Expand Down Expand Up @@ -597,7 +597,7 @@ def insert_transaction(self, tx_obj):
dat[KeyType.all_asset_files] = ast
return self._send_msg(dat)

def search_transaction_with_condition(self, asset_group_id=None, asset_id=None, user_id=None, count=1):
def search_transaction_with_condition(self, asset_group_id=None, asset_id=None, user_id=None, direction=0, count=1):
"""Search transaction data by asset_group_id/asset_id/user_id
If multiple conditions are specified, they are considered as AND condition.
Expand All @@ -606,6 +606,7 @@ def search_transaction_with_condition(self, asset_group_id=None, asset_id=None,
asset_group_id (bytes): asset_group_id in BBcEvent and BBcRelations
asset_id (bytes): asset_id in BBcAsset
user_id (bytes): user_id in BBcAsset that means the owner of the asset
direction (int): 0: descend, 1: ascend
count (int): the number of transactions to retrieve
Returns:
bytes: query_id
Expand All @@ -617,6 +618,7 @@ def search_transaction_with_condition(self, asset_group_id=None, asset_id=None,
dat[KeyType.asset_id] = asset_id
if user_id is not None:
dat[KeyType.user_id] = user_id
dat[KeyType.direction] = direction
dat[KeyType.count] = count
return self._send_msg(dat)

Expand All @@ -632,21 +634,48 @@ def search_transaction(self, transaction_id):
dat[KeyType.transaction_id] = transaction_id
return self._send_msg(dat)

def traverse_transactions(self, transaction_id, direction=1, hop_count=3):
def count_transactions(self, asset_group_id=None, asset_id=None, user_id=None):
"""Count transactions that matches the given conditions
If multiple conditions are specified, they are considered as AND condition.
Args:
asset_group_id (bytes): asset_group_id in BBcEvent and BBcRelations
asset_id (bytes): asset_id in BBcAsset
user_id (bytes): user_id in BBcAsset that means the owner of the asset
Returns:
int: the number of transactions
"""
dat = self._make_message_structure(MsgType.REQUEST_COUNT_TRANSACTIONS)
if asset_group_id is not None:
dat[KeyType.asset_group_id] = asset_group_id
if asset_id is not None:
dat[KeyType.asset_id] = asset_id
if user_id is not None:
dat[KeyType.user_id] = user_id
return self._send_msg(dat)

def traverse_transactions(self, transaction_id, asset_group_id=None, user_id=None, direction=1, hop_count=3):
"""Search request for transactions
The method traverses the transaction graph in the ledger.
The response from the bbc_core includes the list of transactions.
Args:
transaction_id (bytes): the target transaction to retrieve
asset_group_id (bytes): asset_group_id that target transactions should have
user_id (bytes): user_id that target transactions should have
direction (int): 1:backforward, non-1:forward
hop_count (int): hop count to traverse from the specified origin point
Returns:
bytes: query_id
"""
dat = self._make_message_structure(MsgType.REQUEST_TRAVERSE_TRANSACTIONS)
dat[KeyType.transaction_id] = transaction_id
if asset_group_id is not None:
dat[KeyType.asset_group_id] = asset_group_id
if user_id is not None:
dat[KeyType.user_id] = user_id
dat[KeyType.direction] = direction
dat[KeyType.hop_count] = hop_count
return self._send_msg(dat)
Expand Down Expand Up @@ -832,6 +861,8 @@ def dispatch(self, dat, payload_type):
self.proc_resp_search_transaction(dat)
elif dat[KeyType.command] == MsgType.RESPONSE_SEARCH_WITH_CONDITIONS:
self.proc_resp_search_with_condition(dat)
elif dat[KeyType.command] == MsgType.RESPONSE_COUNT_TRANSACTIONS:
self.proc_resp_count_transactions(dat)
elif dat[KeyType.command] == MsgType.RESPONSE_TRAVERSE_TRANSACTIONS:
self.proc_resp_traverse_transactions(dat)
elif dat[KeyType.command] == MsgType.RESPONSE_GATHER_SIGNATURE:
Expand Down Expand Up @@ -1007,6 +1038,16 @@ def proc_resp_search_transaction(self, dat):
"""
self.queue.put(dat)

def proc_resp_count_transactions(self, dat):
"""Callback for message RESPONSE_COUNT_TRANSACTIONS
This method should be overridden if you want to process the message asynchronously.
Args:
dat (dict): received message
"""
self.queue.put(dat)

def proc_resp_traverse_transactions(self, dat):
"""Callback for message RESPONSE_TRAVERSE_TRANSACTIONS
Expand Down
64 changes: 38 additions & 26 deletions bbc1/core/bbc_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

TIMEOUT_TIMER = 3

current_config = {
plain_config = {
'workingdir': DEFAULT_WORKING_DIR,
'client': {
'port': DEFAULT_CORE_PORT,
Expand All @@ -50,6 +50,10 @@
'directory': DEFAULT_WORKING_DIR+"/domain_keys",
'obsolete_timeout': 300,
},
'search_config': {
'max_count': 30,
'max_traverse': 30,
},
'domains': {
'0000000000000000000000000000000000000000000000000000000000000000': {
'module': 'p2p_domain0',
Expand All @@ -64,6 +68,21 @@
},
},
},
'domain_default': {
'storage': {
"type": "internal", # or "external"
},
'db': {
"db_type": "sqlite", # or "mysql"
"db_name": "bbc_ledger.sqlite",
"replication_strategy": "all", # or "p2p"/"external" (valid only in db_type=mysql)
"db_servers": [{"db_addr": "127.0.0.1", "db_port": 3306, "db_user": "user", "db_pass": "pass"}]
# valid only in the case of db_type=mysql
},
'static_nodes': {
# id : [ipv4, ipv6, port]
},
},
'ethereum': {
'chain_id': DEFAULT_ETHEREUM_CHAIN_ID,
'port': DEFAULT_ETHEREUM_GETH_PORT,
Expand All @@ -76,6 +95,17 @@
}


def load_config(filepath):
config = dict()
with open(filepath, "r") as f:
try:
config = json.load(f)
except:
print("config file must be in JSON format")
os._exit(1)
return config


def update_deep(d, u):
"""Utility for updating nested dictionary"""
for k, v in u.items():
Expand All @@ -92,8 +122,8 @@ def update_deep(d, u):

class BBcConfig:
"""System configuration"""
def __init__(self, directory=None, file=None):
self.config = copy.deepcopy(current_config)
def __init__(self, directory=None, file=None, default_confpath=None):
self.config = copy.deepcopy(plain_config)
if directory is not None:
self.working_dir = directory
self.config['workingdir'] = self.working_dir
Expand All @@ -109,18 +139,14 @@ def __init__(self, directory=None, file=None):

if os.path.isfile(self.config_file):
update_deep(self.config, self.read_config())

if default_confpath is not None and os.path.exists(default_confpath):
self.config.update(load_config(default_confpath))
self.update_config()

def read_config(self):
"""Read config file"""
config = dict()
with open(self.config_file, "r") as f:
try:
config = json.load(f)
except:
print("config file must be in JSON format")
os._exit(1)
return config
return load_config(self.config_file)

def update_config(self):
"""Write config to file (config.json)"""
Expand Down Expand Up @@ -150,21 +176,7 @@ def get_domain_config(self, domain_id, create_if_new=False):
self.config['domains'][domain_id_str] = conf['domains'][domain_id_str]

if create_if_new and domain_id_str not in self.config['domains']:
self.config['domains'][domain_id_str] = {
'storage': {
"type": "internal", # or "external"
},
'db': {
"db_type": "sqlite", # or "mysql"
"db_name": "bbc_ledger.sqlite",
"replication_strategy": "all", # or "p2p"/"external" (valid only in db_type=mysql)
"db_servers": [{"db_addr": "127.0.0.1", "db_port": 3306, "db_user": "user", "db_pass": "pass"}]
# valid only in the case of db_type=mysql
},
'static_nodes': {
# id : [ipv4, ipv6, port]
},
}
self.config['domains'][domain_id_str] = self.config['domain_default']
if domain_id_str in self.config['domains']:
return self.config['domains'][domain_id_str]
return None
Expand Down

0 comments on commit 8d7e1d3

Please sign in to comment.