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
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+
+
+
+
+
+
+
+
+
+
+ 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);