diff --git a/.env.example b/.env.example index a0306b1bbe..ce3bf349af 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,8 @@ NODE_ENV=development NODE_IP= +DH_NODE_IP= +DH_NODE_PORT= +DH_WALLET= DB_USERNAME=root DB_PASSWORD=root diff --git a/.eslintrc.js b/.eslintrc.js index a578085b88..545d6741cc 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,10 +17,6 @@ module.exports = { "error", "unix" ], - "quotes": [ - "error", - "single" - ], "semi": [ "error", "always" diff --git a/.gitignore b/.gitignore index 133e4bf666..ff6de2f3c3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,10 @@ config.json package-lock.json kad-storage/* !kad-storage/.gitkeep -import-log.txt \ No newline at end of file +system/* +!system/.gitkeep +import-log.txt +OT-GIT-NODE-DEVELOP.zip +manual-testing-scripts +log.log + diff --git a/gulpfile.js b/gulpfile.js index a0c8c1fc35..c2881ad646 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,14 +1,14 @@ -const gulp = require('gulp') -const beautify = require('gulp-beautify') -const eslint = require('gulp-eslint') +const gulp = require('gulp'); +const beautify = require('gulp-beautify'); +const eslint = require('gulp-eslint'); gulp.task('make-origintrail-great-again', function () { - gulp.src('./**/*.js') - .pipe(beautify({ - indent_size: 2 - })) - .pipe(eslint({ - fix: true - })) - .pipe(gulp.dest('./')) -}) + gulp.src('./**/*.js') + .pipe(beautify({ + indent_size: 2 + })) + .pipe(eslint({ + fix: true + })) + .pipe(gulp.dest('./')); +}); diff --git a/importers/example.xml b/importers/default_example.xml similarity index 100% rename from importers/example.xml rename to importers/default_example.xml diff --git a/importers/default_importer.py b/importers/default_importer.py index 6b55409332..ac3863910f 100644 --- a/importers/default_importer.py +++ b/importers/default_importer.py @@ -48,7 +48,7 @@ password = os.environ.get("DB_PASSWORD"), enable_logging = True) -db = client.db('origintrail') +db = client.db(os.environ.get("DB_DATABASE")) # client.grant_user_access(os.environ.get("DB_USERNAME"), os.environ.get("DB_DATABASE")) current_graphs = db.graphs() diff --git a/importers/example_connected_v1.5.xml b/importers/example_connected_v1.5.xml new file mode 100644 index 0000000000..baa6b7845b --- /dev/null +++ b/importers/example_connected_v1.5.xml @@ -0,0 +1,200 @@ + + + WALLET_2_ID + + + + + + + RETAILER_ID + + + + Retailer + + +
Retailer's Street 01C
+ Bytesfield + Cryptonia + 20001 + + 00.0000 + 00.0000 + +
+
+
+ + + PROVIDER_ID + SomeValue + + + + + Green Warehouse Ltd + Gruene Warehouse Ltd + + + +
Data Boulevard 01
+ Traceshire + Cryptonia + 10000 + + 00.0000 + 00.0000 + +
+ Lorem Ipsum +
+
+
+ + + RETAILER_ID + + STORE_1 + + + + Retailer's Store + + Store + +
Retailer's Street 01C
+ Bytesfield + Cryptonia + 20001 + + 00.0000 + 00.0000 + +
+
+
+ + PROVIDER_ID + + WAREHOUSE_1 + SomeValue + + + + Provider's Warehouse + Das Warehouse des Anbieters + + + Warehouse + +
Data Boulevard 02
+ Traceshire + Cryptonia + 10000 + + 00.0000 + 00.0000 + +
+ Lorem Ipsum +
+
+ +
+ + + + OBJECT_2 + 1234567890124 + + + + Packed crypto Carrots 1 Kg + + Vegetable + Carrot + + The cryptiest carrots in the entire Cryptonia, packed for retail in 1 Kg package. + + + + + + + + OUTPUT_BATCH_ID + OBJECT_2 + SomeValue + + + + + 1 + Unit + + + 10 + Kg + + + Purchased on time + Lorem ipsum + + + +
+ + + + + TRANSACTION_3 + TRANSACTION_DOCUMENT_3 + + + + + OUTPUT_BATCH_ID + + + + 1 + Unit + + + 10 + Kg + + + + + + + + 21.12.2012T00:00:00 + Purchase + STORE_1 + Input + WAREHOUSE_1 + STORE_1 + Regular Purchase + + + 10 + 1% + 11 + USD + 0% + + + + + + +
diff --git a/importers/example_v1.5.xml b/importers/example_v1.5.xml new file mode 100644 index 0000000000..01267c8383 --- /dev/null +++ b/importers/example_v1.5.xml @@ -0,0 +1,469 @@ + + + WALLET_ID + + + + + + + PROVIDER_ID + SomeValue + + + + + Green Warehouse Ltd + Gruene Warehouse Ltd + + + +
Data Boulevard 01
+ Traceshire + Cryptonia + 10000 + + 00.0000 + 00.0000 + +
+ Lorem Ipsum +
+
+ + + PARTNER_ID + + + + Partner + + +
Farmer's Street 01B
+ Bytesfield + Cryptonia + 20000 + + 00.0000 + 00.0000 + +
+
+
+ + + RETAILER_ID + + + + Retailer + + +
Retailer's Street 01C
+ Bytesfield + Cryptonia + 20001 + + 00.0000 + 00.0000 + +
+
+
+
+ + + PROVIDER_ID + + WAREHOUSE_1 + SomeValue + + + + Provider's Warehouse + Das Warehouse des Anbieters + + + Warehouse + +
Data Boulevard 02
+ Traceshire + Cryptonia + 10000 + + 00.0000 + 00.0000 + +
+ Lorem Ipsum +
+
+ + PARTNER_ID + + FARM_1 + + + + Partner's Farm + + Farm + +
Farmer's Street 01B
+ Bytesfield + Cryptonia + 20000 + + 00.0000 + 00.0000 + +
+
+
+ + RETAILER_ID + + STORE_1 + + + + Retailer's Store + + Store + +
Retailer's Street 01C
+ Bytesfield + Cryptonia + 20001 + + 00.0000 + 00.0000 + +
+
+
+
+ + + + OBJECT_1 + 1234567890123 + 12345678 + 5u34bgouenf089dsavbna97ybf84rwens0vub9sudv + 5u34bgouenf089dsavbna97ybf84rwens0vub9sud0 + 5u34bgouenf089dsavbna97ybf84rwens0vub9sud1 + codeValue-dataMatrix + codeValue-upcA + codeValue-someOtherCode + + + + Raw crypto Carrots 50 Kg + Rohe Krypto Karotten 50 Kg + + Vegetable + Carrot + + The cryptiest carrots in the entire Cryptonia, packed in 50 Kg package. + + Lorem Ipsum + + + + + OBJECT_2 + 1234567890124 + + + + Packed crypto Carrots 1 Kg + + Vegetable + Carrot + + The cryptiest carrots in the entire Cryptonia, packed for retail in 1 Kg package. + + + + + + + + INPUT_BATCH_ID + OBJECT_1 + SomeValue + + + + + 1 + Unit + + + 50 + Kg + + + Recieved on time + Lorem ipsum + + + + + OUTPUT_BATCH_ID + OBJECT_2 + SomeOtherValue + + + + + 50 + Unit + + + 50 + Kg + + + Labeled on time + Lorem ipsum + + + +
+ + + + + TRANSACTION_1 + TRANSACTION_DOCUMENT_1 + + + + + + + INPUT_BATCH_ID + + + + 50 + Unit + + + 50 + Kg + + + + + + + + OUTPUT_BATCH_ID + + + + 1 + Unit + + + 50 + Kg + + + + + + + + 21.01.2018T00:00:00 + Packaging + WAREHOUSE_1 + Packaging carrots for retail + + Machine 1 jammed for 5 minutes + + + + + + + + TRANSACTION_2 + TRANSACTION_DOCUMENT_2 + + + + + INPUT_BATCH_ID + + + + 1 + Unit + + + 50 + Kg + + + + + + + + 21.12.2012T00:00:00 + Purchase + WAREHOUSE_1 + Input + FARM_1 + WAREHOUSE_1 + Regular Purchase + + + 100 + 1% + 101 + USD + 0% + + Bill + + + + + + TRANSACTION_3 + TRANSACTION_DOCUMENT_3 + + + + + OUTPUT_BATCH_ID + + + + 10 + Unit + + + 10 + Kg + + + + + + + + 21.12.2012T00:00:00 + Sale + WAREHOUSE_1 + Output + WAREHOUSE_1 + STORE_1 + Regular Sale + + + 10 + 1% + 11 + USD + 0% + + + + + + + + + + + + + EVENT_1 + OUTPUT_BATCH_ID + OBJECT_2 + + + + 2018-01-01T00:00:00 + 2018-01-02T00:00:00 + 27 + 18 + 31 + C + + + + 2018-01-01T00:00:00 + 24 + C + + + 2018-01-01T00:00:01 + 27 + C + + + 2018-01-01T00:00:02 + 25 + C + + + 2018-01-01T00:00:03 + 26 + C + + + + TMP123 + + + + 2018-01-01T00:00:00 + 2018-01-02T00:00:00 + 50 + 35 + 75 + % + + + + 2018-01-01T01:00:00 + 55 + % + + + 2018-01-01T03:00:00 + 27 + % + + + 2018-01-01T05:00:00 + 67 + % + + + 2018-01-01T07:00:00 + 75 + % + + + + HUM123 + + + + + + +
diff --git a/importers/v1.5.py b/importers/v1.5.py new file mode 100644 index 0000000000..5efae998df --- /dev/null +++ b/importers/v1.5.py @@ -0,0 +1,907 @@ +import sys +sys.path.append('./dependencies') +from xmljson import yahoo as parser +from xml.etree.ElementTree import fromstring +from xml.etree.ElementTree import ParseError +from json import dumps, loads +import hashlib +import time +import os + +from os.path import join, dirname +from dotenv import load_dotenv + +dotenv_path = join(dirname(__file__), '..','.env') +load_dotenv(dotenv_path) + +from arango import ArangoClient + +if len(sys.argv) != 2: + print("Invalid number of arguments, required format: python xmlimporter.py import_file.xml") + sys.exit() + +# Entities +PARTICIPANTS = {} +LOCATIONS = {} +OBJECTS = {} +BATCHES = {} +TRANSACTIONS = {} +EVENTS = {} + +INPUT_BATCHES = [] +OUTPUT_BATCHES = [] +TRANSFERED_BATCHES = [] + +# Relations +OWNED_BY = [] +AT = [] +INPUT_BATCH = [] +OUTPUT_BATCH = [] +INSTANCE_OF = [] +OF_BATCH = [] +TRACED_BY = [] +FROM = [] +TO = [] + +import_id = int(time.time()) + +#Database connection + +client = ArangoClient(protocol = 'http', +host = os.environ.get("DB_HOST"), +port = os.environ.get("DB_PORT"), +username = os.environ.get("DB_USERNAME"), +password = os.environ.get("DB_PASSWORD"), +enable_logging = True) + +db = client.db(os.environ.get("DB_DATABASE")) +# client.grant_user_access(os.environ.get("DB_USERNAME"), os.environ.get("DB_DATABASE")) + +current_graphs = db.graphs() +new_graph = True + +for graph in current_graphs: + if 'origintrail_graph' in graph.values(): + ot_graph = db.graph('origintrail_graph') + new_graph = False + break + +if new_graph: + + ot_graph = db.create_graph('origintrail_graph') + + # Creating collections + ot_graph.create_vertex_collection('ot_vertices') + + ot_graph.create_edge_definition( + name='ot_edges', + from_collections=['ot_vertices'], + to_collections=['ot_vertices'] + ) + +# MD5 hashing function + +def hashed(source_string): + hash_method = hashlib.md5() + hash_method.update(source_string.encode('utf-8')) + return hash_method.hexdigest() + +# Error display function + +def error(error_message): + sys.stderr.write("ERROR: " + error_message) + sys.exit() + +# Insert new node_value + +def insert_node(collection, node_value, data_provider): + node_value['vertex_type'] = collection + node_value['data_provider'] = data_provider + nodesCollection = db.collection('ot_vertices') + + if nodesCollection.has(node_value['_key']): + doc = nodesCollection[node_value['_key']] + + if 'imports' not in doc: + doc['imports'] = [] + + doc['imports'].append(import_id) + nodesCollection.update(doc) + + else: + node_value['imports'] = [import_id] + nodesCollection.insert(dumps(node_value)) + +# Insert new edge + +def insert_edge(collection, edge_value, data_provider): + edge_value['_to'] = 'ot_vertices/' + edge_value['_to'] + edge_value['_from'] = 'ot_vertices/' + edge_value['_from'] + edge_value['data_provider'] = data_provider + edge_value['edge_type'] = collection + edgesCollection = db.collection('ot_edges') + + if edgesCollection.get(edge_value['_key']): + doc = edgesCollection[edge_value['_key']] + + if 'imports' not in doc: + doc['imports'] = [] + + doc['imports'].append(import_id) + edgesCollection.update(doc) + + else: + edge_value['imports'] = [import_id] + edgesCollection.insert(dumps(edge_value)) + +def joinTransactions(transaction, data_provider_id): + transaction_id = transaction['identifiers']['ExternalTransactionId'] + key = transaction['_key'] + + if transaction['data']['TransactionFlow'] == 'Input': + aql = "FOR e IN ot_vertices FILTER e.vertex_type == 'TRANSACTION' and e.transaction_flow == 'Output' and e.identifiers.TransactionId == '" + transaction_id + "' and e._key != '"+ key +"' RETURN e._key" + + result = db.aql.execute(aql); + + for res_key in result: + insert_edge('TRANSACTION_CONNECTION', {'_key':hashed(key + "-" + res_key), 'TransactionFlow': 'Output', '_from': key, '_to' : res_key}, data_provider_id) + insert_edge('TRANSACTION_CONNECTION', {'_key':hashed(res_key + "-" + key), 'TransactionFlow': 'Input', '_from': res_key, '_to' : key}, data_provider_id) + else: + aql = "FOR e IN ot_vertices FILTER e.vertex_type == 'TRANSACTION' and e.transaction_flow == 'Input' and e.identifiers.TransactionId == '" + transaction_id + "' and e._key != '"+ key +"' RETURN e._key" + + result = db.aql.execute(aql); + + for res_key in result: + insert_edge('TRANSACTION_CONNECTION', {'_key':hashed(key + "-" + res_key), 'TransactionFlow': 'Input', '_from': key, '_to' : res_key}, data_provider_id) + insert_edge('TRANSACTION_CONNECTION', {'_key':hashed(res_key + "-" + key), 'TransactionFlow': 'Output', '_from': res_key, '_to' : key}, data_provider_id) +# Collaboration check + +def isCollaborationConfirmed(providerId, partnerId): + return True + +# Find vertex key by id and vertex type + +def hasVertex(vertex_key): + nodesCollection = db.collection('ot_vertices') + return nodesCollection.has(vertex_key); + +# Loading XML from input file supplied in command line argument +xml_file_url = sys.argv[1] +xml_file = open(xml_file_url, "r", encoding="utf-8") +xml_data = xml_file.read() + +# Data from import file loaded as dictionary + +try: + import_data = parser.data(fromstring(xml_data)) +except ParseError: + error('Invalid XML file') + +if 'OriginTrailExport' not in import_data: + error("Missing OriginTrailExport element!") + + +# Reading file header + +OriginTrailExport_element = import_data['OriginTrailExport'] + +if 'version' not in OriginTrailExport_element: + error('Missing version number attribute for OriginTrailExport element!') + +export_version = OriginTrailExport_element['version'] + +if 'DataProvider' not in OriginTrailExport_element: + error("Missing DataProvider element!") + +DataProvider_element = OriginTrailExport_element['DataProvider'] + +if isinstance(DataProvider_element, list): + error("Multiple DataProvider elements!") + +if 'ParticipantId' not in DataProvider_element: + error('Missing ParticipantId element for DataProvider!') + +data_provider_id = DataProvider_element['ParticipantId'] + + +# Reading Master Data + +if 'MasterData' in OriginTrailExport_element: + + MasterData_element = OriginTrailExport_element['MasterData'] + + + # Reading Participants Data + + if 'ParticipantsList' in MasterData_element: + + ParticipantsList_element = MasterData_element['ParticipantsList'] + + if 'Participant' not in ParticipantsList_element: + error('Missing Participant element for ParticipantsList') + + Participant_elements = ParticipantsList_element['Participant'] + + if not isinstance(Participant_elements, list): + tmp_Participant_elements = Participant_elements + Participant_elements = [] + Participant_elements.append(tmp_Participant_elements) + + for participant_element in Participant_elements: + + if 'ParticipantIdentifiers' not in participant_element: + error('Missing ParticipantIdentifiers element for Participant!') + + ParticipantIdentifiers_element = participant_element['ParticipantIdentifiers'] + + if 'ParticipantId' not in ParticipantIdentifiers_element: + error('Missing ParticipantId for Participant!') + + participant_id = ParticipantIdentifiers_element['ParticipantId'] + + participant_uid = 'ot:' + data_provider_id + ':otpartid:' + participant_id + + if 'ParticipantData' not in participant_element: + error('Missing ParticipantData element for Participant!') + + ParticipantData_element = participant_element['ParticipantData'] + + PARTICIPANTS[participant_id] = {} + PARTICIPANTS[participant_id]['identifiers'] = ParticipantIdentifiers_element + PARTICIPANTS[participant_id]['identifiers']['uid'] = participant_uid + PARTICIPANTS[participant_id]['data'] = ParticipantData_element + PARTICIPANTS[participant_id]['_key'] = hashed('participant_' + participant_uid) + PARTICIPANTS[participant_id]['vertex_key'] = hashed('participant_' + participant_uid) + + + # Reading Business Locations Data + + if 'BusinessLocationsList' in MasterData_element: + + BusinessLocationsList_element = MasterData_element['BusinessLocationsList'] + + if 'BusinessLocation' not in BusinessLocationsList_element: + error('Missing BusinessLocation element for BusinessLocationsList!') + + BusinessLocation_elements = BusinessLocationsList_element['BusinessLocation'] + + if not isinstance(BusinessLocation_elements, list): + tmp_BusinessLocation_elements = BusinessLocation_elements + BusinessLocation_elements = [] + BusinessLocation_elements.append(tmp_BusinessLocation_elements) + + for business_location_element in BusinessLocation_elements: + + if 'BusinessLocationOwnerId' not in business_location_element: + error('Missing BusinessLocationOwnerId for BusinessLocation!'); + + business_location_owner_id = business_location_element['BusinessLocationOwnerId'] + + if business_location_owner_id in PARTICIPANTS: + business_location_owner_key = PARTICIPANTS[business_location_owner_id]['_key'] + else: + business_location_owner_key = hashed('participant_ot:' + data_provider_id + ':otpartid:' + business_location_owner_id) + + if not hasVertex(business_location_owner_key): + error('Business location owner with id ' + business_location_owner_id + ' is not provided in export nor found in database!') + + if not business_location_owner_key: + error('Business location owner with id ' + business_location_owner_id + ' not provided in export nor found in database') + + if 'BusinessLocationIdentifiers' not in business_location_element: + error('Missing BusinessLocationIdentifiers element for BusinessLocation!') + + BusinessLocationIdentifiers_element = business_location_element['BusinessLocationIdentifiers'] + + if 'BusinessLocationId' not in BusinessLocationIdentifiers_element: + error('Missing BusinessLocationId for BusinessLocation') + + business_location_id = BusinessLocationIdentifiers_element['BusinessLocationId'] + + business_location_uid = 'ot:' + data_provider_id + ':otblid:' + business_location_id + + if 'BusinessLocationData' not in business_location_element: + error('Missing BusinessLocationData element for BusinessLocation!') + + BusinessLocationData_element = business_location_element['BusinessLocationData'] + + LOCATIONS[business_location_id] = {} + LOCATIONS[business_location_id]['identifiers'] = BusinessLocationIdentifiers_element + LOCATIONS[business_location_id]['identifiers']['uid'] = business_location_uid + LOCATIONS[business_location_id]['data'] = BusinessLocationData_element + LOCATIONS[business_location_id]['_key'] = hashed('business_location_' + business_location_uid) + LOCATIONS[business_location_id]['vertex_key'] = hashed('business_location_' + business_location_uid) + + OWNED_BY.append({ + '_from': LOCATIONS[business_location_id]['_key'], + '_to': business_location_owner_key, + '_key': hashed('owned_by_' + business_location_owner_key + '_' + LOCATIONS[business_location_id]['_key']) + }) + + # Reading Objects Data + + if 'ObjectsList' in MasterData_element: + + ObjectsList_element = MasterData_element['ObjectsList'] + + if 'Object' not in ObjectsList_element: + error('Missing Object element for ObjectsList!') + + Object_elements = ObjectsList_element['Object'] + + if not isinstance(Object_elements, list): + tmp_Object_elements = Object_elements + Object_elements = [] + Object_elements.append(tmp_Object_elements) + + for object_element in Object_elements: + + if 'ObjectIdentifiers' not in object_element : + error('Missing ObjectIdentifiers element for Object!') + + ObjectIdentifiers_element = object_element['ObjectIdentifiers'] + + if 'ObjectId' not in ObjectIdentifiers_element: + error('Missing ObjectId for Object') + + object_id = ObjectIdentifiers_element['ObjectId'] + + object_uid = 'ot:' + data_provider_id + ':otoid:' + object_id + + if 'ObjectData' not in object_element: + error('Missing ObjectData element for Object!') + + ObjectData_element = object_element['ObjectData'] + + OBJECTS[object_id] = {} + OBJECTS[object_id]['identifiers'] = ObjectIdentifiers_element + OBJECTS[object_id]['identifiers']['uid'] = object_uid + OBJECTS[object_id]['data'] = ObjectData_element + OBJECTS[object_id]['_key'] = hashed('object_' + object_uid) + OBJECTS[object_id]['vertex_key'] = hashed('object_' + object_uid) + + # Reading Objects Data + + if 'BatchesList' in MasterData_element: + + BatchesList_element = MasterData_element['BatchesList'] + + if 'Batch' not in BatchesList_element: + error('Missing Batch element for BatchesList!') + + Batch_elements = BatchesList_element['Batch'] + + if not isinstance(Batch_elements, list): + tmp_Batch_elements = Batch_elements + Batch_elements = [] + Batch_elements.append(tmp_Batch_elements) + + for batch_element in Batch_elements: + + if 'BatchIdentifiers' not in batch_element: + error('Missing BatchIdentifiers element for Batch!') + + BatchIdentifiers_element = batch_element['BatchIdentifiers'] + + if 'BatchId' not in BatchIdentifiers_element: + error('Missing BatchId for Batch') + + batch_id = BatchIdentifiers_element['BatchId'] + + if 'ObjectId' not in ObjectIdentifiers_element: + error('Missing ObjectId for Batch') + + object_id = BatchIdentifiers_element['ObjectId'] + + if object_id in OBJECTS: + object_key = OBJECTS[object_id]['_key'] + else: + object_key = hashed('object_ot:' + data_provider_id + ':otoid:' + object_id) + + if not hasVertex(object_key): + error('Object with id ' + object_id + ' is not provided in export nor found in database!') + + batch_uid = 'ot:' + data_provider_id + ':otbid:' + batch_id + + if 'BatchData' not in batch_element: + error('Missing BatchData element for Object!') + + BatchData_element = batch_element['BatchData'] + + BATCHES[batch_uid] = {} + BATCHES[batch_uid]['identifiers'] = BatchIdentifiers_element + BATCHES[batch_uid]['identifiers']['uid'] = batch_uid + BATCHES[batch_uid]['data'] = BatchData_element + BATCHES[batch_uid]['_key'] = hashed('batch_' + batch_uid) + BATCHES[batch_uid]['vertex_key'] = hashed('batch_' + batch_uid) + + INSTANCE_OF.append({ + '_from': BATCHES[batch_uid]['vertex_key'], + '_to': object_key, + '_key': hashed('instance_of_' + BATCHES[batch_uid]['vertex_key'] + '_' + object_key) + }) + + + +# Reading Transactions Data + +if 'TransactionData' in OriginTrailExport_element: + + TransactionsData_element = OriginTrailExport_element['TransactionData'] + + # Reading internal transactions data + + if 'InternalTransactionsList' in TransactionsData_element: + + InternalTransactionsList_element = TransactionsData_element['InternalTransactionsList'] + + if 'InternalTransaction' not in InternalTransactionsList_element: + error('Missing InternalTransaction element for InternalTransactionsList!') + + InternalTransaction_elements = InternalTransactionsList_element['InternalTransaction'] + + if not isinstance(InternalTransaction_elements, list): + tmp_InternalTransaction_elements = InternalTransaction_elements + InternalTransaction_elements = [] + InternalTransaction_elements.append(tmp_InternalTransaction_elements) + + for internal_transaction_element in InternalTransaction_elements: + + if 'InternalTransactionIdentifiers' not in internal_transaction_element : + error('Missing InternalTransactionIdentifiers element for InternalTransaction!') + + InternalTransactionIdentifiers_element = internal_transaction_element['InternalTransactionIdentifiers'] + + if 'InternalTransactionId' not in InternalTransactionIdentifiers_element: + error('Missing InternalTransactionId for InternalTransaction!') + + internal_transaction_id = InternalTransactionIdentifiers_element['InternalTransactionId'] + + internal_transaction_uid = 'ot:' + data_provider_id + ':ottid:' + internal_transaction_id + + if 'TransactionBatchesInformation' not in internal_transaction_element: + error('Missing TransactionBatchesInformation element for InternalTransaction!') + + BatchesInformation_element = internal_transaction_element['TransactionBatchesInformation'] + + # Reading input batches for internal transaction + + if 'InputBatchesList' in BatchesInformation_element: + + InputBatchesList_element = BatchesInformation_element['InputBatchesList'] + + if 'TransactionBatch' not in InputBatchesList_element: + error('Missing TransactionBatch element for InputBatchesList!') + + Batch_elements = InputBatchesList_element['TransactionBatch'] + + if not isinstance(Batch_elements, list): + tmp_Batch_elements = Batch_elements + Batch_elements = [] + Batch_elements.append(tmp_Batch_elements) + + INPUT_BATCHES = [] + + for batch_element in Batch_elements: + + if 'TransactionBatchId' not in batch_element: + error('Missing TransactionBatchId for Batch!') + + batch_id = batch_element['TransactionBatchId'] + + batch_uid = 'ot:' + data_provider_id + ':otbid:' + batch_id + + if batch_uid in BATCHES: + batch_key = BATCHES[batch_uid]['_key'] + else: + batch_key = hashed('batch_' + batch_uid) + + if not hasVertex(object_key): + error('Batch with id ' + batch_id + ' is not provided in export nor found in database!') + + if 'TransactionBatchData' not in batch_element: + error('Missing TransactionBatchData element for Batch!') + + INPUT_BATCHES.append(batch_key); + + # Reading output units for internal transaction + + if 'OutputBatchesList' not in BatchesInformation_element: + error('Missing OutputBatchesList for TransactionBatchesInformation') + + OutputBatchesList_element = BatchesInformation_element['OutputBatchesList'] + + if 'TransactionBatch' not in OutputBatchesList_element: + error('Missing TransactionBatch element for OutputBatchesList!') + + Batch_elements = OutputBatchesList_element['TransactionBatch'] + + if not isinstance(Batch_elements, list): + tmp_Batch_elements = Batch_elements + Batch_elements = [] + Batch_elements.append(tmp_Batch_elements) + + OUTPUT_BATCHES = [] + + for batch_element in Batch_elements: + + if 'TransactionBatchId' not in batch_element: + error('Missing BatchId for Batch!') + + batch_id = batch_element['TransactionBatchId'] + + batch_uid = 'ot:' + data_provider_id + ':otbid:' + batch_id + + if batch_uid in BATCHES: + batch_key = BATCHES[batch_uid]['_key'] + else: + batch_key = hashed('batch_' + batch_uid) + + if not hasVertex(object_key): + error('Batch with id ' + batch_id + ' is not provided in export nor found in database!') + + if 'TransactionBatchData' not in batch_element: + error('Missing TransactionBatchData element for Batch!') + + BatchData_element = batch_element['TransactionBatchData'] + + OUTPUT_BATCHES.append(batch_key); + + if 'InternalTransactionData' not in internal_transaction_element: + error('Missing InternalTransactionData element for InternalTransaction!') + + InternalTransactionData_element = internal_transaction_element['InternalTransactionData'] + + if 'BusinessLocationId' not in InternalTransactionData_element: + error('Missing BusinessLocationId for Internal Transaction!') + + business_location_id = InternalTransactionData_element['BusinessLocationId'] + + if business_location_id in LOCATIONS: + business_location_key = LOCATIONS[business_location_id]['_key'] + else: + business_location_key = hashed('business_location_ot:' + data_provider_id + ':otblid:' + business_location_id) + + if not hasVertex(business_location_key): + error('Business location with id ' + business_location_id + ' is not provided in export nor found in database!') + + + TRANSACTIONS[internal_transaction_id] = {} + TRANSACTIONS[internal_transaction_id]['identifiers'] = InternalTransactionIdentifiers_element + TRANSACTIONS[internal_transaction_id]['identifiers']['uid'] = internal_transaction_uid + TRANSACTIONS[internal_transaction_id]['identifiers']['TransactionId'] = internal_transaction_id + TRANSACTIONS[internal_transaction_id]['data'] = InternalTransactionData_element + TRANSACTIONS[internal_transaction_id]['data']['BatchesInformation'] = BatchesInformation_element + TRANSACTIONS[internal_transaction_id]['TransactionType'] = 'InternalTransaction' + TRANSACTIONS[internal_transaction_id]['_key'] = hashed('transaction_' + internal_transaction_uid) + TRANSACTIONS[internal_transaction_id]['vertex_key'] = hashed('transaction_' + internal_transaction_uid) + + AT.append({ + '_from': TRANSACTIONS[internal_transaction_id]['_key'], + '_to': business_location_key, + '_key': hashed('at_' + TRANSACTIONS[internal_transaction_id]['_key'] + '_' + business_location_key) + }) + + for input_batch in INPUT_BATCHES: + INPUT_BATCH.append({ + '_from': TRANSACTIONS[internal_transaction_id]['_key'], + '_to': input_batch, + '_key': hashed('input_batch_' + TRANSACTIONS[internal_transaction_id]['_key'] + '_' + input_batch) + }) + + for output_batch in OUTPUT_BATCHES: + OUTPUT_BATCH.append({ + '_from': output_batch, + '_to': TRANSACTIONS[internal_transaction_id]['_key'], + '_key': hashed('output_batch_' + TRANSACTIONS[internal_transaction_id]['_key'] + '_' + output_batch) + }) + + # Reading external transactions data + + if 'ExternalTransactionsList' in TransactionsData_element: + + ExternalTransactionsList_element = TransactionsData_element['ExternalTransactionsList'] + + if 'ExternalTransaction' not in ExternalTransactionsList_element: + error('Missing ExternalTransaction element for ExternalTransactionsList!') + + ExternalTransaction_elements = ExternalTransactionsList_element['ExternalTransaction'] + + if not isinstance(ExternalTransaction_elements, list): + tmp_ExternalTransaction_elements = ExternalTransaction_elements + ExternalTransaction_elements = [] + ExternalTransaction_elements.append(tmp_ExternalTransaction_elements) + + for external_transaction_element in ExternalTransaction_elements: + + if 'ExternalTransactionIdentifiers' not in external_transaction_element : + error('Missing ExternalTransactionIdentifiers element for ExternalTransaction!') + + ExternalTransactionIdentifiers_element = external_transaction_element['ExternalTransactionIdentifiers'] + + if 'ExternalTransactionId' not in ExternalTransactionIdentifiers_element: + error('Missing ExternalTransactionId for ExternalTransaction!') + + external_transaction_id = ExternalTransactionIdentifiers_element['ExternalTransactionId'] + + external_transaction_uid = 'ot:' + data_provider_id + ':ottid:' + external_transaction_id + + if 'TransactionBatchesInformation' not in external_transaction_element: + error('Missing TransactionBatchesInformation element for ExternalTransaction!') + + BatchesInformation_element = external_transaction_element['TransactionBatchesInformation'] + + # Reading batches for external transaction + + if 'TransactionBatchesList' not in BatchesInformation_element: + error('Missing TransactionBatchesList for ExternalTransaction!') + + BatchesList_element = BatchesInformation_element['TransactionBatchesList'] + + if 'TransactionBatch' not in BatchesList_element: + error('Missing TransactionBatch element for TransactionBatchesList!') + + Batch_elements = BatchesList_element['TransactionBatch'] + + if not isinstance(Batch_elements, list): + tmp_Batch_elements = Batch_elements + Batch_elements = [] + Batch_elements.append(tmp_Batch_elements) + + TRANSFERED_BATCHES = [] + + for batch_element in Batch_elements: + + if 'TransactionBatchId' not in batch_element: + error('Missing BatchId for Batch!') + + batch_id = batch_element['TransactionBatchId'] + + batch_uid = 'ot:' + data_provider_id + ':otbid:' + batch_id + + if batch_uid in BATCHES: + batch_key = BATCHES[batch_uid]['_key'] + else: + batch_key = hashed('batch_' + batch_uid) + + if not hasVertex(object_key): + error('Batch with id ' + batch_id + ' is not provided in export nor found in database!') + + if 'TransactionBatchData' not in batch_element: + error('Missing TransactionBatchData element for Batch!') + + TRANSFERED_BATCHES.append(batch_key); + + if 'ExternalTransactionData' not in external_transaction_element: + error('Missing ExternalTransactionData element for ExternalTransaction!') + + ExternalTransactionData_element = external_transaction_element['ExternalTransactionData'] + + if 'BusinessLocationId' not in ExternalTransactionData_element: + error('Missing BusinessLocationId for External Transaction!') + + business_location_id = ExternalTransactionData_element['BusinessLocationId'] + + if business_location_id in LOCATIONS: + business_location_key = LOCATIONS[business_location_id]['_key'] + else: + business_location_key = hashed('object_ot:' + data_provider_id + ':otoid:' + business_location_id) + + if not hasVertex(business_location_key): + error('Business location with id ' + business_location_id + ' is not provided in export nor found in database!') + + if 'BusinessLocationId' not in ExternalTransactionData_element: + error('Missing BusinessLocationId for External Transaction!') + + source_business_location_id = ExternalTransactionData_element['SourceBusinessLocationId'] + + if source_business_location_id in LOCATIONS: + source_business_location_key = LOCATIONS[source_business_location_id]['_key'] + else: + source_business_location_key = hashed('object_ot:' + data_provider_id + ':otoid:' + source_business_location_id) + + if not hasVertex(source_business_location_key): + error('Business location with id ' + source_business_location_id + ' is not provided in export nor found in database!') + + dest_business_location_id = ExternalTransactionData_element['DestinationBusinessLocationId'] + + if dest_business_location_id in LOCATIONS: + dest_business_location_key = LOCATIONS[dest_business_location_id]['_key'] + else: + dest_business_location_key = hashed('object_ot:' + data_provider_id + ':otoid:' + dest_business_location_id) + + if not hasVertex(dest_business_location_key): + error('Business location with id ' + dest_business_location_id + ' is not provided in export nor found in database!') + + if 'TransactionFlow' not in ExternalTransactionData_element: + error('Missing TransactionFlow element for ExternalTransaction!') + + transaction_flow = ExternalTransactionData_element['TransactionFlow'] + + if not (transaction_flow == 'Input' or transaction_flow == 'Output'): + error('Invalid value for TransactionFlow element!') + + TRANSACTIONS[external_transaction_id] = {} + TRANSACTIONS[external_transaction_id]['identifiers'] = ExternalTransactionIdentifiers_element + TRANSACTIONS[external_transaction_id]['identifiers']['uid'] = external_transaction_uid + TRANSACTIONS[external_transaction_id]['identifiers']['TransactionId'] = external_transaction_id + TRANSACTIONS[external_transaction_id]['transaction_flow'] = transaction_flow + TRANSACTIONS[external_transaction_id]['data'] = ExternalTransactionData_element + TRANSACTIONS[external_transaction_id]['data']['BatchesInformation'] = BatchesInformation_element + TRANSACTIONS[external_transaction_id]['TransactionType'] = 'ExternalTransaction' + TRANSACTIONS[external_transaction_id]['_key'] = hashed('transaction_' + external_transaction_uid) + TRANSACTIONS[external_transaction_id]['vertex_key'] = hashed('transaction_' + external_transaction_uid) + + + AT.append({ + '_from': TRANSACTIONS[external_transaction_id]['_key'], + '_to': business_location_key, + '_key': hashed('at_' + TRANSACTIONS[external_transaction_id]['_key'] + '_' + business_location_key) + }) + + FROM.append({ + '_from': TRANSACTIONS[external_transaction_id]['_key'], + '_to': source_business_location_key, + '_key': hashed('from_' + TRANSACTIONS[external_transaction_id]['_key'] + '_' + source_business_location_key) + }) + + TO.append({ + '_from': TRANSACTIONS[external_transaction_id]['_key'], + '_to': dest_business_location_key, + '_key': hashed('to_' + TRANSACTIONS[external_transaction_id]['_key'] + '_' + dest_business_location_key) + }) + + for transfered_batch in TRANSFERED_BATCHES: + OF_BATCH.append({ + '_from': transfered_batch, + '_to': TRANSACTIONS[external_transaction_id]['_key'], + '_key': hashed('of_batch_' + TRANSACTIONS[external_transaction_id]['_key'] + '_' + transfered_batch) + }) + + OF_BATCH.append({ + '_from': TRANSACTIONS[external_transaction_id]['_key'], + '_to': transfered_batch, + '_key': hashed('of_batch_' + transfered_batch + '_' + TRANSACTIONS[external_transaction_id]['_key']) + }) + +# Reading Visibility Events data Data + +if 'VisibilityEventData' in OriginTrailExport_element: + + VisibilityEventData_element = OriginTrailExport_element['VisibilityEventData'] + + + + if 'VisibilityEventsList' in VisibilityEventData_element: + + VisibilityEventsList_element = VisibilityEventData_element['VisibilityEventsList'] + + if 'Event' not in VisibilityEventsList_element: + error('Missing Event element for VisibilityEventsList') + + Event_elements = VisibilityEventsList_element['Event'] + + if not isinstance(Event_elements, list): + tmp_Event_elements = Event_elements + Event_elements = [] + Event_elements.append(tmp_Event_elements) + + for event_element in Event_elements: + + if 'EventIdentifiers' not in event_element: + error('Missing EventIdentifiers element for Event!') + + EventIdentifiers_element = event_element['EventIdentifiers'] + + if 'EventId' not in EventIdentifiers_element: + error('Missing EventId for Event!') + + event_id = EventIdentifiers_element['EventId'] + + event_uid = 'ot:' + data_provider_id + ':oteid:' + event_id + + if 'BatchId' not in EventIdentifiers_element: + error('Missing BatchId for Event!') + + batch_id = EventIdentifiers_element['BatchId'] + batch_uid = 'ot:' + data_provider_id + ':otbid:' + batch_id + + if batch_uid in BATCHES: + batch_key = BATCHES[batch_uid]['_key'] + else: + + batch_key = hashed('batch_' + batch_uid) + + if not hasVertex(batch_key): + error('Batch with id ' + batch_id + ' is not provided in export nor found in database!') + + if 'EventData' not in event_element: + error('Missing EventData element for Event!') + + EventData_element = event_element['EventData'] + + EVENTS[event_id] = {} + EVENTS[event_id]['identifiers'] = EventIdentifiers_element + EVENTS[event_id]['identifiers']['uid'] = event_uid + EVENTS[event_id]['data'] = EventData_element + EVENTS[event_id]['_key'] = hashed('event_' + event_uid) + EVENTS[event_id]['vertex_key'] = hashed('event_' + event_uid) + + TRACED_BY.append({ + '_from': batch_key, + '_to': EVENTS[event_id]['vertex_key'], + '_key': hashed('traced_by_' + batch_key + '_' + EVENTS[event_id]['vertex_key']) + }) + + +# Importing parsed data into graph database + +VERTICES = [] +EDGES = [] + +for key, participant_vertex in PARTICIPANTS.items(): + VERTICES.append(participant_vertex) + insert_node('PARTICIPANT', participant_vertex, data_provider_id) + +for key, location_vertex in LOCATIONS.items(): + VERTICES.append(location_vertex) + insert_node('BUSINESS_LOCATION', location_vertex, data_provider_id) + +for key, object_vertex in OBJECTS.items(): + VERTICES.append(object_vertex) + insert_node('OBJECT', object_vertex, data_provider_id) + +for key, batch_vertex in BATCHES.items(): + VERTICES.append(batch_vertex) + insert_node('BATCH', batch_vertex, data_provider_id) + +for key, transaction_vertex in TRANSACTIONS.items(): + VERTICES.append(transaction_vertex) + insert_node('TRANSACTION', transaction_vertex, data_provider_id) + +for key, event_vertex in EVENTS.items(): + VERTICES.append(event_vertex) + insert_node('VISIBILITY_EVENT', event_vertex, data_provider_id) + +for owned_by_relation in OWNED_BY: + EDGES.append(owned_by_relation) + insert_edge('OWNED_BY', owned_by_relation, data_provider_id) + +for at_relation in AT: + EDGES.append(at_relation) + insert_edge('AT', at_relation, data_provider_id) + +for input_batch_relation in INPUT_BATCH: + EDGES.append(input_batch_relation) + insert_edge('INPUT_BATCH', input_batch_relation, data_provider_id) + +for output_batch_relation in OUTPUT_BATCH: + EDGES.append(output_batch_relation) + insert_edge('OUTPUT_BATCH', output_batch_relation, data_provider_id) + +for instance_of_relation in INSTANCE_OF: + EDGES.append(instance_of_relation) + insert_edge('INSTANCE_OF', instance_of_relation, data_provider_id) + +for of_batch_relation in OF_BATCH: + EDGES.append(of_batch_relation) + insert_edge('OF_BATCH', of_batch_relation, data_provider_id) + +for sent_from_relation in FROM: + EDGES.append(sent_from_relation) + insert_edge('FROM', sent_from_relation, data_provider_id) + +for sent_to_relation in TO: + EDGES.append(sent_to_relation) + insert_edge('TO', sent_to_relation, data_provider_id) + +for traced_by_relation in TRACED_BY: + EDGES.append(traced_by_relation) + insert_edge('TRACED_BY', traced_by_relation, data_provider_id) + +print(dumps({"message": "Data import complete!", "vertices": VERTICES, "edges": EDGES, "import_id": import_id})) +sys.stdout.flush() + +for key, transaction in TRANSACTIONS.items(): + if 'TransactionFlow' in transaction['data']: + joinTransactions(transaction, data_provider_id) diff --git a/install-aws.sh b/install-aws.sh index ba6f3f534e..08e1e4c4de 100644 --- a/install-aws.sh +++ b/install-aws.sh @@ -24,7 +24,7 @@ pip3 install --user python-dotenv sudo yum install patch cd ~ -git clone https://github.com/OriginTrail/ot-node.git +git clone -b master https://github.com/OriginTrail/ot-node.git cd ot-node && npm install cp .env.example .env diff --git a/install.sh b/install.sh index 7daf06a15b..9942ab1354 100644 --- a/install.sh +++ b/install.sh @@ -8,6 +8,15 @@ sudo apt-add-repository 'deb https://www.arangodb.com/repositories/arangodb3/xUb sudo apt-get update -y sudo apt-get install arangodb3 +sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927 +echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list +sudo apt-get update +sudo apt-get install -y mongodb-org +sudo systemctl start mongod +sudo systemctl enable mongod + +export LC_ALL=C + sudo apt-get install -y python3-pip sudo pip3 install python-arango @@ -16,8 +25,8 @@ sudo pip3 install python-dotenv sudo apt-get install git -git clone https://github.com/OriginTrail/ot-node.git +git clone -b master https://github.com/OriginTrail/ot-node.git cd ot-node cp .env.example .env -npm install \ No newline at end of file +npm install diff --git a/ipc.js b/ipc.js index 477d14f8a3..a995466919 100644 --- a/ipc.js +++ b/ipc.js @@ -5,7 +5,7 @@ const socket_com = require('./modules/sockets')(); const importer = require('./modules/importer')(); const utilities = require('./modules/utilities')(); const config = utilities.getConfig(); - +const log = utilities.getLogger(); // Node server configuration // ========================= const server = restify.createServer({ @@ -79,5 +79,5 @@ server.post('/import', function (req, res) { socket_com.start(); server.listen(parseInt(config.IPC_API_PORT), 'localhost', function () { - console.log('%s listening at %s', server.name, server.url); + log.info('%s listening at %s', server.name, server.url); }); diff --git a/modules/DataReplication.js b/modules/DataReplication.js new file mode 100644 index 0000000000..52e8ad9a2e --- /dev/null +++ b/modules/DataReplication.js @@ -0,0 +1,76 @@ +const axios = require('axios'); +const graph = require('./graph')(); +const testing = require('./testing')(); +const holding = require('./holding')(); +const utilities = require('./utilities')(); +const signing = require('./blockchain_interface/ethereum/signing')(); +const log = utilities.getLogger(); +const config = utilities.getConfig(); + + +class DataReplication { + + /** + * Sends data to DH for replication + * + * @param data object {VERTICES, EDGES, IMPORT_ID} This is the payload to be sent + * @return object response + */ + sendPayload(data, callback) { + log.info('Entering sendPayload'); + + var currentUnixTime = Math.floor(new Date() / 1000); + var min10 = currentUnixTime + 120 + 60; // End of testing period + let options_signing = { + dh_wallet: config.DH_WALLET, + import_id: data.data_id, + amount: data.vertices.length + data.edges.length, + start_time: currentUnixTime + 120, + total_time: 60 + }; + signing.signAndAllow(options_signing).then(response => { + graph.encryptVertices(config.DH_NODE_IP, config.DH_NODE_PORT, data.vertices, encryptedVertices => { + + + testing.generateTests(data.data_id, config.DH_NODE_IP, config.DH_NODE_PORT, config.blockchain.settings.ethereum.wallet_address, encryptedVertices.vertices, 10, currentUnixTime + 120, min10, (res, err) => { + log.info('[DC] Tests generated'); + }); + const payload = JSON.stringify({ + vertices: encryptedVertices.vertices, + public_key: encryptedVertices.public_key, + edges: data.edges, + data_id: data.data_id, + dc_wallet: config.blockchain.settings.ethereum.wallet_address + }); + const options = { + method: 'POST', + url: 'http://' + config.DH_NODE_IP + ':' + config.DH_NODE_PORT + '/api/replication', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': payload.length + }, + data: payload + }; + try { + axios(options).then(result => { + log.info('Payload sent'); + holding.addHoldingData(config.DH_WALLET, data.data_id, payload.public_key, () => { + log.info('[DH] Holding data saved into database'); + }); + utilities.executeCallback(callback, result.data); + }).catch(err => { + console.error(err); + }); + + } catch(e) { + log.error('Payload not sent'); + console.error('DH connection failed'); + } + }); + }); + + } + +} + +module.exports = new DataReplication; \ No newline at end of file diff --git a/modules/EventHandlers.js b/modules/EventHandlers.js new file mode 100644 index 0000000000..9bd65660b3 --- /dev/null +++ b/modules/EventHandlers.js @@ -0,0 +1,99 @@ +const product = require('./product')(); +const importer = require('./importer')(); +const blockchain = require('./blockchain')(); +const testing = require('./testing')(); +const signing = require('./blockchain_interface/ethereum/signing')(); +const utilities = require('./utilities')(); +const log = utilities.getLogger(); +const config = utilities.getConfig(); + +class EventHandlers { + + constructor(data, socket) { + //kebab-case to snakeCase + this.event = data.request.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); + + //get the first part of some-response => some + this.eventPrefix = data.request.split(/-(.+)/)[0]; + + this.queryObject = data.queryObject; + this.clientRequest = data.clientRequest; + + try { + this[this.event](socket); + } catch(err) { + socket.emit('event', { + response: 'Unsupported event' + }); + } + } + + emitResponse(socket, response) { + socket.emit('event', { + response: this.eventPrefix + '-response', + responseData: response, + clientRequest: this.clientRequest + }); + } + + trailRequest(socket){ + product.getTrailByQuery(this.queryObject, (response) => { + this.emitResponse(socket, response); + }); + } + + importRequest(socket) { + importer.importXML(this.queryObject.filepath, (response) => { + this.emitResponse(socket, response); + }); + } + + blockchainRequest(socket) { + let batch_uid_hash = utilities.sha3(this.queryObject.batch_uid); + blockchain.getFingerprint(this.queryObject.owner, batch_uid_hash, (response) => { + this.emitResponse(socket, response); + + }); + } + + expirationRequest(socket) { + product.getExpirationDates(this.queryObject, (response) => { + this.emitResponse(socket, response); + }); + } + + replicationRequest(socket) { + importer.importJSON(this.queryObject, () => { + log.info('[DH] JSON imported'); + this.emitResponse(socket, { + status: 'success', + code: 200, + data: [] + }); + }); + } + + testingRequest(socket) { + log.info('[DH] Event emitted: Testing Request Response'); + //log.warn(this.queryObject); + testing.answerQuestion(this.queryObject, (answer) => { + this.emitResponse(socket, { + answer: answer, + wallet: config.blockchain.settings.ethereum.wallet_address, + ip: config.NODE_IP, + port: config.RPC_API_PORT + }); + }); + + } + + receiptRequest(socket) { + signing.sendConfirmation(this.queryObject, (response) => { + log.info('[DH] Event emitted: Receipt Request Response'); + this.emitResponse(socket, []); + }); + + } +} + +module.exports = EventHandlers; diff --git a/modules/SendTest.js b/modules/SendTest.js new file mode 100644 index 0000000000..dd09fe7bfb --- /dev/null +++ b/modules/SendTest.js @@ -0,0 +1,157 @@ +const testTable = require('./test_table')(); +const signing = require('./blockchain_interface/ethereum/signing.js')(); +const axios = require('axios'); +const holding = require('./holding')(); +const utilities = require('./utilities')(); +const config = utilities.getConfig(); +const log = utilities.getLogger(); + +class SendTests { + + /** + * Start the test sequence + * + */ + startTests() { + log.info('Starting tests'); + return setInterval(() => { + this.checkTests(); + }, 45000); + } + + /** + * End the test sequence + * + */ + endTests(test) { + clearInterval(test); + } + /** + * Check if there is a new test to be sent + * + */ + checkTests() { + log.info('Checking if there are tests to send'); + testTable.getTests((test) => { + if(test.length === 0) return; + test = test[0]; + let currentUnixTime = Math.floor(new Date() / 1000); + + if (currentUnixTime > test.test_time) { + + this.sendTest(test.dh_ip, test.dh_port, test.question, answer => { + log.info('Test sent:'); + //log.info(test); + this.verifyResult(test, answer.data); + }); + + } else { + log.info('Next test time: ' + test.test_time); + log.info('Current time: ' + currentUnixTime); + } + + }); + } + + /** + * Sends test to Data Holder + * + * @param ip string DH IP address + * @param port string DH port + * @param question object + * @returns {Promise.data} object data.answer + */ + sendTest(ip, port, question, callback) { + log.info('Entering sendTest'); + question = JSON.stringify({ + question: question + }); + // log.info('Question to send'); + // log.info(question); + let testQuestion = utilities.copyObject(question); + delete testQuestion.answer; + + const options = { + method: 'POST', + url: 'http://' + ip + ':' + port + '/api/testing', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': question.length + }, + data: question + }; + + axios(options).then(result => { + utilities.executeCallback(callback, result); + }).catch(err => { + console.error(err); + }); + } + + /** + * Verify if the test result is correct and sends the receipt + * + * @param test + * @param answer + */ + verifyResult(test, answer) { + log.info('Entering verifyResult'); + // log.error(test.answer); + // log.warn(answer); + var receipt; + if(test.answer === answer.answer) { + log.info('Answer is good'); + holding.getHoldingData(config.DH_WALLET, test.data_id, (holdingData) => { + receipt = signing.createConfirmation(config.DH_WALLET, test.data_id, holdingData.confirmation_number, test.test_time, true); + this.sendReceipt(answer.ip, answer.port, receipt).then(result => { + log.info('Receipt sent. Result:'); + testTable.popNextTest(() => { + log.info("Test deleted from database"); + }); + }).catch(err => { + console.error('DH connection failed'); + }); + + }); + + + } else { + log.warn('Answer not good'); + + holding.getHoldingData(answer.wallet, test.data_id, (holdingData) => { + receipt = signing.createConfirmation(answer.wallet, test.data_id, holdingData.confirmation_number, test.test_time, false); + holding.increaseConfirmationVerificationNumber(answer.wallet, test.data_id, response => { + this.sendReceipt(answer.ip, answer.port, receipt).then(result => { + log.info('Receipt sent. Result:'); + testTable.popNextTest(() => { + log.info("Test deleted from database"); + }); + }).catch(err => { + console.error(err); + }); + }); + }); + } + } + + + async sendReceipt(ip, port, receipt) { + log.info('Sending receipt...'); + + // log.info(receipt); + const options = { + method: 'POST', + url: 'http://' + ip + ':' + port + '/api/receipt', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': receipt.length + }, + data: receipt + }; + + let result = await axios(options); + return result; + } +} + +(new SendTests).startTests(); \ No newline at end of file diff --git a/modules/blockchain.js b/modules/blockchain.js index a26591b4cb..39ae9c56d7 100644 --- a/modules/blockchain.js +++ b/modules/blockchain.js @@ -1,9 +1,10 @@ // External modules var utilities = require('./utilities')(); +const log = utilities.getLogger(); var config = utilities.getConfig(); var chain = config.blockchain.preferred_chain; var chainInterface = null; -//console.log(chain); +//log.info(chain); switch (chain) { case 'ethereum': @@ -13,7 +14,7 @@ case 'neo': break; default: chainInterface = null; - console.log('ERROR: Couldn\'t load blockchain interaface, please check your config file.'); + log.info('ERROR: Couldn\'t load blockchain interaface, please check your config file.'); } module.exports = function () { @@ -21,12 +22,12 @@ module.exports = function () { var blockchain = { addFingerprint: function (batch_uid, batch_uid_hash, trail_hash) { - console.log('Writing on blockchain...'); - console.log(batch_uid); - console.log(batch_uid_hash); - console.log(trail_hash); + log.info('Writing on blockchain...'); + log.info(batch_uid); + log.info(batch_uid_hash); + log.info(trail_hash); - console.log(); + log.info(); chainInterface.addFingerprint(batch_uid, batch_uid_hash, trail_hash); }, diff --git a/modules/blockchain_interface/ethereum/contracts/escrow_abi.js b/modules/blockchain_interface/ethereum/contracts/escrow_abi.js new file mode 100644 index 0000000000..37dde748ea --- /dev/null +++ b/modules/blockchain_interface/ethereum/contracts/escrow_abi.js @@ -0,0 +1,168 @@ +[ + { + "constant": true, + "inputs": [], + "name": "token", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "escrow", + "outputs": [ + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "tokens_sent", + "type": "uint256" + }, + { + "name": "verification_number", + "type": "uint256" + }, + { + "name": "last_confirmation_time", + "type": "uint256" + }, + { + "name": "end_time", + "type": "uint256" + }, + { + "name": "total_time", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "token_amount", + "type": "uint256" + }, + { + "name": "start_time", + "type": "uint256" + }, + { + "name": "total_time", + "type": "uint256" + } + ], + "name": "initiateEscrow", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "DC_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + }, + { + "name": "confirmation_verification_number", + "type": "uint256" + }, + { + "name": "confirmation_time", + "type": "uint256" + }, + { + "name": "confirmation_valid", + "type": "bool" + }, + { + "name": "confirmation_hash", + "type": "bytes32" + }, + { + "name": "v", + "type": "uint8" + }, + { + "name": "r", + "type": "bytes32" + }, + { + "name": "s", + "type": "bytes32" + } + ], + "name": "payOut", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "DH_wallet", + "type": "address" + }, + { + "name": "data_id", + "type": "uint256" + } + ], + "name": "refund", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "name": "tokenAddress", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + } +] \ No newline at end of file diff --git a/modules/blockchain_interface/ethereum/contracts/token_abi.js b/modules/blockchain_interface/ethereum/contracts/token_abi.js new file mode 100644 index 0000000000..5d9be0a120 --- /dev/null +++ b/modules/blockchain_interface/ethereum/contracts/token_abi.js @@ -0,0 +1,475 @@ +[ + { + "constant": true, + "inputs": [], + "name": "mintingFinished", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "from", + "type": "address" + }, + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "contributor", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "wallet", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "startTime", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "finishMinting", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "teamAndFoundersWallet", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "advisorsAndPreICO", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "TOTAL_NUM_TOKENS", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "remaining", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "name": "_wallet", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "transferIsAllowed", + "type": "bool" + } + ], + "name": "TransferAllowed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "MintFinished", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + } +] diff --git a/modules/blockchain_interface/ethereum/interface.js b/modules/blockchain_interface/ethereum/interface.js index 969c17cb0a..9b707c1813 100644 --- a/modules/blockchain_interface/ethereum/interface.js +++ b/modules/blockchain_interface/ethereum/interface.js @@ -1,6 +1,7 @@ var fs = require('fs'); var Web3 = require('web3'); var utilities = require('../../utilities')(); +const log = utilities.getLogger(); var signing = require('./signing')(); config = utilities.getConfig(); @@ -8,29 +9,54 @@ config = utilities.getConfig(); module.exports = function() { web3 = new Web3(new Web3.providers.HttpProvider(config.blockchain.settings.ethereum.rpc_node + ":" + config.blockchain.settings.ethereum.node_port)); + + var contract_address = config.blockchain.settings.ethereum.contract_address; + var token_address = config.blockchain.settings.ethereum.token_contract; + var escrow_address = config.blockchain.settings.ethereum.escrow_contract; + var contract_abi_path = config.blockchain.settings.ethereum.contract_abi; var contract_abi_file = fs.readFileSync(contract_abi_path); var contract_abi = JSON.parse(contract_abi_file); - var ot_contract = web3.eth.contract(contract_abi); + var token_abi_path = config.blockchain.settings.ethereum.token_abi; + var token_abi_file = fs.readFileSync(token_abi_path); + var token_abi = JSON.parse(token_abi_file); + + var escrow_abi_path = config.blockchain.settings.ethereum.escrow_abi; + var escrow_abi_file = fs.readFileSync(escrow_abi_path); + var escrow_abi = JSON.parse(escrow_abi_file); - var contract_instance = ot_contract.at(config.blockchain.settings.ethereum.contract_address); + var ot_contract = new web3.eth.Contract(contract_abi, contract_address); + var token_contract = new web3.eth.Contract(token_abi, token_address); + var escrow_contract = new web3.eth.Contract(escrow_abi, escrow_address); var interface = { - getFingerprintByBatchHash: function(address, batch_id_hash) { - return contract_instance.getFingerprintByBatchHash(address, batch_id_hash, { + + giveAllowance: function(ammount, callback) { + signing.signAndAllow(ammount, callback) + return true; + }, + + createEscrow: function(DC_wallet, DH_wallet, data_id, token_amount, start_time, total_time, callback) { + signing.createEscrow(DC_wallet, DH_wallet, data_id, token_amount, start_time, total_time, callback) + return true; + }, + + + getFingerprintByBatchHash: function(address, data_id_hash) { + return contract_instance.getFingerprintByBatchHash(address, data_id_hash, { from: web3.eth.accounts[0] }); }, - addFingerprint: function(batch_id, batch_id_hash, graph_hash) { - signing.signAndSend(batch_id, batch_id_hash, graph_hash) + addFingerprint: function(data_id, data_id_hash, import_hash) { + signing.signAndSend(data_id, data_id_hash, import_hash) return true; }, - getFingerprint: function(data_holder_address, batch_id_hash, callback) { + getFingerprint: function(data_holder_address, import_hash, callback) { var graph_hash = null; - graph_hash = contract_instance.getFingerprintByBatchHash(data_holder_address, batch_id_hash, { + graph_hash = contract_instance.getFingerprintByBatchHash(data_holder_address, data_id_hash, { from: web3.eth.accounts[0] }); diff --git a/modules/blockchain_interface/ethereum/migrations/1_initial_migration.js b/modules/blockchain_interface/ethereum/migrations/1_initial_migration.js index 42968952f7..7648a569fd 100644 --- a/modules/blockchain_interface/ethereum/migrations/1_initial_migration.js +++ b/modules/blockchain_interface/ethereum/migrations/1_initial_migration.js @@ -1,5 +1,5 @@ -var Migrations = artifacts.require('./Migrations.sol') +var Migrations = artifacts.require('./Migrations.sol'); module.exports = function (deployer) { - deployer.deploy(Migrations) -} + deployer.deploy(Migrations); +}; diff --git a/modules/blockchain_interface/ethereum/signing.js b/modules/blockchain_interface/ethereum/signing.js index fd2844c703..b4b983ed47 100644 --- a/modules/blockchain_interface/ethereum/signing.js +++ b/modules/blockchain_interface/ethereum/signing.js @@ -1,67 +1,235 @@ var utilities = require('../../utilities')(); var Web3 = require('web3'); var fs = require('fs'); - var util = require('ethereumjs-util'); var tx = require('ethereumjs-tx'); - var lightwallet = require('eth-lightwallet'); +var Account = require("eth-lib/lib/account"); +var Hash = require("eth-lib/lib/hash"); +var BN = require('bn.js'); +var abi = require('ethereumjs-abi'); var txutils = lightwallet.txutils; - var config = utilities.getConfig(); +const log = utilities.getLogger(); -var contract_abi = config.blockchain.settings.ethereum.contract_abi; -var private_key = config.blockchain.settings.ethereum.private_key; - -var contract_address = config.blockchain.settings.ethereum.contract_address; var wallet_address = config.blockchain.settings.ethereum.wallet_address; +var private_key = config.blockchain.settings.ethereum.private_key; var web3 = new Web3(new Web3.providers.HttpProvider(config.blockchain.settings.ethereum.rpc_node+":"+config.blockchain.settings.ethereum.node_port)); + + +// OT contract data +var contract_address = config.blockchain.settings.ethereum.contract_address; var contract_abi_path = config.blockchain.settings.ethereum.contract_abi; var contract_abi_file = fs.readFileSync(contract_abi_path); var contract_abi = JSON.parse(contract_abi_file); -var nonce = parseInt(web3.toHex(web3.eth.getTransactionCount(wallet_address, 'pending'))); +// Token contract data +var token_address = config.blockchain.settings.ethereum.token_contract; +var token_abi_path = config.blockchain.settings.ethereum.token_abi; +var token_abi_file = fs.readFileSync(token_abi_path); +var token_abi = JSON.parse(token_abi_file); + +// Escrow contract data +var escrow_address = config.blockchain.settings.ethereum.escrow_contract; +var escrow_abi_path = config.blockchain.settings.ethereum.escrow_abi; +var escrow_abi_file = fs.readFileSync(escrow_abi_path); +var escrow_abi = JSON.parse(escrow_abi_file); + +/* +console.log('------------------------'); +var nonce = 5; +web3.eth.getTransactionCount("0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe",web3.eth.defaultBlock,function(err, result) { +}).then(function (nonce){console.log(nonce)}) +console.log('------------------------');*/ + +var nonce = -1; var nonce_increment = 0; module.exports = function() { - function sendRaw(rawTx) { - var privateKey = new Buffer(private_key, 'hex'); - var transaction = new tx(rawTx); - transaction.sign(privateKey); - var serializedTx = transaction.serialize().toString('hex'); - web3.eth.sendRawTransaction( - '0x' + serializedTx, function(err, result) { - if(err) { - console.log(err); - } else { - console.log('Transaction: ', result); - } - }); - } + function sendRaw(rawTx, callback) { + var privateKey = new Buffer(private_key, 'hex'); + var transaction = new tx(rawTx); + transaction.sign(privateKey); + var serializedTx = transaction.serialize().toString('hex'); + return web3.eth.sendSignedTransaction('0x' + serializedTx); + } + + function sendTransaction(abi, method, args, txOptions) { + return new Promise((resolve, reject) => { + web3.eth.getTransactionCount(wallet_address).then(nonce => { + + txOptions.nonce = nonce; + + //log.info(method); + log.warn(txOptions); + + var rawTx = txutils.functionTx(abi, method, args, txOptions); + return sendRaw(rawTx).then(response => { + if(response.error == '0x0') { + return reject(response); + } else { + return resolve(response); + } + }).catch(err => { + reject(err); + }); + + }); + }); + } var signing = { signAndSend: function(batch_id, batch_id_hash, graph_hash) { - var new_nonce = nonce + nonce_increment; - nonce_increment = nonce_increment + 1; + var txOptions = { + gasLimit: web3.utils.toHex(config.blockchain.settings.ethereum.gas_limit), + gasPrice: web3.utils.toHex(config.blockchain.settings.ethereum.gas_price), + to: contract_address + }; + + return sendTransaction(contract_abi, 'addFingerPrint', [batch_id,batch_id_hash, graph_hash], txOptions); + }, + + signAndAllow: function(options) { + + var approvalFunction = this.listenApproval; + var createEscrowFunction = this.createEscrow; + + return new Promise((resolve, reject) => { + + var txOptions = { + gasLimit: web3.utils.toHex(config.blockchain.settings.ethereum.gas_limit), + gasPrice: web3.utils.toHex(config.blockchain.settings.ethereum.gas_price), + to: token_address + }; + + sendTransaction(token_abi, 'increaseApproval', [escrow_address, options.amount], txOptions).then(function(response) { + //log.info(response); + + log.info('Creating Escrow...'); + createEscrowFunction(options.dh_wallet, options.import_id, options.amount, options.start_time, options.total_time).then( result => { + log.info('Escrow created'); + resolve(result); + }).catch(e => { + log.error('Escrow creation failed'); + reject(e); + }); + + + }).catch(e => { + log.error('Not Approved!'); + console.log(e); + reject(e); + }); + }); + }, + + createEscrow: function(DH_wallet, data_id, token_amount, start_time, total_time, callback) { var txOptions = { - nonce: new_nonce, - gasLimit: web3.toHex(config.blockchain.settings.ethereum.gas_limit), - gasPrice: web3.toHex(config.blockchain.settings.ethereum.gas_price), - to: contract_address - } + gasLimit: web3.utils.toHex(config.blockchain.settings.ethereum.gas_limit), + gasPrice: web3.utils.toHex(config.blockchain.settings.ethereum.gas_price), + to: escrow_address + }; + + return sendTransaction(escrow_abi, 'initiateEscrow', [DH_wallet, data_id, token_amount, start_time, total_time], txOptions); + }, + + createConfirmation: function(DH_wallet, data_id, confirmation_verification_number, confirmation_time, confirmation_valid){ + + /* + address DC_wallet, uint data_id, + uint confirmation_verification_number, uint confirmation_time, bool confirmation_valid, + bytes32 confirmation_hash, uint8 v, bytes32 r, bytes32 s + */ + + // (msg.sender, data_id, confirmation_verification_number, confirmation_time, confirmation_valid) == confirmation_hash + var raw_data = "0x" + abi.soliditySHA3( + ["address", "uint", "uint", "uint", "bool"], + [new BN(DH_wallet, 16), data_id, confirmation_verification_number, confirmation_time, confirmation_valid] + ).toString('hex'); + + var hash = utilities.sha3(raw_data); + var signature = Account.sign(hash, '0x' + private_key); + var vrs = Account.decodeSignature(signature); + s = { + message: raw_data, + messageHash: hash, + v: vrs[0], + r: vrs[1], + s: vrs[2], + signature: signature + }; + + var confirmation = { + DC_wallet: wallet_address, + data_id: data_id, + confirmation_verification_number: confirmation_verification_number, + confirmation_time: confirmation_time, + confirmation_valid: confirmation_valid, + v: s.v, + r: s.r, + s: s.s, + confirmation_hash: s.message + }; + + return confirmation; + }, + sendRawX: function (rawTx, callback) { + var privateKey = new Buffer(private_key, 'hex'); + var transaction = new tx(rawTx); + transaction.sign(privateKey); + var serializedTx = transaction.serialize().toString('hex'); + web3.eth.sendSignedTransaction( + '0x' + serializedTx, function(err, result) { + if(err) { + console.log(err); + + if(callback) { + utilities.executeCallback(callback, false); + } + } else { + if(callback) { + utilities.executeCallback(callback, result); + } + console.log('Transaction: ', result); + } + }); + }, + + sendConfirmation: async function(confirmation, callback) { + + if(nonce == -1) + nonce = await web3.eth.getTransactionCount(wallet_address); - console.log(txOptions) + var new_nonce = nonce + nonce_increment; + nonce_increment = nonce_increment + 1; - var rawTx = txutils.functionTx(contract_abi, 'addFingerPrint', [batch_id,batch_id_hash, graph_hash], txOptions); - sendRaw(rawTx); + var txOptions = { + nonce: new_nonce, + gasLimit: web3.utils.toHex(config.blockchain.settings.ethereum.gas_limit), + gasPrice: web3.utils.toHex(config.blockchain.settings.ethereum.gas_price), + to: escrow_address + }; + + console.log(txOptions); + + var rawTx = txutils.functionTx(escrow_abi, 'payOut', [confirmation.DC_wallet, + confirmation.data_id, + confirmation.confirmation_verification_number, + confirmation.confirmation_time, + confirmation.confirmation_valid, + confirmation.confirmation_hash, + confirmation.v, + confirmation.r, + confirmation.s], txOptions); + this.sendRawX(rawTx, callback); } - } - return signing; -} + }; + return signing; +}; diff --git a/modules/blockchain_interface/ethereum/truffle-config.js b/modules/blockchain_interface/ethereum/truffle-config.js index efec0ab006..faeaff5631 100644 --- a/modules/blockchain_interface/ethereum/truffle-config.js +++ b/modules/blockchain_interface/ethereum/truffle-config.js @@ -1,4 +1,4 @@ module.exports = { - // See - // to customize your Truffle configuration! -} + // See + // to customize your Truffle configuration! +}; diff --git a/modules/blockchain_interface/ethereum/truffle.js b/modules/blockchain_interface/ethereum/truffle.js index efec0ab006..faeaff5631 100644 --- a/modules/blockchain_interface/ethereum/truffle.js +++ b/modules/blockchain_interface/ethereum/truffle.js @@ -1,4 +1,4 @@ module.exports = { - // See - // to customize your Truffle configuration! -} + // See + // to customize your Truffle configuration! +}; diff --git a/modules/config.js b/modules/config.js index 2b4e25fe0a..4c14264bf9 100644 --- a/modules/config.js +++ b/modules/config.js @@ -1,44 +1,53 @@ require('dotenv').config(); module.exports = { - "NODE_IP": process.env.NODE_IP, - "DB_TYPE": "arango", - "DB_USERNAME": process.env.DB_USERNAME, - "DB_PASSWORD": process.env.DB_PASSWORD, - "DB_HOST": process.env.DB_HOST, - "DB_PORT": process.env.DB_PORT, - "DB_DATABASE": process.env.DB_DATABASE, - "MAX_PATH_LENGTH": process.env.MAX_PATH_LENGTH, - "RPC_API_PORT": process.env.RPC_API_PORT, - "IPC_API_PORT": process.env.IPC_API_PORT, - "KADEMLIA_PORT": process.env.KADEMLIA_PORT, - "WALLET_ID": process.env.WALLET_ID, - "KADEMLIA_SEED_IP": process.env.KADEMLIA_SEED_IP, - "KADEMLIA_SEED_PORT": process.env.KADEMLIA_SEED_PORT, - "IS_KADEMLIA_BEACON": process.env.IS_KADEMLIA_BEACON, - "REQUEST_TIMEOUT": process.env.REQUEST_TIMEOUT, - "REMOTE_ACCESS": [process.env.REMOTE_ACCESS], - "blockchain":{ - "preferred_chain": "ethereum", - "settings":{ - "ethereum" : { - "network": "rinkeby", - "wallet_address": process.env.WALLET_ADDRESS, - "private_key": process.env.PRIVATE_KEY, - "contract_bytecode": "606060405262093a80600155341561001657600080fd5b6040516020806108fc83398101604052808051906020019091905050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060028190555050610873806100896000396000f30060606040526004361061008d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680620be63914610092578063037a4c38146100f45780630d8e6e2c146101835780633a7941f8146101ac5780633e118dbe1461020e5780638da5cb5b146102375780639201de551461028c578063f2fde38b1461032c575b600080fd5b341561009d57600080fd5b6100d6600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803560001916906020019091905050610365565b60405180826000191660001916815260200191505060405180910390f35b34156100ff57600080fd5b610169600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091908035600019169060200190919080356000191690602001909190505061038a565b604051808215151515815260200191505060405180910390f35b341561018e57600080fd5b6101966104f8565b6040518082815260200191505060405180910390f35b34156101b757600080fd5b6101f0600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803560001916906020019091905050610502565b60405180826000191660001916815260200191505060405180910390f35b341561021957600080fd5b6102216105a0565b6040518082815260200191505060405180910390f35b341561024257600080fd5b61024a6105a6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561029757600080fd5b6102b16004808035600019169060200190919050506105cb565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102f15780820151818401526020810190506102d6565b50505050905090810190601f16801561031e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561033757600080fd5b610363600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506106ca565b005b6003602052816000526040600020602052806000526040600020600091509150505481565b60008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515156103c757600080fd5b81600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085600019166000191681526020019081526020016000208160001916905550836040518082805190602001908083835b60208310151561045e5780518252602082019150602081019050602083039250610439565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390203373ffffffffffffffffffffffffffffffffffffffff167f2a87ffb089688d8430d27ae416aac00c02c0a287c0764d29018525e4ff01da45858560405180836000191660001916815260200182600019166000191681526020019250505060405180910390a39392505050565b6000600254905090565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561053f57600080fd5b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836000191660001916815260200190815260200160002054905092915050565b60025481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6105d361081f565b6105db610833565b60008060206040518059106105ed5750595b9080825280601f01601f19166020018201604052509250600091505b60208210156106bf578160080260020a856001900402600102905060007f010000000000000000000000000000000000000000000000000000000000000002817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415156106b25780838381518110151561068157fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505b8180600101925050610609565b829350505050919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561072557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561076157600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a72305820cc75fad3044d79294ab40db826904e4446135c3a14d6166b3ebfb0b6f92241d60029", - "contract_address": "0x9d4c317d44850ba0bb56580acb8e14990f7ffe09", - "contract_abi": "modules/blockchain_interface/ethereum/contracts/contract_abi.js", - "rpc_node": "http://ec2-52-59-72-10.eu-central-1.compute.amazonaws.com", - "node_port": "80", - "gas_limit": process.env.GAS_LIMIT, - "gas_price": process.env.GAS_PRICE - }, - "iota": { - "i":"// TODO: setup testing Iota node" - }, - "neo":{ - "i":"// TODO: setup testing Neo node" - } - } - } -} + 'NODE_IP': process.env.NODE_IP, + 'DH_NODE_IP' : process.env.DH_NODE_IP, + 'DH_NODE_PORT' : process.env.DH_NODE_PORT, + 'DH_WALLET': process.env.DH_WALLET, + 'DB_TYPE': 'arango', + 'DB_USERNAME': process.env.DB_USERNAME, + 'DB_PASSWORD': process.env.DB_PASSWORD, + 'DB_HOST': process.env.DB_HOST, + 'DB_PORT': process.env.DB_PORT, + 'DB_DATABASE': process.env.DB_DATABASE, + 'MAX_PATH_LENGTH': process.env.MAX_PATH_LENGTH, + 'RPC_API_PORT': process.env.RPC_API_PORT, + 'IPC_API_PORT': process.env.IPC_API_PORT, + 'KADEMLIA_PORT': process.env.KADEMLIA_PORT, + 'WALLET_ID': process.env.WALLET_ID, + 'KADEMLIA_SEED_IP': process.env.KADEMLIA_SEED_IP, + 'KADEMLIA_SEED_PORT': process.env.KADEMLIA_SEED_PORT, + 'IS_KADEMLIA_BEACON': process.env.IS_KADEMLIA_BEACON, + 'REQUEST_TIMEOUT': process.env.REQUEST_TIMEOUT, + 'REMOTE_ACCESS': [process.env.REMOTE_ACCESS], + 'blockchain':{ + 'preferred_chain': 'ethereum', + 'settings':{ + 'ethereum' : { + 'token_contract': '0x98d9a611ad1b5761bdc1daac42c48e4d54cf5882', + 'escrow_contract':'0x704c83ed23078bea4ce38ce243657e4a764129d7', + 'escrow_abi': 'modules/blockchain_interface/ethereum/contracts/escrow_abi.js', + 'escrow_bytecode':'6060604052341561000f57600080fd5b604051602080610fb683398101604052808051906020019091905050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561006757600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610e9d806101196000396000f30060606040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063410085df1461007257806382b9be1a146100b45780638d7c24891461014c578063b1c8e343146101de578063fc0c546a1461023b575b600080fd5b341561007d57600080fd5b6100b2600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610290565b005b34156100bf57600080fd5b610113600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061070b565b60405180878152602001868152602001858152602001848152602001838152602001828152602001965050505050505060405180910390f35b341561015757600080fd5b6101dc600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001909190803515159060200190919080356000191690602001909190803560ff169060200190919080356000191690602001909190803560001916906020019091905050610761565b005b34156101e957600080fd5b610239600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091908035906020019091908035906020019091908035906020019091905050610b03565b005b341561024657600080fd5b61024e610e2d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008033915062093a80600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008581526020019081526020016000206004015401421015151561033a57600080fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060010154600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000858152602001908152602001600020600001540390506000811180156104fe5750600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000206000015481105b1561070557600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060000154600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085815260200190815260200160002060010181905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15156106ec57600080fd5b5af115156106f957600080fd5b50505060405180519050505b50505050565b600260205282600052604060002060205281600052604060002060205280600052604060002060009250925050508060000154908060010154908060020154908060030154908060040154908060050154905086565b600080600260008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b815260200190815260200160002091508160000154826001015410151561080957600080fd5b87826003015410151561081b57600080fd5b6001866040518082600019166000191681526020019150506040518091039020868686604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af115156108a957600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff161415156108eb57600080fd5b8560001916338b8b8b8b604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140185815260200184815260200183815260200182151515157f01000000000000000000000000000000000000000000000000000000000000000281526001019550505050505060405180910390206000191614151561099757600080fd5b8615610ae3578882600201541415156109af57600080fd5b81600401548811156109c357816004015497505b8160050154826003015489038360000154028115156109de57fe5b049050878260030181905550610a01818360010154610e5390919063ffffffff16565b50600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1515610ac657600080fd5b5af11515610ad357600080fd5b5050506040518051905050610af6565b8882600201819055508782600301819055505b5050505050505050505050565b82600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b1515610bf457600080fd5b5af11515610c0157600080fd5b5050506040518051905010151515610c1857600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1515610d1057600080fd5b5af11515610d1d57600080fd5b505050604051805190505060c0604051908101604052808481526020016000815260200160008152602001838152602001828401815260200182815250600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000868152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a082015181600501559050505050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000808284019050838110151515610e6757fe5b80915050929150505600a165627a7a723058205518d069b4e7e7d7f362095539e8d100588082fde3e8025277a83f0a88171b0c0029', + 'token_bytecode':'60606040526000600360146101000a81548160ff021916908315150217905550635a5cc1f06004556b019d971e4fe8401e74000000600855341561004257600080fd5b604051602080611bda8339810160405280805190602001909190505033600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008173ffffffffffffffffffffffffffffffffffffffff16141515156100c557600080fd5b80600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050611ac4806101166000396000f30060606040526004361061011d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305d2035b1461012257806306fdde031461014f578063095ea7b3146101dd57806318160ddd1461023757806323b872dd14610260578063313ce567146102d957806340c10f1914610308578063521eb2731461036257806366188463146103b757806370a082311461041157806378e979251461045e5780637d64bcb4146104875780638b8ecffa146104b45780638da5cb5b1461050957806395d89b411461055e578063a9059cbb146105ec578063c2572c5114610646578063c8e7e5ef1461069b578063d73dd623146106c4578063dd62ed3e1461071e578063f2fde38b1461078a575b600080fd5b341561012d57600080fd5b6101356107c3565b604051808215151515815260200191505060405180910390f35b341561015a57600080fd5b6101626107d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101a2578082015181840152602081019050610187565b50505050905090810190601f1680156101cf5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156101e857600080fd5b61021d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061080f565b604051808215151515815260200191505060405180910390f35b341561024257600080fd5b61024a610993565b6040518082815260200191505060405180910390f35b341561026b57600080fd5b6102bf600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610999565b604051808215151515815260200191505060405180910390f35b34156102e457600080fd5b6102ec6109ca565b604051808260ff1660ff16815260200191505060405180910390f35b341561031357600080fd5b610348600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506109cf565b604051808215151515815260200191505060405180910390f35b341561036d57600080fd5b610375610a3f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156103c257600080fd5b6103f7600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a65565b604051808215151515815260200191505060405180910390f35b341561041c57600080fd5b610448600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610cf6565b6040518082815260200191505060405180910390f35b341561046957600080fd5b610471610d3f565b6040518082815260200191505060405180910390f35b341561049257600080fd5b61049a610d45565b604051808215151515815260200191505060405180910390f35b34156104bf57600080fd5b6104c7610df1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561051457600080fd5b61051c610e17565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561056957600080fd5b610571610e3d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156105b1578082015181840152602081019050610596565b50505050905090810190601f1680156105de5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156105f757600080fd5b61062c600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610e76565b604051808215151515815260200191505060405180910390f35b341561065157600080fd5b610659610ea5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156106a657600080fd5b6106ae610ecb565b6040518082815260200191505060405180910390f35b34156106cf57600080fd5b610704600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610ed1565b604051808215151515815260200191505060405180910390f35b341561072957600080fd5b610774600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506110cd565b6040518082815260200191505060405180910390f35b341561079557600080fd5b6107c1600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611154565b005b600360149054906101000a900460ff1681565b6040805190810160405280600f81526020017f416c7068615472616320546f6b656e000000000000000000000000000000000081525081565b600080600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054148061089b5750600082145b15156108a357fe5b81600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b6000600360149054906101000a900460ff1615156109b657600080fd5b6109c18484846112ac565b90509392505050565b601281565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610a2d57600080fd5b610a37838361166b565b905092915050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905080831115610b76576000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610c0a565b610b89838261183d90919063ffffffff16565b600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b8373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518082815260200191505060405180910390a3600191505092915050565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60045481565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610da357600080fd5b6001600360146101000a81548160ff0219169083151502179055507fae5184fba832cb2b1f702aca6117b8d265eaf03ad33eb133f19dde0f5920fa0860405160405180910390a16001905090565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040805190810160405280600581526020017f415452414300000000000000000000000000000000000000000000000000000081525081565b6000600360149054906101000a900460ff161515610e9357600080fd5b610e9d8383611856565b905092915050565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60085481565b6000610f6282600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611a7a90919063ffffffff16565b600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156111b057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156111ec57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff16600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a380600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156112e957600080fd5b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115151561133757600080fd5b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482111515156113c257600080fd5b61141482600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461183d90919063ffffffff16565b600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506114a982600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611a7a90919063ffffffff16565b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061157b82600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461183d90919063ffffffff16565b600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156116c957600080fd5b600360149054906101000a900460ff161515156116e557600080fd5b6116fa82600054611a7a90919063ffffffff16565b60008190555061175282600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611a7a90919063ffffffff16565b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885836040518082815260200191505060405180910390a28273ffffffffffffffffffffffffffffffffffffffff1660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b600082821115151561184b57fe5b818303905092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561189357600080fd5b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482111515156118e157600080fd5b61193382600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461183d90919063ffffffff16565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506119c882600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611a7a90919063ffffffff16565b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000808284019050838110151515611a8e57fe5b80915050929150505600a165627a7a723058207521fc64764334e4e2da7b3bfc57ce8935b705ade9e9945d59aea5801597f77e0029', + 'token_abi':'modules/blockchain_interface/ethereum/contracts/token_abi.js', + 'network': 'rinkeby', + 'wallet_address': process.env.WALLET_ADDRESS, + 'private_key': process.env.PRIVATE_KEY, + 'contract_bytecode': '606060405262093a80600155341561001657600080fd5b6040516020806108fc83398101604052808051906020019091905050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060028190555050610873806100896000396000f30060606040526004361061008d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680620be63914610092578063037a4c38146100f45780630d8e6e2c146101835780633a7941f8146101ac5780633e118dbe1461020e5780638da5cb5b146102375780639201de551461028c578063f2fde38b1461032c575b600080fd5b341561009d57600080fd5b6100d6600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803560001916906020019091905050610365565b60405180826000191660001916815260200191505060405180910390f35b34156100ff57600080fd5b610169600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091908035600019169060200190919080356000191690602001909190505061038a565b604051808215151515815260200191505060405180910390f35b341561018e57600080fd5b6101966104f8565b6040518082815260200191505060405180910390f35b34156101b757600080fd5b6101f0600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803560001916906020019091905050610502565b60405180826000191660001916815260200191505060405180910390f35b341561021957600080fd5b6102216105a0565b6040518082815260200191505060405180910390f35b341561024257600080fd5b61024a6105a6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561029757600080fd5b6102b16004808035600019169060200190919050506105cb565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102f15780820151818401526020810190506102d6565b50505050905090810190601f16801561031e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561033757600080fd5b610363600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506106ca565b005b6003602052816000526040600020602052806000526040600020600091509150505481565b60008073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515156103c757600080fd5b81600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085600019166000191681526020019081526020016000208160001916905550836040518082805190602001908083835b60208310151561045e5780518252602082019150602081019050602083039250610439565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390203373ffffffffffffffffffffffffffffffffffffffff167f2a87ffb089688d8430d27ae416aac00c02c0a287c0764d29018525e4ff01da45858560405180836000191660001916815260200182600019166000191681526020019250505060405180910390a39392505050565b6000600254905090565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561053f57600080fd5b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836000191660001916815260200190815260200160002054905092915050565b60025481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6105d361081f565b6105db610833565b60008060206040518059106105ed5750595b9080825280601f01601f19166020018201604052509250600091505b60208210156106bf578160080260020a856001900402600102905060007f010000000000000000000000000000000000000000000000000000000000000002817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415156106b25780838381518110151561068157fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505b8180600101925050610609565b829350505050919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561072557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561076157600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a72305820cc75fad3044d79294ab40db826904e4446135c3a14d6166b3ebfb0b6f92241d60029', + 'contract_address': '0x8126e8a02bcae11a631d4413b9bd4f01f14e045d', + 'contract_abi': 'modules/blockchain_interface/ethereum/contracts/contract_abi.js', + 'rpc_node': 'https://rinkeby.infura.io/1WRiEqAQ9l4SW6fGdiDt', + 'node_port': '80', + 'gas_limit': process.env.GAS_LIMIT, + 'gas_price': process.env.GAS_PRICE + }, + 'iota': { + 'i':'// TODO: setup testing Iota node' + }, + 'neo':{ + 'i':'// TODO: setup testing Neo node' + } + } + } +}; diff --git a/modules/database.js b/modules/database.js index 6f412bbec0..8ed20208aa 100644 --- a/modules/database.js +++ b/modules/database.js @@ -1,5 +1,6 @@ // External modules const utilities = require('./utilities')(); +const log = utilities.getLogger(); const Database = require('arangojs').Database; const config = utilities.getConfig(); @@ -25,7 +26,126 @@ module.exports = function () { utilities.executeCallback(callback, cursor._result); } catch (err) { utilities.executeCallback(callback, []); - console.log(err) + console.log(err); + } + }, + createVertexCollection: async function(collection_name, callback) { + var collection = db.collection(collection_name); + collection.create().then( + () => { + log.info('Collection created'); + utilities.executeCallback(callback, true); + }, + err => { + if(err.response.body.code == 409) { + log.info('collection already exists'); + utilities.executeCallback(callback, true); + } + else + { + log.info(err); + utilities.executeCallback(callback, false); + } + } + ); + }, + createEdgeCollection: async function(collection_name, callback) { + var collection = db.edgeCollection(collection_name); + collection.create().then( + () => { + log.info('Collection created'); + utilities.executeCallback(callback, true); + }, + err => { + if(err.response.body.code == 409) { + log.info('collection already exists'); + utilities.executeCallback(callback, true); + } + else + { + log.info(err); + utilities.executeCallback(callback, false); + } + } + ); + }, + + addVertex: function(collection_name, vertex, callback) { + var collection = db.collection(collection_name); + collection.save(vertex).then( + meta => utilities.executeCallback(callback, true), + err => { + //console.error('Failed to save document:', err) + utilities.executeCallback(callback, false); + } + ); + }, + + addEdge: function(collection_name, edge, callback) { + var collection = db.collection(collection_name); + collection.save(edge).then( + meta => utilities.executeCallback(callback, true), + err => { + //console.error('Failed to save document:', err) + utilities.executeCallback(callback, false); + } + ); + }, + + updateDocumentImports: function(collection_name, document_key, import_number, callback) { + var collection = db.collection(collection_name); + collection.document(document_key).then( + doc => { + + var imports = doc.imports; + + if(imports == undefined) + imports = []; + + if(imports.indexOf(import_number) == -1) + { + imports.push(import_number); + collection.update(document_key, {imports: imports}).then( + meta => utilities.executeCallback(callback, true), + err => { + log.info(err); + utilities.executeCallback(callback, false); + } + ); + } + }, + err => { + log.info(err); + utilities.executeCallback(callback, false); + } + ); + }, + + getVerticesByImportId: async function(data_id, callback){ + + queryString = 'FOR v IN ot_vertices FILTER POSITION(v.imports, @importId, false) != false RETURN v'; + params = {importId: data_id}; + + try { + let cursor = await db.query(queryString, params); + utilities.executeCallback(callback, cursor._result); + } catch (err) { + utilities.executeCallback(callback, []); + log.info(err); + } + }, + + getEdgesByImportId: async function(data_id, callback){ + + queryString = 'FOR v IN ot_edges FILTER POSITION(v.imports, @importId, false) != false RETURN v'; + params = {importId: data_id}; + + try { + let cursor = await db.query(queryString, params); + utilities.executeCallback(callback, cursor._result); + } catch (err) { + utilities.executeCallback(callback, []); + log.info(err); } } }; diff --git a/modules/encryption.js b/modules/encryption.js new file mode 100644 index 0000000000..09e8551221 --- /dev/null +++ b/modules/encryption.js @@ -0,0 +1,36 @@ +// External modules +var RSA = require('node-rsa'); + +module.exports = function () { + let encryption = { + generateKeyPair: function() { + var key = new RSA({b: 512}); + + var private = key.exportKey('pkcs8-private'); + var public = key.exportKey('pkcs8-public'); + + return { + privateKey: private, + publicKey: public + } + }, + + encryptObject: function(data, private_key) { + var key = new RSA(); + key.importKey(private_key, 'pkcs8-private'); + var encrypted = key.encryptPrivate(data, 'base64'); + + return encrypted + }, + + decryptObject: function(data, public_key) { + var key = new RSA(); + key.importKey(public_key, 'pkcs8-public'); + var decrypted = key.decryptPublic(data, 'utf8'); + + return JSON.parse(decrypted) + } + }; + + return encryption; +}; diff --git a/modules/graph.js b/modules/graph.js index 03cfcc2299..3dfef68883 100644 --- a/modules/graph.js +++ b/modules/graph.js @@ -1,13 +1,16 @@ // External modules const utilities = require('./utilities')(); +//const log = utilities.getLogger(); const database = require('./database')(); +const encryption = require('./encryption')(); +const storage = require('./storage')(); const config = utilities.getConfig(); const MAX_PATH_LENGTH = parseInt(config.MAX_PATH_LENGTH); module.exports = function () { let graph = { - getVertices: function (queryObject, callback) { + getVertices: function (queryObject, callback) { let queryString = 'FOR v IN ot_vertices '; let params = {}; if (utilities.isEmptyObject(queryObject) === false) { @@ -21,7 +24,7 @@ module.exports = function () { continue; } - if(key != 'vertex_type') + if(key != 'vertex_type' && key != '_key') { search_key = 'identifiers.' + key; } @@ -173,6 +176,67 @@ module.exports = function () { } else { return traversalArray; } + }, + + encryptVertices: function(dh_ip, dh_port, vertices, callback) { + + storage.getObject('Keys', function(response) { + if(response.length == 0) + { + var keypair = encryption.generateKeyPair(); + + storage.storeObject('Keys', [{dh_ip: dh_ip, dh_port: dh_port, privateKey: keypair.privateKey, publicKey: keypair.publicKey}], function(response) { + + for(let i in vertices) { + vertices[i].data = encryption.encryptObject(vertices[i].data, keypair.privateKey); + vertices[i].decryption_key = keypair.publicKey; + } + + utilities.executeCallback(callback, {vertices: vertices, public_key: keypair.publicKey}); + }) + + } + else + { + for(let i in response) { + if(response[i].dh_ip == dh_ip && response[i].dh_port == dh_port) { + + for(let j in vertices) { + vertices[j].data = encryption.encryptObject(vertices[j].data, response[i].privateKey); + vertices[j].decryption_key = response[i].publicKey; + } + + utilities.executeCallback(callback, {vertices: vertices, public_key: response[i].publicKey}); + return; + } + } + + var keypair = encryption.generateKeyPair(); + + response.push({dh_ip: dh_ip, dh_port: dh_port, privateKey: keypair.privateKey, publicKey: keypair.publicKey}); + + storage.storeObject('Keys', response, function(response) { + + for(let i in vertices) { + vertices[i].data = encryption.encryptObject(vertices[i].data, keypair.privateKey); + vertices[i].decryption_key = keypair.publicKey; + } + + utilities.executeCallback(callback, {vertices: vertices, public_key: keypair.publicKey}); + return; + }) + + } + }) + }, + + decryptVertices: function(vertices, public_key) { + + for(i in vertices) { + vertices[i].data = encryption.decryptObject(vertices[i].data, public_key); + } + + return vertices; } }; diff --git a/modules/holding.js b/modules/holding.js new file mode 100644 index 0000000000..7e77052b4e --- /dev/null +++ b/modules/holding.js @@ -0,0 +1,86 @@ +var utilities = require('./utilities')(); +const log = utilities.getLogger(); +var storage = require('./storage')(); + +module.exports = function(){ + + var holding = { + addHoldingData: function(dh_wallet, data_id, public_key, callback) { + storage.getObject('Holding', function(response) { + + if(response.length == 0) + { + response = {data:[]}; + } + + for(let i in response.data) { + + if (response.data[i].dh_wallet == dh_wallet && response.data[i].data_id == data_id) + { + utilities.executeCallback(callback, true); + return; + } + } + + new_data = {dh_wallet: dh_wallet, data_id: data_id, public_key: public_key, confirmation_number: 0}; + log.info(JSON.stringify(new_data)) + response.data.push(new_data); + + storage.storeObject('Holding', response, function(status){ + utilities.executeCallback(callback, true); + }) + + }) + }, + + getHoldingData: function(dh_wallet, data_id, callback) { + storage.getObject('Holding', function(response) { + + if(response.length == 0 || response.data.length == 0) { + utilities.executeCallback(callback, {}); + return; + } + + for(let i in response.data) { + + if (response.data[i].dh_wallet == dh_wallet && response.data[i].data_id == data_id) + { + utilities.executeCallback(callback, response.data[i]); + return; + } + + } + + utilities.executeCallback(callback, {}); + + }) + }, + + increaseConfirmationVerificationNumber: function(dh_wallet, data_id, callback) { + storage.getObject('Holding', function(response) { + + if(response.length == 0) + { + utilities.executeCallback(callback, false); + return; + } + + for(let i in response.data) { + + if (response.data[i].dh_wallet == dh_wallet && response.data[i].data_id == data_id) + { + response.data[i].confirmation_number += 1; + } + } + + storage.storeObject('Holding',response, function(status){ + utilities.executeCallback(callback, true); + }) + + }) + } + }; + + return holding + +} diff --git a/modules/importer.js b/modules/importer.js index c3531da404..99077dc49f 100644 --- a/modules/importer.js +++ b/modules/importer.js @@ -1,52 +1,145 @@ // External modules -var PythonShell = require('python-shell'); +const PythonShell = require('python-shell'); const utilities = require('./utilities')(); +const log = utilities.getLogger(); +const config = utilities.getConfig(); +const Mtree = require('./mtree')(); +const storage = require('./storage')(); const blockchain = require('./blockchain')(); -const product = require('./product')(); +const signing = require('./blockchain_interface/ethereum/signing')(); const async = require('async'); +const db = require('./database')(); + +const replication = require('./DataReplication'); module.exports = function () { let importer = { - importXML: function (ot_xml_document, callback) { + importJSON: async function (json_document, callback) { + log.info('Entering importJSON'); + var graph = json_document; + await db.createVertexCollection('ot_vertices', function(){}); + await db.createEdgeCollection('ot_edges', function(){}); + + let vertices = graph.vertices; + let edges = graph.edges; + let data_id = graph.import_id; + + async.each(vertices, function (vertex, next) { + db.addVertex('ot_vertices', vertex, function(import_status) { + if(import_status == false) { + db.updateDocumentImports('ot_vertices', vertex._key, data_id, function(update_status) { + if(update_status == false) + { + log.info('Import error!'); + return; + } + else + { + next(); + } + }); + } + else { + next(); + } + }); + }, function(){ + + }); + + async.each(edges, function (edge, next) { + db.addEdge('ot_edges', edge, function(import_status) { + if(import_status == false) { + db.updateDocumentImports('ot_edges', edge._key, data_id, function(update_status) { + if(update_status == false) + { + log.info('Import error!'); + return; + } + else + { + next(); + } + }); + } + else { + next(); + } + }); + }, function(){ + log.info('JSON import complete'); + }); + + utilities.executeCallback(callback,true); + }, + + importXML: async function async (ot_xml_document, callback) { var options = { - mode: 'text', - pythonPath: 'python3', - scriptPath: 'importers/', - args: [ot_xml_document] + mode: 'text', + pythonPath: 'python3', + scriptPath: 'importers/', + args: [ot_xml_document] }; - PythonShell.run('default_importer.py', options, function(stderr, stdout){ + PythonShell.run('v1.5.py', options, function(stderr, stdout){ if (stderr) { - console.log(stderr); + log.info(stderr); utilities.executeCallback(callback, { message: 'Import failure', data: [] }); - return; + return; } else { + log.info('[DC] Import complete'); let result = JSON.parse(stdout); - let batch_uids_array = Object.keys(result.batches); - async.each(batch_uids_array, function (batch_uid, next) { - product.getTrailByUID(batch_uid, function (trailObject) { - let trail = trailObject.graph; - let bid = batch_uid; - let bid_hash = utilities.sha3(bid); - let trail_hash = product.hashTrail(trail, bid); + var vertices = result.vertices; + var edges = result.edges; + let data_id = result.import_id; + - // blockchain.addFingerprint(bid, bid_hash, trail_hash); + let leaves = []; + let hash_pairs = []; - next(); - }); - }, function () { - utilities.executeCallback(callback, { - message: 'Import success', - data: [] + for(let i in vertices) { + leaves.push(utilities.sha3(utilities.sortObject({identifiers: vertices[i].identifiers, data: vertices[i].data}))); + hash_pairs.push({key: vertices[i]._key, hash: utilities.sha3({identifiers: vertices[i].identifiers, data: vertices[i].data})}); + } + + let tree = new Mtree(hash_pairs); + let root_hash = tree.root(); + + log.info("Import id: " + data_id); + log.info("Import hash: " + root_hash); + storage.storeObject('Import_'+data_id, {vertices: hash_pairs, root_hash: root_hash}, function(response) { + signing.signAndSend(data_id, utilities.sha3(data_id), utilities.sha3(tree.root())).then(response => { + + const graph = require('./graph')(); + const testing = require('./testing')(); + + graph.encryptVertices(config.DH_NODE_IP, config.DH_NODE_PORT, vertices, result => { + const encryptedVertices = result; + log.info('[DC] Preparing to enter sendPayload'); + + const data = {}; + data.vertices = vertices; + data.edges = edges; + data.data_id = data_id; + + replication.sendPayload(data, (result) => { + log.info('[DC] Payload sent'); + log.info('[DC] Generating tests for DH'); + }); + }); + + }).catch(err => { + log.warn('Failed to write data fingerprint on blockchain!'); }); }); + } }); } @@ -55,3 +148,4 @@ module.exports = function () { return importer; }; + diff --git a/modules/kademlia.js b/modules/kademlia.js index 8a6c482fe8..6a448e143c 100644 --- a/modules/kademlia.js +++ b/modules/kademlia.js @@ -1,94 +1,96 @@ // External modules -var leveldup = require('levelup') -var leveldown = require('leveldown') -var kad = require('kad') -const quasar = require('kad-quasar') -var utilities = require('./utilities')() -var config = utilities.getConfig() +var leveldup = require('levelup'); +var leveldown = require('leveldown'); +var kad = require('kad'); +const quasar = require('kad-quasar'); +var utilities = require('./utilities')(); +const log = utilities.getLogger(); +var config = utilities.getConfig(); // Response pool -var ping_responses = [] -var waiting_for_responses = false -var node = null +var ping_responses = []; +var waiting_for_responses = false; +var node = null; module.exports = function () { - var kademlia = { - - sendRequest: function (requestType, requestObject) { - node.quasarPublish(requestType, requestObject) - }, - - getPingResponses: function () { - return ping_responses - }, - - clearPingResponses: function () { - ping_responses = [] - }, - - waitForResponse: function () { - waiting_for_responses = true - }, - - stopWaitingForResponse: function () { - waiting_for_responses = false - }, - - start: function () { - - const seed = ['0000000000000000000000000000000000000001', { - hostname: config.KADEMLIA_SEED_IP, - port: config.KADEMLIA_SEED_PORT - }] - - node = kad({ - transport: new kad.HTTPTransport(), - storage: require('levelup')(leveldown('kad-storage')), - contact: { - hostname: config.NODE_IP, - port: config.KADEMLIA_PORT - } - }) - node.plugin(quasar) - - if (config.IS_KADEMLIA_BEACON == 'false') { - node.join(seed, function () { - if (node.router.size != 0) { - console.log('Kademlia connected to seed') - } else { - console.log('Kademlia connection to seed failed') - } - }) - } - - node.listen(config.KADEMLIA_PORT, function () { - console.log('Kademlia service listening...') - }) - - node.quasarSubscribe('ot-ping-request', (content) => { - if (content.sender_ip == config.NODE_IP && content.sender_port == config.RPC_API_PORT) { - return - } - - node.quasarPublish('ot-ping-response', { - request_id: content.request_id, - sender_ip: config.NODE_IP, - sender_port: config.RPC_API_PORT, - message: 'ALOHA' - }) - }) - - node.quasarSubscribe('ot-ping-response', (content) => { - if (content.sender_ip == config.NODE_IP && content.sender_port == config.RPC_API_PORT) { - return - } - - if (waiting_for_responses == true) { - ping_responses.push(content) - } - }) - } - } - - return kademlia -} + var kademlia = { + + sendRequest: function (requestType, requestObject) { + node.quasarPublish(requestType, requestObject); + }, + + getPingResponses: function () { + return ping_responses; + }, + + clearPingResponses: function () { + ping_responses = []; + }, + + waitForResponse: function () { + waiting_for_responses = true; + }, + + stopWaitingForResponse: function () { + waiting_for_responses = false; + }, + + start: function () { + + const seed = ['0000000000000000000000000000000000000001', { + hostname: config.KADEMLIA_SEED_IP, + port: config.KADEMLIA_SEED_PORT + }]; + + node = kad({ + transport: new kad.HTTPTransport(), + storage: require('levelup')(leveldown('kad-storage')), + contact: { + hostname: config.NODE_IP, + port: config.KADEMLIA_PORT + } + }); + + node.plugin(quasar); + + if (config.IS_KADEMLIA_BEACON == 'false') { + node.join(seed, function () { + if (node.router.size != 0) { + log.info('Kademlia connected to seed'); + } else { + log.warn('Kademlia connection to seed failed'); + } + }); + } + + node.listen(config.KADEMLIA_PORT, function () { + log.info('Kademlia service listening...'); + }); + + node.quasarSubscribe('ot-ping-request', (content) => { + if (content.sender_ip == config.NODE_IP && content.sender_port == config.RPC_API_PORT) { + return; + } + + node.quasarPublish('ot-ping-response', { + request_id: content.request_id, + sender_ip: config.NODE_IP, + sender_port: config.RPC_API_PORT, + message: 'ALOHA' + }); + }); + + node.quasarSubscribe('ot-ping-response', (content) => { + if (content.sender_ip == config.NODE_IP && content.sender_port == config.RPC_API_PORT) { + return; + } + + if (waiting_for_responses == true) { + ping_responses.push(content); + } + }); + } + }; + + return kademlia; +}; diff --git a/modules/mtree.js b/modules/mtree.js new file mode 100644 index 0000000000..44ee067ce9 --- /dev/null +++ b/modules/mtree.js @@ -0,0 +1,57 @@ +const MerkleTree = require('@garbados/merkle-tree'); +const crypto = require('crypto'); + +module.exports = function(){ + + class MTree { + + constructor(dataArray) { + this.dataArray = dataArray; + this.tree = new MerkleTree('sha256', dataArray); + } + + root() { + return this.tree.root; + } + + + digestFn (hashType, data) { + if (typeof data !== 'string') data = JSON.stringify(data); + const hash = crypto.createHash(hashType); + hash.update(data); + return hash.digest('hex'); + } + + verifyLeaf(leaf_index) { + + if(leaf_index >= this.tree.leaves.length || leaf_index < 0) + return false; + + let proof = this.tree.proof(leaf_index); + return proof[0].indexOf(this.tree.leaves[leaf_index]) != -1; + } + + verifyLeaves(test_leaves) { + for(var i in test_leaves){ + + var test_leaf = test_leaves[i]; + + var test_leaf_index = this.findIndex(test_leaf); + + if(this.verifyLeaf(test_leaf_index) === false) { + return false; + } + } + return true; + } + + findIndex(leaf) { + let test_leaf_hash = this.digestFn('sha256', leaf); + return this.tree.leaves.indexOf(test_leaf_hash); + } + + } + + return MTree; + +}; \ No newline at end of file diff --git a/modules/product.js b/modules/product.js index dc4c7cc5a4..43436cf6df 100644 --- a/modules/product.js +++ b/modules/product.js @@ -1,5 +1,6 @@ // External modules var utilities = require('./utilities')(); +const log = utilities.getLogger(); var database = require('./database')(); var graph = require('./graph')(); var Database = require('arangojs').Database; diff --git a/modules/replication.js b/modules/replication.js index eb71022e5b..eb06f0c0f4 100644 --- a/modules/replication.js +++ b/modules/replication.js @@ -1,44 +1,45 @@ // External modules -var unirest = require('unirest') -var kademlia = require('./kademlia')() -var utilities = require('./utilities')() -var config = utilities.getConfig() +var unirest = require('unirest'); +var kademlia = require('./kademlia')(); +var utilities = require('./utilities')(); +var config = utilities.getConfig(); +const log = utilities.getLogger(); module.exports = function () { - var replication = { - - replicate: function (input_file) { - kademlia.clearPingResponses() - kademlia.waitForResponse() - - var reqNum = utilities.getRandomInt(10000000000) - - kademlia.sendRequest('ot-ping-request', { - request_id: reqNum, - sender_ip: config.NODE_IP, - sender_port: config.RPC_API_PORT - }) - - setTimeout(function () { - kademlia.stopWaitingForResponse() - - var responses = kademlia.getPingResponses() - - for (var i in responses) { - unirest.post('http://' + responses[i].sender_ip + ':' + responses[i].sender_port + '/import') - .headers({ - 'Content-Type': 'multipart/form-data' - }) - .field('noreplicate', true) - .attach('importfile', input_file) - .end(function (response) { - console.log('Replication response : ' + JSON.stringify(response.body)) - }) - } - }, parseInt(config.REQUEST_TIMEOUT)) - } - - } - - return replication -} + var replication = { + + replicate: function (input_file) { + kademlia.clearPingResponses(); + kademlia.waitForResponse(); + + var reqNum = utilities.getRandomInt(10000000000); + + kademlia.sendRequest('ot-ping-request', { + request_id: reqNum, + sender_ip: config.NODE_IP, + sender_port: config.RPC_API_PORT + }); + + setTimeout(function () { + kademlia.stopWaitingForResponse(); + + var responses = kademlia.getPingResponses(); + + for (var i in responses) { + unirest.post('http://' + responses[i].sender_ip + ':' + responses[i].sender_port + '/import') + .headers({ + 'Content-Type': 'multipart/form-data' + }) + .field('noreplicate', true) + .attach('importfile', input_file) + .end(function (response) { + log.info('Replication response : ' + JSON.stringify(response.body)); + }); + } + }, parseInt(config.REQUEST_TIMEOUT)); + } + + }; + + return replication; +}; diff --git a/modules/sockets.js b/modules/sockets.js index 2f5444eae9..d1eee57b1f 100644 --- a/modules/sockets.js +++ b/modules/sockets.js @@ -1,84 +1,29 @@ // External modules -var product = require('./product')() -var blockchain = require('./blockchain')() -var importer = require('./importer')() -var utilities = require('./utilities')() -var io = require('socket.io')() +const io = require('socket.io')(); +const utilities = require('./utilities')(); +const log = utilities.getLogger(); +const EventHandlers = require('./EventHandlers'); // Socket communication settings // io.set('origins', 'localhost:*'); io.on('connection', function (socket) { - console.log('RPC Server connected') + log.info('RPC Server connected'); - socket.on('event', function (data) { - if (data.request == 'trail-request') { - var queryObject = data.queryObject - var clientRequest = data.clientRequest - - product.getTrailByQuery(queryObject, function (trail_graph) { - socket.emit('event', { - response: 'trail-response', - responseData: trail_graph, - clientRequest: clientRequest - }) - }) - } else if (data.request == 'import-request') { - var queryObject = data.queryObject - var clientRequest = data.clientRequest - - var input_file = queryObject.filepath - - importer.importXML(input_file, function (data) { - socket.emit('event', { - response: 'import-response', - responseData: data, - clientRequest: clientRequest - }) - }) - } else if (data.request == 'blockchain-request') { - var queryObject = data.queryObject - var owner = queryObject.owner - var batch_uid_hash = utilities.sha3(queryObject.batch_uid) - var clientRequest = data.clientRequest - - var input_file = queryObject.filepath - - blockchain.getFingerprint(owner, batch_uid_hash, function (data) { - socket.emit('event', { - response: 'blockchain-response', - responseData: data, - clientRequest: clientRequest - }) - }) - } else if (data.request == 'expiration-request') { - var queryObject = data.queryObject - var clientRequest = data.clientRequest - - product.getExpirationDates(queryObject, function (data) { - socket.emit('event', { - response: 'expiration-response', - responseData: data, - clientRequest: clientRequest - }) - }) - } else { - socket.emit('event', { - response: 'Unsupported request' - }) - } - }) -}) + socket.on('event', function (data) { + new EventHandlers(data, socket); + }); +}); module.exports = function () { - var sockets = { + var sockets = { - start: function () { - io.listen(3000) - console.log('IPC-RPC Communication server listening on port ' + 3000) - } + start: function () { + io.listen(3000); + log.info('IPC-RPC Communication server listening on port ' + 3000); + } - } + }; - return sockets -} + return sockets; +}; diff --git a/modules/storage.js b/modules/storage.js new file mode 100644 index 0000000000..4ed353b619 --- /dev/null +++ b/modules/storage.js @@ -0,0 +1,75 @@ +const utilities = require('./utilities')(); +const log = utilities.getLogger(); + +var db = require('mongodb').MongoClient; +var url = "mongodb://localhost:27017"; + +var dbo = undefined; + + + + +module.exports = function(){ + + var storage = { + storeObject: function(key, obj, callback) { + db.connect(url, function(err, db) { + dbo = db.db("origintrail"); + dbo.createCollection("ot_system", function(err, res) { + dbo.collection("ot_system").findOne({key: key}, function(err, result) { + + if (result == null) { + + dbo.collection('ot_system').insertOne({key: key, data: obj}, function(err, res) { + if (err) throw err; + utilities.executeCallback(callback, true); + }); + db.close(); + } + else + { + var query = { key: key}; + var newvalues = { $set: {key: key, data: obj } }; + dbo.collection("ot_system").updateOne(query, newvalues, function(err, res) { + if (result == null) { + utilities.executeCallback(callback, false); + db.close(); + } + else { + utilities.executeCallback(callback, true); + db.close(); + } + }); + + } + }); + + + + }); + }); + + + }, + + getObject: function(key, callback) { + db.connect(url, function(err, db) { + dbo = db.db("origintrail"); + dbo.collection("ot_system").findOne({key: key}, function(err, result) { + + if (err || result == null) { + // log.info('Storage: ' + err); + utilities.executeCallback(callback, []); + } + else { + utilities.executeCallback(callback, result.data); + } + + }); + }); + + } + }; + + return storage; +}; \ No newline at end of file diff --git a/modules/test_table.js b/modules/test_table.js new file mode 100644 index 0000000000..c2988dc68a --- /dev/null +++ b/modules/test_table.js @@ -0,0 +1,96 @@ +var utilities = require('./utilities')(); +const log = utilities.getLogger(); +var storage = require('./storage')(); + +module.exports = function () { + + var test_table = { + + insertTest: function(test, callback) + { + storage.getObject('Tests', function(response) { + + let n = response.length; + let i = n - 1; + + while(i >= 0 && response[i].test_time > test.test_time) { + i--; + } + + response.splice(i+1, 0, test); + + storage.storeObject('Tests', response, function(status){ + log.info(response); + utilities.executeCallback(callback, true); + }); + + }); + }, + + insertTests: function(tests, callback) + { + storage.getObject('Tests', function(response) { + + for(let j = 0; j < tests.length; j++) { + let n = response.length; + let i = n - 1; + while(i >= 0 && response[i].test_time > tests[j].test_time) { + i--; + } + response.splice(i+1, 0, tests[j]); + } + + storage.storeObject('Tests', response, function(status){ + utilities.executeCallback(callback, true); + }); + + }); + }, + + popNextTest: function(callback) { + storage.getObject('Tests', function(response) { + if(response.length == 0) { + utilities.executeCallback(callback, undefined); + } else { + let test = response.shift(); + + storage.storeObject('Tests', response, function(status) { + if(status == false) { + log.info('Storing tests failes!'); + utilities.executeCallback(callback, {}); + } else { + utilities.executeCallback(callback, test); + } + }); + } + }); + }, + + nextTest: function(callback) { + storage.getObject('Tests', function(response) { + if(response.length == 0) { + utilities.executeCallback(callback, {}); + } else { + let test = response[0]; + + utilities.executeCallback(callback, test); + } + }); + }, + + getTests: function(callback) { + storage.getObject('Tests', function(response) { + // log.info(response); + if(response.length == 0) { + log.info('There are no planed tests'); + utilities.executeCallback(callback, []); + } else { + utilities.executeCallback(callback, response); + } + }); + } + }; + + return test_table; + +}; diff --git a/modules/testing.js b/modules/testing.js new file mode 100644 index 0000000000..c601365f62 --- /dev/null +++ b/modules/testing.js @@ -0,0 +1,92 @@ +var utilities = require('./utilities')(); +var config = utilities.getConfig(); +const log = utilities.getLogger(); +var test_table = require('./test_table')(); +var encryption = require('./encryption')(); +var graph = require('./graph')(); +var async = require('async'); + +module.exports = function () { + + var testing = { + generateTests: function(data_id, dh_ip, dh_port, dh_wallet, encrypted_vertices, number_of_tests, start_time, end_time, callback) { + //log.info('[DH] Encrypted vertices:'); + //log.info(encrypted_vertices); + var tests = []; + + for(let i = 0; i < number_of_tests; i++) { + + let new_test = {}; + + let j = utilities.getRandomIntRange(0,encrypted_vertices.length - 1); + //log.error('Random number: ' + j); + let test_vertex = encrypted_vertices[j]; + let test_vertex_data = test_vertex.data; + + let start_index = 0; + let end_index = 0; + + start_index = utilities.getRandomIntRange(0,test_vertex_data.length -1); + end_index = utilities.getRandomIntRange(start_index, test_vertex_data.length -1); + + let question = {vertex_key: test_vertex._key, start_index: start_index, end_index: end_index}; + let answer = test_vertex_data.substring(start_index, end_index); + + new_test.question = question; + new_test.answer = answer; + new_test.dh_ip = dh_ip; + new_test.dh_port = dh_port; + new_test.dc_ip = config.NODE_IP; + new_test.dc_port = config.NODE_PORT; + new_test.dh_wallet = dh_wallet; + new_test.data_id = data_id; + + if(i == number_of_tests - 1) + { + new_test.test_time = end_time; + } else { + new_test.test_time = utilities.getRandomIntRange(start_time, end_time - 1); + } + + tests.push(new_test); + } + + test_table.insertTests(tests, function(response) { + utilities.executeCallback(callback, response); + }); + }, + + answerQuestion: function(test, callback) { + var question = test.question; + let start_index = question.start_index; + let end_index = question.end_index; + let vertex_key = question.vertex_key; + + // console.log('VERTEX_KEY',vertex_key); + + graph.getVertices({_key: vertex_key}, function(response) { + + let vertex = response[0]; + + if(vertex == undefined || vertex.data == undefined) + { + utilities.executeCallback(callback, 'MISSING_DATA'); + return; + } + else + { + let vertex_data = vertex.data; + + let answer = vertex_data.substring(start_index, end_index); + + utilities.executeCallback(callback, answer); + } + }); + + } + + }; + + return testing; + +}; \ No newline at end of file diff --git a/modules/utilities.js b/modules/utilities.js index 50700b669f..39c4ef00d8 100644 --- a/modules/utilities.js +++ b/modules/utilities.js @@ -2,18 +2,27 @@ var config = require('./config'); var ipaddr = require('ipaddr.js'); var sha3 = require('solidity-sha3').default; +// eslint-disable-next-line no-unused-vars var net = require('net'); +// eslint-disable-next-line no-unused-vars var natpmp = require('nat-pmp'); +var _ = require('lodash'); +const log = require('winston'); +log.add(log.transports.File, { filename: 'log.log', colorize: true, prettyPrint: true }); +log.remove(log.transports.Console); +log.add(log.transports.Console, {colorize: true}); module.exports = function () { + var utilities = { + executeCallback: function executeCallback (callback, callback_input) { if (typeof callback === 'function') { callback(callback_input); } else { - console.log('Callback not defined!'); + log.info('Callback not defined!'); } }, @@ -26,7 +35,7 @@ module.exports = function () { }, getRandomInt: function (max) { - return Math.floor(Math.random() * Math.floor(max)); + return _.random(0, max); }, sha3: function (value) { @@ -65,6 +74,14 @@ module.exports = function () { return sortedObj; }, + + getRandomIntRange: function (min, max) { + return _.random(min,max); + }, + + getLogger() { + return log; + } }; return utilities; diff --git a/package.json b/package.json index 0be9d4c51b..2514792d41 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,25 @@ { "name": "ot-node", - "version": "0.1.0", - "auto-updater":{ - "repo":"OriginTrail/ot-node", - "branch":"master" + "version": "0.3.0", + "auto-updater": { + "repo": "OriginTrail/ot-node", + "branch": "master" }, "description": "OriginTrail node", "main": "gulpfile.js", "dependencies": { + "@garbados/merkle-tree": "^1.0.3-alpha", "ajv": "^6.2.0", "aql": "0.0.3-alpha", "arangojs": "^6.1.0", "async": "^2.6.0", "auto-updater": "^1.0.2", + "axios": "^0.18.0", + "bn": "^1.0.1", + "concurrently": "^3.5.1", "dotenv": "^5.0.0", "eth-lightwallet": "^3.0.1", + "ethereumjs-abi": "^0.6.5", "ethereumjs-tx": "^1.3.3", "ethereumjs-util": "^5.1.4", "ipaddr.js": "^1.6.0", @@ -22,15 +27,20 @@ "kad-quasar": "^2.1.0", "leveldown": "^3.0.0", "levelup": "^2.0.2", + "lodash": "^4.17.5", + "mongodb": "^3.0.4", "nat-pmp": "^1.0.0", "nat-upnp": "^1.1.1", + "node-rsa": "^0.4.2", "python-shell": "^0.5.0", "restify": "^6.3.4", "snyk": "^1.69.7", "socket.io": "^2.0.4", "solidity-sha3": "^0.4.1", "tcp-port-used": "^0.1.2", - "unirest": "^0.5.1" + "unirest": "^0.5.1", + "web3": "^1.0.0-beta.30", + "winston": "^2.4.0" }, "devDependencies": { "eslint": "^4.17.0", @@ -41,8 +51,7 @@ }, "scripts": { "test": "nyc mocha --recursive test", - "snyk-protect": "snyk protect", - "prepare": "npm run snyk-protect" + "start": "sudo systemctl start mongod && concurrently -n IPC,RPC -c magenta,yellow \"node ipc\" \"node rpc\" --kill-others --prefix \"{name}\"" }, "repository": { "type": "git", diff --git a/rpc.js b/rpc.js index 6a8a81fbb7..236a03dcf3 100644 --- a/rpc.js +++ b/rpc.js @@ -6,29 +6,44 @@ var replication = require('./modules/replication')(); var io = require('socket.io-client')('http://localhost:3000'); var config = utilities.getConfig(); var natUpnp = require('nat-upnp'); - +const log = utilities.getLogger(); // Active requests pool var socketRequests = {}; +/** + * Start testing mechanism as a separate thread + */ + +const { fork } = require('child_process'); +const forked = fork('./modules/SendTest.js'); + +// forked.on('message', (msg) => { +// log.info('Test sent', msg); +// }); + + // Socket communication configuration for RPC client // ================================================= var socket = io.connect('http://localhost:3000', { reconnect: true }); socket.on('connect', function () { - console.log('Socket connected to IPC-RPC Communication server on port ' + 3000); + log.info('Socket connected to IPC-RPC Communication server on port ' + 3000); }); socket.on('event', function (data) { var reqNum = data.clientRequest; socketRequests[reqNum].send(data.responseData); + //console.log('data',data); + //console.log('data.responseData',data.responseData); + // Free request slot delete socketRequests[reqNum]; }); socket.on('disconnect', function () { - console.log('IPC-RPC Communication disconnected'); + log.info('IPC-RPC Communication disconnected'); }); // ================================================= @@ -65,7 +80,6 @@ server.get('/api/trail/batches', function (req, res) { while (socketRequests[reqNum] != undefined) { utilities.getRandomInt(10000000000); } - socketRequests[reqNum] = res; socket.emit('event', { request: 'trail-request', @@ -122,11 +136,94 @@ server.get('/api/blockchain/check', function (req, res) { clientRequest: reqNum }); }); + + +/* +* Imports data for replication +* Method: post +* +* @param json payload +*/ + +server.post('/api/replication', function (req, res) { + let queryObject = req.body; + + //TODO: extract this as it repeats + var reqNum = utilities.getRandomInt(10000000000); + + while (socketRequests[reqNum] != undefined) { + utilities.getRandomInt(10000000000); + } + + socketRequests[reqNum] = res; + + socket.emit('event', { + request: 'replication-request', + queryObject: queryObject, + clientRequest: reqNum + }); +}); + +/** + * Receive test request + * Method: post + * + * @param json test + */ + +server.post('/api/testing', function (req, res) { + + let queryObject = req.body; + + var reqNum = utilities.getRandomInt(10000000000); + + while (socketRequests[reqNum] != undefined) { + utilities.getRandomInt(10000000000); + } + + socketRequests[reqNum] = res; + + socket.emit('event', { + request: 'testing-request', + queryObject: queryObject, + clientRequest: reqNum + }); +}); + +/** + * Receive receipt + * Method: post + * + * @param json receipt + */ + +server.post('/api/receipt', function (req, res) { + + let queryObject = req.body; + + var reqNum = utilities.getRandomInt(10000000000); + + while (socketRequests[reqNum] != undefined) { + utilities.getRandomInt(10000000000); + } + + socketRequests[reqNum] = res; + + socket.emit('event', { + request: 'receipt-request', + queryObject: queryObject, + clientRequest: reqNum + }); +}); + // ============================ // Remote data import route // ======================== server.post('/import', function (req, res) { + + log.info('[DC] Import request received!'); + var request_ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; var remote_access = utilities.getConfig().REMOTE_ACCESS; @@ -153,11 +250,11 @@ server.post('/import', function (req, res) { var input_file = req.files.importfile.path; var reqNum = utilities.getRandomInt(10000000000); - +/* if (req.body.noreplicate == undefined) { replication.replicate(input_file); } - +*/ socketRequests[reqNum] = res; var queryObject = { filepath: input_file @@ -175,55 +272,52 @@ server.post('/import', function (req, res) { if(config.NODE_IP == '127.0.0.1') { var client = natUpnp.createClient(); - client.portMapping({ - public: config.RPC_API_PORT, - private: config.RPC_API_PORT, - ttl: 0, + public: config.RPC_API_PORT, + private: config.RPC_API_PORT, + ttl: 0, }, function(err) { if(err) { - console.log(err) + log.info(err); } else { - console.log("uPnP port mapping enabled, port: " + config.RPC_API_PORT) + log.info('uPnP port mapping enabled, port: ' + config.RPC_API_PORT); } }); client.portMapping({ - public: config.KADEMLIA_PORT, - private: config.KADEMLIA_PORT, - ttl: 0, + public: config.KADEMLIA_PORT, + private: config.KADEMLIA_PORT, + ttl: 0, }, function(err) { if(err) { - console.log(err) + log.info(err); } else { - console.log("uPnP port mapping enabled, port: " + config.KADEMLIA_PORT) + log.info('uPnP port mapping enabled, port: ' + config.KADEMLIA_PORT); } }); client.externalIp(function(err, ip) { - config.NODE_IP = ip - console.log(ip) - kademlia.start(); + config.NODE_IP = ip; + log.info(ip); + kademlia.start(); - server.listen(parseInt(config.RPC_API_PORT), function () { - console.log('%s listening at %s', server.name, server.url); + server.listen(parseInt(config.RPC_API_PORT), function () { + log.info('%s listening at %s', server.name, server.url); }); }); } else { - kademlia.start() + kademlia.start(); server.listen(parseInt(config.RPC_API_PORT), function () { - console.log('%s listening at %s', server.name, server.url); -}); -} - - + log.info('%s listening at %s', server.name, server.url); + }); +} \ No newline at end of file diff --git a/test/modules/utilities.test.js b/test/modules/utilities.test.js index e609062a9a..1e7abba0ec 100644 --- a/test/modules/utilities.test.js +++ b/test/modules/utilities.test.js @@ -1,7 +1,11 @@ 'use strict'; +const {describe, it} = require('mocha'); +// eslint-disable-next-line no-unused-vars const should = require('should'); -const reuest = require('supertest'); +// eslint-disable-next-line no-unused-vars +const request = require('supertest'); const utilities = require('../../modules/utilities')(); +// eslint-disable-next-line no-unused-vars const config = utilities.getConfig(); @@ -37,12 +41,19 @@ describe('The Utilities', () => { number.should.be.belowOrEqual(10); }); + it('should return random number in range min - max', () => { + let number = utilities.getRandomIntRange(8,17); + number.should.be.aboveOrEqual(8, "Number should be >= then min"); + number.should.be.belowOrEqual(17, "Number should be <= then max"); + }); + it('should return true if two IP addresses are the same', () => { let ip1 = '127.0.0.1'; let ip2 = '127.0.0.1'; let result = utilities.isIpEqual(ip1, ip2); result.should.be.true; }); + it('should return false if two IP addresses are not the same', () => { let ip1 = '127.0.0.1'; let ip2 = '192.168.0.0'; @@ -50,5 +61,8 @@ describe('The Utilities', () => { result.should.be.false; }); - + it('should return copied object', ()=> { + let obj1 = { "name":"Mike", "age":30, "city":"New York"}; + obj1.should.be.deepEqual(utilities.copyObject(obj1)); + }); }); \ No newline at end of file diff --git a/update.js b/update.js index d7fd4cf198..79b8c0007b 100644 --- a/update.js +++ b/update.js @@ -12,7 +12,7 @@ var autoupdater = new AutoUpdater({ // State the events autoupdater.on('git-clone', function() { - console.log("You have a clone of the repository. Use 'git pull' to be up-to-date"); + log.info("You have a clone of the repository. Use 'git pull' to be up-to-date"); }); autoupdater.on('check.up-to-date', function(v) { console.info("You have the latest version: " + v); @@ -23,31 +23,31 @@ autoupdater.on('check.out-dated', function(v_old, v) { // Maybe ask if the'd like to download the update. }); autoupdater.on('update.downloaded', function() { - console.log("Update downloaded and ready for install"); + log.info("Update downloaded and ready for install"); autoupdater.fire('extract'); // If autoupdate: false, you'll have to do this manually. }); autoupdater.on('update.not-installed', function() { - console.log("The Update was already in your folder! It's read for install"); + log.info("The Update was already in your folder! It's read for install"); autoupdater.fire('extract'); // If autoupdate: false, you'll have to do this manually. }); autoupdater.on('update.extracted', function() { - console.log("Update extracted successfully!"); + log.info("Update extracted successfully!"); console.warn("RESTART THE APP!"); }); autoupdater.on('download.start', function(name) { - console.log("Starting downloading: " + name); + log.info("Starting downloading: " + name); }); autoupdater.on('download.progress', function(name, perc) { process.stdout.write("Downloading " + perc + "% \033[0G"); }); autoupdater.on('download.end', function(name) { - console.log("Downloaded " + name); + log.info("Downloaded " + name); }); autoupdater.on('download.error', function(err) { console.error("Error when downloading: " + err); }); autoupdater.on('end', function() { - console.log("The app is ready to function"); + log.info("The app is ready to function"); }); autoupdater.on('error', function(name, e) { console.error(name, e);