Forráskód Böngészése

start implementing a wallet

Malte Kraus 8 éve
szülő
commit
d5db126211
5 módosított fájl, 91 hozzáadás és 5 törlés
  1. 38 5
      miner.py
  2. 6 0
      requirements.txt
  3. 4 0
      src/crypto.py
  4. 1 0
      src/protocol.py
  5. 42 0
      wallet.py

+ 38 - 5
miner.py

@@ -2,9 +2,17 @@
 
 import argparse
 from urllib.parse import urlparse
+
+import flask
+import json
+app = flask.Flask(__name__)
+
 from src.crypto import Signing
 from src.protocol import Protocol
 from src.block import GENESIS_BLOCK
+from src.chainbuilder import ChainBuilder
+from src.mining import Miner
+from src.transaction import TransactionInput
 
 def parse_addr_port(val):
     url = urlparse("//" + val)
@@ -17,6 +25,29 @@ def parse_addr_port(val):
     assert url.hostname is not None
     return (url.hostname, url.port)
 
+def rpc_server(port, chainbuilder):
+
+    @app.route("/transactions", methods=['POST'])
+    def get_transactions_for_key():
+        key = Signing(flask.request.data)
+        transactions = set()
+        outputs = set()
+        for b in chainbuilder.primary_block_chain.blocks:
+            for t in b.transactions:
+                for i, target in enumerate(t.targets):
+                    if target.recipient_pk == key:
+                        transactions.add(t)
+                        outputs.add(TransactionInput(t.get_hash(), i))
+        for b in chainbuilder.primary_block_chain.blocks:
+            for t in b.transactions:
+                for inp in t.inputs:
+                    if inp in outputs:
+                        transactions.add(t)
+
+        return json.dumps([t.to_json_compatible() for t in transactions])
+
+    app.run(port=port)
+
 def main():
     parser = argparse.ArgumentParser(description="Blockchain Miner.")
     parser.add_argument("--listen-address", default="",
@@ -25,8 +56,10 @@ def main():
                         help="The port where the P2P server should listen. Defaults a dynamically assigned port.")
     parser.add_argument("--mining-pubkey", type=argparse.FileType('rb'),
                         help="The public key where mining rewards should be sent to. No mining is performed if this is left unspecified.")
-    parser.add_argument("--bootstrap-peer", action='append', type=parse_addr_port,
+    parser.add_argument("--bootstrap-peer", action='append', type=parse_addr_port, default=[],
                         help="Addresses of other P2P peers in the network.")
+    parser.add_argument("--rpc-port", type=int, default=40203,
+                        help="The port number where the wallet can find an RPC server.")
 
     args = parser.parse_args()
 
@@ -36,11 +69,11 @@ def main():
         args.mining_pubkey.close()
         miner = Miner(proto, pubkey)
         miner.start_mining()
+        chainbuilder = miner.chainbuilder
+    else:
+        chainbuilder = ChainBuilder(proto)
 
-    # TODO: start RPC
-    import time
-    while True:
-        time.sleep(2**31)
+    rpc_server(args.rpc_port, chainbuilder)
 
 if __name__ == '__main__':
     main()

+ 6 - 0
requirements.txt

@@ -1,9 +1,13 @@
 alabaster==0.7.10
 Babel==2.3.4
+click==6.7
 docutils==0.13.1
+Flask==0.12
 imagesize==0.7.1
+itsdangerous==0.24
 Jinja2==2.9.5
 MarkupSafe==0.23
+pudb==2017.1.1
 pycrypto==2.6.1
 Pygments==2.2.0
 pytz==2016.10
@@ -12,3 +16,5 @@ six==1.10.0
 snowballstemmer==1.2.1
 Sphinx==1.5.3
 treelib==1.3.5
+urwid==1.3.1
+Werkzeug==0.12

+ 4 - 0
src/crypto.py

@@ -50,3 +50,7 @@ class Signing:
             return self.rsa.exportKey()
         else:
             return self.rsa.publickey().exportKey()
+
+    def __eq__(self, other):
+        # TODO: it's possible that the same key has multiple different representations
+        return self.as_bytes() == other.as_bytes()

+ 1 - 0
src/protocol.py

@@ -160,6 +160,7 @@ class PeerConnection:
 class SocketServer(socketserver.TCPServer):
     allow_reuse_address = True
     def serve_forever_bg(self):
+        logging.info("listening on %s", self.server_address)
         Thread(target=self.serve_forever, daemon=True).start()
 
     def close_request(self, request):

+ 42 - 0
wallet.py

@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+
+import argparse
+import requests
+
+from binascii import hexlify, unhexlify
+
+from src.blockchain import Blockchain
+from src.block import Block
+from src.transaction import Transaction
+from src.crypto import Signing
+
+def send_transaction(sess, url, transaction):
+    resp = sess.put(url + 'new-transaction', data=transaction.to_json_compatible())
+    resp.raise_for_status()
+
+def network_state(sess, url):
+    pass
+
+def get_transactions(sess, url, pubkey):
+    resp = sess.post(url + 'transactions', data=pubkey.as_bytes())
+    resp.raise_for_status()
+    return [Transaction.from_json_compatible(t) for t in resp.json()]
+
+def main():
+    parser = argparse.ArgumentParser(description="Wallet.")
+    parser.add_argument("--miner-port", default=40203, type=int,
+                        help="The RPC port of the miner to connect to.")
+    parser.add_argument("--show-transactions", type=argparse.FileType("rb"), default=[], action="append",
+                        help="Shows all transactions involving the public key stored in the specified file.")
+    args = parser.parse_args()
+
+    url = "http://localhost:{}/".format(args.miner_port)
+    s = requests.session()
+
+    for key in args.show_transactions:
+        for trans in get_transactions(s, url, Signing(key.read())):
+            print(trans.to_json_compatible())
+        key.close()
+
+if __name__ == '__main__':
+    main()