Ver Fonte

Added basic RPC implementation

DebenOldert há 4 anos atrás
pai
commit
6e87a75239
9 ficheiros alterados com 163 adições e 44 exclusões
  1. 0 0
      gui/__init__.py
  2. 29 0
      gui/main.py
  3. 15 1
      lib/block.py
  4. 3 0
      lib/chain.py
  5. 6 2
      lib/contract.py
  6. 0 2
      lib/rpc.py
  7. 6 0
      lib/service.py
  8. 13 1
      lib/transaction.py
  9. 91 38
      main.py

+ 0 - 0
gui/__init__.py


+ 29 - 0
gui/main.py

@@ -0,0 +1,29 @@
+import time
+
+import rpyc
+
+from lib.contract import Contract
+from lib.transaction import Transaction
+
+if __name__ == '__main__':
+    conn = rpyc.connect(host='localhost', port=42069, keepalive=True)
+
+    # Create a new contract
+    contract1 = Contract()
+    contract1.create(title='Digital legal handshake',
+                     desc='Hereby you declare to fulfill the following terms',
+                     deadline=int(time.time()),
+                     price=420.69)
+
+    # Create a new term
+    term1 = Contract.Term()
+    term1.create(title='U gotta work',
+                 desc='Finish this',
+                 deadline=int(time.time()))
+
+    # Add term to contract1
+    contract1.add_term(term=term1)
+
+    conn.root.push_contract(contract1.serialize(out_json=True))
+
+    conn.close()

+ 15 - 1
lib/block.py

@@ -4,8 +4,21 @@ import time
 
 from lib.transaction import Transaction
 
+CURRENT = None
+
 
 class Block:
+    class Current:
+        @staticmethod
+        def set(block):
+            global CURRENT
+            CURRENT = block
+
+        @staticmethod
+        def get():
+            global CURRENT
+            return CURRENT
+
     def __init__(self, previous=None):
         self.proof = None
         self.previous_hash = previous.hash_value if previous is not None else None
@@ -13,6 +26,7 @@ class Block:
         self.hash_value = None
         self.locked = False
         self.timestamp = 0
+        self.height = previous.height + 1 if previous is not None else 0
 
     def add_transaction(self, trans: Transaction):
         if not self.locked:
@@ -58,4 +72,4 @@ class Block:
         return hex_hash
 
     def log(self, text):
-        print(f'[ BLOCK ] {text}')
+        print(f'[ BLOCK ] {text}')

+ 3 - 0
lib/chain.py

@@ -10,3 +10,6 @@ class Chain:
 
     def last_block(self):
         return self.blocks[-1]
+
+    def get_height(self):
+        return self.last_block().height

+ 6 - 2
lib/contract.py

@@ -30,7 +30,7 @@ class Contract(object):
                 return True
             return False
 
-        def serialize(self):
+        def serialize(self, out_json=False):
             obj = {
                 '@type': 'term',
                 'id': self.id,
@@ -39,6 +39,8 @@ class Contract(object):
                 'deadline': self.deadline
             }
             self.log('Serialized')
+            if out_json:
+                json.dumps(obj, sort_keys=True)
             return obj
 
         def log(self, text):
@@ -84,7 +86,7 @@ class Contract(object):
             return True
         return False
 
-    def serialize(self):
+    def serialize(self, out_json=False):
         # TODO: Add all properties
         term_serialize = []
         for term in self.terms:
@@ -95,6 +97,8 @@ class Contract(object):
             'terms': term_serialize
         }
         self.log(f'Serialized: {len(term_serialize)} terms')
+        if out_json:
+            return json.dumps(obj, sort_keys=True)
         return obj
 
     def log(self, text):

+ 0 - 2
lib/rpc.py

@@ -1,2 +0,0 @@
-class RPC:
-    pass

+ 6 - 0
lib/service.py

@@ -0,0 +1,6 @@
+import rpyc
+
+from lib.block import CURRENT
+
+
+

+ 13 - 1
lib/transaction.py

@@ -1,6 +1,7 @@
 import hashlib
 import json
 import time
+import uuid
 
 from lib.contract import Contract
 
@@ -13,20 +14,31 @@ class Transaction:
         self.locked = False
         self.timestamp = 0
 
+    def set_serialized_contract(self, serialized):
+        if not self.locked:
+            self.id = str(uuid.uuid1())
+            self.data = serialized
+            self.log('Serialized contract set')
+            return True
+        return False
+
     def set_contract(self, contract: Contract):
         if not self.locked:
+            self.id = str(uuid.uuid1())
             self.data = contract.serialize()
             self.log(f'Contract set: {contract.id} | {contract.title}')
             return True
         return False
 
-    def serialize(self):
+    def serialize(self, out_json=False):
         obj = {
             'id': self.id,
             'timestamp': self.timestamp,
             'data': self.data
         }
         self.log(f'Serialized')
