miner.py 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #!/usr/bin/env python3
  2. """
  3. The executable that participates in the P2P network and optionally mines new blocks. Can be reached
  4. through a REST API by the wallet.
  5. """
  6. __all__ = []
  7. import argparse
  8. from urllib.parse import urlparse
  9. from typing import Tuple
  10. import logging
  11. logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)-8s %(message)s")
  12. from src.config import *
  13. from src.crypto import Key
  14. from src.protocol import Protocol
  15. from src.blockchain import GENESIS_BLOCK
  16. from src.chainbuilder import ChainBuilder
  17. from src.mining import Miner
  18. from src.persistence import Persistence
  19. from src.rpc_server import rpc_server
  20. def parse_addr_port(val: str) -> Tuple[str, int]:
  21. """ Parse a user-specified `host:port` value to a tuple. """
  22. url = urlparse("//" + val)
  23. assert url.scheme == ''
  24. assert url.path == ''
  25. assert url.params == ''
  26. assert url.query == ''
  27. assert url.fragment == ''
  28. assert url.port is not None
  29. assert url.hostname is not None
  30. return (url.hostname, url.port)
  31. def main():
  32. """
  33. Takes arguments:
  34. `listen-address`: The IP address where the P2P server should bind to. Default is: `\"\"`
  35. `listen-port`: The port where the P2P server should listen. Defaults a dynamically assigned port. Default is: `0`
  36. `mining-pubkey`: The public key where mining rewards should be sent to. No mining is performed if this is left unspecified.
  37. `bootstrap-peer`: Addresses of other P2P peers in the network. Default is: `[]`
  38. `rpc-port`: The port number where the wallet can find an RPC server. Default is: `40203`
  39. `persist-path`: The file where data is persisted.
  40. """
  41. parser = argparse.ArgumentParser(description="Blockchain Miner.")
  42. parser.add_argument("--listen-address", default="",
  43. help="The IP address where the P2P server should bind to.")
  44. parser.add_argument("--listen-port", default=0, type=int,
  45. help="The port where the P2P server should listen. Defaults a dynamically assigned port.")
  46. parser.add_argument("--mining-pubkey", type=argparse.FileType('rb'),
  47. help="The public key where mining rewards should be sent to. No mining is performed if this is left unspecified.")
  48. parser.add_argument("--bootstrap-peer", action='append', type=parse_addr_port, default=[],
  49. help="Addresses of other P2P peers in the network.")
  50. parser.add_argument("--rpc-port", type=int, default=40203,
  51. help="The port number where the wallet can find an RPC server.")
  52. parser.add_argument("--persist-path",
  53. help="The file where data is persisted.")
  54. args = parser.parse_args()
  55. proto = Protocol(args.bootstrap_peer, GENESIS_BLOCK, args.listen_port, args.listen_address)
  56. if args.mining_pubkey is not None:
  57. pubkey = Key(args.mining_pubkey.read())
  58. args.mining_pubkey.close()
  59. miner = Miner(proto, pubkey)
  60. miner.start_mining()
  61. chainbuilder = miner.chainbuilder
  62. else:
  63. chainbuilder = ChainBuilder(proto)
  64. if args.persist_path:
  65. persist = Persistence(args.persist_path, chainbuilder)
  66. try:
  67. persist.load()
  68. except FileNotFoundError:
  69. pass
  70. else:
  71. persist = None
  72. rpc_server(args.rpc_port, chainbuilder, persist)
  73. def start_listener(rpc_port: int, bootstrap_peer: str, listen_port: int, listen_address: str):
  74. """ Starts the RPC Server and initializes the protocol. """
  75. proto = Protocol([parse_addr_port(bootstrap_peer)], GENESIS_BLOCK, listen_port, listen_address)
  76. chainbuilder = ChainBuilder(proto)
  77. rpc_server(rpc_port, chainbuilder, None)
  78. if __name__ == '__main__':
  79. main()