+        if out_json:
+            return json.dumps(obj, sort_keys=True)
         return obj
 
     def lock_hash_finish(self):

+ 91 - 38
main.py

@@ -1,67 +1,120 @@
 import time
-from rpyc.utils.server import ThreadedServer
+
+import rpyc
+from rpyc.utils.server import ThreadPoolServer
+import argparse
+import threading
 
 from lib.chain import Chain, Block
-from lib.rpc import RPC
 from lib.transaction import Transaction
 from lib.contract import Contract
+from lib.block import CURRENT
+
+
 
 if __name__ == '__main__':
-    # Initialize the chain (Creates empty chain)
-    chain = Chain()
+    parser = argparse.ArgumentParser(description='DSP Blockchain')
+    mode = parser.add_mutually_exclusive_group()
+    mode.add_argument('--daemon', action='store_true', help='Run in daemon mode')
+    mode.add_argument('--gui', action='store_true', help='Run in GUI mode')
+
+    parser.add_argument('--static', action='store_true', help='Test run the static chain')
+
+    args = parser.parse_args()
+
+    if args.gui:
+        print('Not yest implemented')
+        exit(1)
 
     # Initialize the genesis block
     initial = Block()
     initial.previous_hash = 'This is the founding block for our DSP project'
     initial.proof = 69
 
-    # Lock block
-    initial.lock_hash_finish()
+    if args.static:
+        # Initialize the chain (Creates empty chain)
+        chain = Chain()
+
+        # Lock block
+        initial.lock_hash_finish()
+
+        # Add the genesis block to the chain
+        chain.add_block(block=initial)
+
+        # Chain work starts from here
+
+        # Static chain interaction
+        block1 = Block(previous=initial)
+
+        # Create a new contract
+        contract1 = Contract()
+        contract1.create(title='Digital legal handshake',
+                         desc='Hereby you declare to fulfill the following terms',
+                         deadline=int(time.time()),
+                         price=420.69)
+
+        # Create a new term
+        term1 = Contract.Term()
+        term1.create(title='U gotta work',
+                     desc='Finish this',
+                     deadline=int(time.time()))
+
+        # Add term to contract1
+        contract1.add_term(term=term1)
+
+        # Bind contract to transaction
+        transaction1 = Transaction()
+        transaction1.set_contract(contract=contract1)
+
+        # Add transaction to current block
+        block1.add_transaction(trans=transaction1)
+
+        # Finish block and all its transactions
+        block1.lock_hash_finish()
 
-    # Add the genesis block to the chain
-    chain.add_block(block=initial)
+        block2 = Block(previous=block1)
+        exit(0)
+    else:
+        chain = Chain()
+        CURRENT = initial
 
-    # Chain work starts from here
+        class Looper(threading.Thread):
+            def __init__(self):
+                super(Looper, self).__init__()
 
-    # Static chain interaction
-    block1 = Block(previous=initial)
+            def run(self):
+                global CURRENT
+                while True:
+                    print(f'[ THR ] Wait for new block')
+                    time.sleep(10)
+                    print(f'[ THR ] Work on new block. Height: {CURRENT.height}')
+                    CURRENT.lock_hash_finish()
+                    CURRENT = Block(previous=CURRENT)
 
-    # Create a new contract
-    contract1 = Contract()
-    contract1.create(title='Digital legal handshake',
-                     desc='Hereby you declare to fulfill the following terms',
-                     deadline=int(time.time()),
-                     price=420.69)
 
-    # Create a new term
-    term1 = Contract.Term()
-    term1.create(title='U gotta work',
-                 desc='Finish this',
-                 deadline=int(time.time()))
+        class Service(rpyc.Service):
+            def exposed_get_current_block(self):
+                global CURRENT
+                return CURRENT
 
-    # Add term to contract1
-    contract1.add_term(term=term1)
+            def exposed_push_contract(self, contract):
+                global CURRENT
+                trans = Transaction()
+                trans.set_serialized_contract(contract)
+                return CURRENT.add_transaction(trans=trans)
 
-    # Bind contract to transaction
-    transaction1 = Transaction()
-    transaction1.set_contract(contract=contract1)
 
-    # Add transaction to current block
-    block1.add_transaction(trans=transaction1)
+        # Start the RPC server to listen for GUI instances
+        server = ThreadPoolServer(Service, port=42069, protocol_config={'allow_public_attrs': True})
 
-    # Finish block and all its transactions
-    block1.lock_hash_finish()
+        looper = Looper()
+        looper.start()
 
-    block2 = Block(previous=block1)
+        print(f'[ RPC ] Started')
+        server.start()
 
-    server = ThreadedServer(RPC, port=42069)
-    server.start()
 
 
-    # Create a loop that starts to sleep for 10 seconds / mocking a 10 second block time
-    while True:
-        # Wait 10 seconds
-        time.sleep(10)
 
 # Possible TODO's:
 # * Upon adding transaction to block check if transaction is already locked