def main(): loop = asyncio.get_event_loop() # because a KeyboardInterrupt is so violent it can shutdown the DB in an unpredictable state. loop.add_signal_handler(SIGINT, system_exit) main_task = loop.create_task(setup_and_start(loop)) try: loop.run_forever() except SystemExit: p2p = NetworkService() loop.run_until_complete(p2p.shutdown()) loop.run_until_complete(shutdown()) loop.run_until_complete(loop.shutdown_asyncgens()) loop.stop() finally: loop.close() logger.info("Closing databases...") NotificationDB.close() Blockchain.Default().Dispose() wallet = main_task.result() if wallet: wallet.Close()
def tearDownClass(cls): # tear down Blockchain DB Blockchain.Default().DeregisterBlockchain() if cls._blockchain is not None: cls._blockchain.UT = False cls._blockchain.Dispose() shutil.rmtree(cls.leveldb_testpath()) # tear down Notification DB NotificationDB.instance().close() shutil.rmtree(cls.N_NOTIFICATION_DB_NAME)
def test_2_persist_isnt_notify_event(self): sc = SmartContractEvent(SmartContractEvent.RUNTIME_NOTIFY, ContractParameter(ContractParameterType.Array, []), self.contract_hash, 99, self.event_tx, True, False) ndb = NotificationDB.instance() ndb.on_smart_contract_event(sc) self.assertEqual(ndb.current_events, [])
def test_8_lookup_should_be_empty(self): ndb = NotificationDB.instance() events = ndb.get_by_block(123) self.assertEqual(len(events), 0)
def test_4_notification_lookup(self): ndb = NotificationDB.instance() events = ndb.get_by_block(91349) self.assertEqual(len(events), 1)
def test_9_lookup_should_be_empty(self): ndb = NotificationDB.instance() sh = UInt160(data=b')\x96S\xb5\xe3e\xcb3\xb4\xea:\xd1\xd7\xe1\xb3\xf5\xe6\x82N/') events = ndb.get_by_addr(sh) self.assertEqual(len(events), 0)
def test_7_lookup_addr_by_script_hash(self): ndb = NotificationDB.instance() sh = UInt160(data=b')\x96S\xb5\xe3e\xcb3\xb4\xea:\xd1\xd7\xe1\xb3\xf5\xe6\x81N/') events = ndb.get_by_addr(sh) self.assertEqual(len(events), 1)
def test_5_addr_from_lookup(self): ndb = NotificationDB.instance() events = ndb.get_by_addr('ALb8FEhEmtSqv97fuNVuoLmcmrSKckffRf') self.assertEqual(len(events), 1) evt = events[0] # type:NotifyEvent self.assertEqual(evt.AddressTo, 'ALb8FEhEmtSqv97fuNVuoLmcmrSKckffRf')
def test_6_addr_to_lookup(self): ndb = NotificationDB.instance() events = ndb.get_by_addr('AKZmSGPD7ytJBbxpRPmobYGLNxdWH3Jiqs') self.assertEqual(len(events), 1) evt = events[0] # type:NotifyEvent self.assertEqual(evt.AddressFrom, 'AKZmSGPD7ytJBbxpRPmobYGLNxdWH3Jiqs')
def token_history(wallet, token_str): notification_db = NotificationDB.instance() try: token = PromptUtils.get_token(wallet, token_str) except ValueError: raise events = notification_db.get_by_contract(token.ScriptHash) return token, events
def execute(self, arguments): if NotificationDB.instance() is None: print("No notification DB Configured") return item = get_arg(arguments) if item is not None: if item[0:2] == "0x": item = item[2:] if len(item) == 34 and item[0] == 'A': events = NotificationDB.instance().get_by_addr(item) elif len(item) == 40: events = NotificationDB.instance().get_by_contract(item) else: try: block_height = int(item) if block_height < Blockchain.Default().Height: events = NotificationDB.instance().get_by_block( block_height) else: print("Block %s not found" % block_height) return except Exception: print("Could not find notifications from args: %s" % arguments) return if len(events): [print(json.dumps(e.ToJson(), indent=4)) for e in events] return events else: print("No events found for %s" % item) return else: print("Please specify the required parameter") return
def test_3_should_persist(self): payload = ContractParameter(ContractParameterType.Array, [ ContractParameter(ContractParameterType.String, b'transfer'), ContractParameter(ContractParameterType.ByteArray, self.addr_to), ContractParameter(ContractParameterType.ByteArray, self.addr_from), ContractParameter(ContractParameterType.Integer, 123000) ]) sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, self.contract_hash, 91349, self.event_tx, True, False) ndb = NotificationDB.instance() ndb.on_smart_contract_event(sc) self.assertEqual(len(ndb.current_events), 1) ndb.on_persist_completed(None)
def __init__(self): self.notif = NotificationDB.instance() self.app = web.Application() self.app.add_routes([ web.route('*', '/', self.home), web.get("/v1/notifications/block/{block}", self.get_by_block), web.get("/v1/notifications/addr/{address}", self.get_by_addr), web.get("/v1/notifications/tx/{tx_hash}", self.get_by_tx), web.get("/v1/notifications/contract/{contract_hash}", self.get_by_contract), web.get("/v1/token/{contract_hash}", self.get_token), web.get("/v1/tokens", self.get_tokens), web.get("/v1/status", self.get_status) ])
def main(): parser = argparse.ArgumentParser() # Network group group = parser.add_mutually_exclusive_group() group.add_argument("-m", "--mainnet", action="store_true", default=False, help="Use MainNet instead of the default TestNet") group.add_argument( "-p", "--privnet", nargs="?", metavar="host", const=True, default=False, help= "Use a private net instead of the default TestNet, optionally using a custom host (default: 127.0.0.1)" ) group.add_argument( "--coznet", action="store_true", default=False, help="Use the CoZ network instead of the default TestNet") group.add_argument( "-u", "--unittest", nargs="?", metavar="host", const=True, default=False, help= "Use a private net instead of the default TestNet, optionally using a custom host (default: 127.0.0.1)" ) group.add_argument("-c", "--config", action="store", help="Use a specific config file") # Theme parser.add_argument( "-t", "--set-default-theme", dest="theme", choices=["dark", "light"], help= "Set the default theme to be loaded from the config file. Default: 'dark'" ) # Verbose parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Show smart-contract events by default") # Where to store stuff parser.add_argument("--datadir", action="store", help="Absolute path to use for database directories") # peers parser.add_argument("--minpeers", action="store", type=int, choices=range(1, 10 + 1), metavar="[1-10]", help="Min peers to use for P2P Joining") parser.add_argument("--maxpeers", action="store", type=int, default=5, choices=range(1, 10 + 1), metavar="[1-10]", help="Max peers to use for P2P Joining") # Show the neo-python version parser.add_argument( "--version", action="version", version="neo-python v{version}".format(version=__version__)) args = parser.parse_args() # Setting the datadir must come before setting the network, else the wrong path is checked at net setup. if args.datadir: settings.set_data_dir(args.datadir) # Setup depending on command line arguments. By default, the testnet settings are already loaded. if args.config: settings.setup(args.config) elif args.mainnet: settings.setup_mainnet() elif args.privnet: try: settings.setup_privnet(args.privnet) except PrivnetConnectionError as e: logger.error(str(e)) return elif args.coznet: settings.setup_coznet() elif args.unittest: settings.setup_unittest_net() # Logfile settings & setup logfile_fn = os.path.join(settings.DATA_DIR_PATH, 'prompt.log') logfile_max_bytes = 5e7 # 50 MB logfile_backup_count = 3 # 3 logfiles history settings.set_logfile(logfile_fn, logfile_max_bytes, logfile_backup_count) if args.theme: preferences.set_theme(args.theme) if args.verbose: settings.set_log_smart_contract_events(True) def set_min_peers(num_peers) -> bool: try: settings.set_min_peers(num_peers) print("Minpeers set to ", num_peers) return True except ValueError: print("Please supply a positive integer for minpeers") return False def set_max_peers(num_peers) -> bool: try: settings.set_max_peers(num_peers) print("Maxpeers set to ", num_peers) return True except ValueError: print("Please supply a positive integer for maxpeers") return False minpeers = args.minpeers maxpeers = args.maxpeers if minpeers and maxpeers: if minpeers > maxpeers: print("minpeers setting cannot be bigger than maxpeers setting") return if not set_min_peers(minpeers) or not set_max_peers(maxpeers): return elif minpeers: if not set_min_peers(minpeers): return if minpeers > settings.CONNECTED_PEER_MAX: if not set_max_peers(minpeers): return elif maxpeers: if not set_max_peers(maxpeers): return if maxpeers < settings.CONNECTED_PEER_MIN: if not set_min_peers(maxpeers): return loop = asyncio.get_event_loop() # put prompt_toolkit on top of asyncio to avoid blocking use_asyncio_event_loop() # Instantiate the blockchain and subscribe to notifications blockchain = Blockchain( DBFactory.getBlockchainDB(settings.chain_leveldb_path)) Blockchain.RegisterBlockchain(blockchain) # Try to set up a notification db if NotificationDB.instance(): NotificationDB.instance().start() # Start the prompt interface fn_prompt_history = os.path.join(settings.DATA_DIR_PATH, '.prompt.py.history') cli = PromptInterface(fn_prompt_history) cli_task = loop.create_task(cli.run()) p2p = NetworkService() loop.create_task(p2p.start()) async def shutdown(): all_tasks = asyncio.all_tasks() for task in all_tasks: task.cancel() with suppress(asyncio.CancelledError): await task # prompt_toolkit hack for not cleaning up see: https://github.com/prompt-toolkit/python-prompt-toolkit/issues/787 old_attrs = termios.tcgetattr(sys.stdin) try: loop.run_forever() except SystemExit: pass finally: with suppress(asyncio.InvalidStateError): app = prompt_toolkit_get_app() if app.is_running: app.exit() with suppress((SystemExit, Exception)): cli_task.exception() loop.run_until_complete(p2p.shutdown()) loop.run_until_complete(shutdown()) loop.run_until_complete(loop.shutdown_asyncgens()) loop.stop() loop.close() # Run things # After the reactor is stopped, gracefully shutdown the database. NotificationDB.close() Blockchain.Default().Dispose() # clean up prompt_toolkit mess, see above termios.tcsetattr(sys.stdin, termios.TCSANOW, old_attrs)
def run(self): # bl: changing to 15 so that we can get connections with a high number to improve transaction relayability settings.set_max_peers(15) loop = asyncio.get_event_loop() # because a KeyboardInterrupt is so violent it can shutdown the DB in an unpredictable state. loop.add_signal_handler(SIGINT, quit) loop.add_signal_handler(SIGHUP, quit) loop.add_signal_handler(SIGTERM, quit) # Disable smart contract events for external smart contracts settings.set_log_smart_contract_events(False) # Instantiate the blockchain and subscribe to notifications blockchain = Blockchain( DBFactory.getBlockchainDB(settings.chain_leveldb_path)) Blockchain.RegisterBlockchain(blockchain) # Try to set up a notification db if NotificationDB.instance(): NotificationDB.instance().start() # if the wallet was set up (by setting a path and loading the password), then open it! if self.wallet_path: self.wallet_open() # invoke any pre-start action that needs to occur before we start the loop. # optional for subclasses to implement. self.pre_start() blockchain_main_task = loop.create_task(self.run_loop()) p2p = NetworkService() loop.create_task(p2p.start()) async def shutdown(): all_tasks = asyncio.all_tasks() for task in all_tasks: task.cancel() with suppress(asyncio.CancelledError): await task try: loop.run_forever() except (SystemExit, KeyboardInterrupt): with suppress((SystemExit, Exception)): blockchain_main_task.exception() loop.run_until_complete(p2p.shutdown()) loop.run_until_complete(shutdown()) loop.run_until_complete(loop.shutdown_asyncgens()) loop.stop() finally: loop.close() # Run things if self.wallet_path: logger.info("Closing wallet file %s" % self.wallet_path) asyncio.run(self.wallet_close()) # After the reactor is stopped, gracefully shutdown the database. logger.info("Closing databases...") NotificationDB.close() Blockchain.Default().Dispose()
def setUpClass(cls): settings.NOTIFICATION_DB_PATH = os.path.join(settings.DATA_DIR_PATH, f"fixtures/{str(uuid1())}") ndb = NotificationDB.instance() ndb.start()
def setUpClass(cls): Blockchain.DeregisterBlockchain() super(BlockchainFixtureTestCase, cls).setUpClass() # for some reason during testing asyncio.get_event_loop() fails and does not create a new one if needed. This is the workaround try: loop = asyncio.get_running_loop() except RuntimeError: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) nodemgr = NodeManager() nodemgr.reset_for_test() # setup Blockchain DB if not os.path.exists(cls.FIXTURE_FILENAME): logger.info( "downloading fixture block database from %s. this may take a while" % cls.FIXTURE_REMOTE_LOC) response = requests.get(cls.FIXTURE_REMOTE_LOC, stream=True) response.raise_for_status() os.makedirs(os.path.dirname(cls.FIXTURE_FILENAME), exist_ok=True) with open(cls.FIXTURE_FILENAME, 'wb+') as handle: for block in response.iter_content(1024): handle.write(block) try: tar = tarfile.open(cls.FIXTURE_FILENAME) tar.extractall(path=settings.DATA_DIR_PATH) tar.close() except Exception as e: raise Exception( "Could not extract tar file - %s. You may want need to remove the fixtures file %s manually to fix this." % (e, cls.FIXTURE_FILENAME)) if not os.path.exists(cls.leveldb_testpath()): raise Exception("Error downloading fixtures at %s" % cls.leveldb_testpath()) settings.setup_unittest_net() cls._blockchain = Blockchain( getBlockchainDB(path=cls.leveldb_testpath()), skip_version_check=True) cls._blockchain.UT = True Blockchain.RegisterBlockchain(cls._blockchain) # setup Notification DB if not os.path.exists(cls.N_FIXTURE_FILENAME): logger.info( "downloading fixture notification database from %s. this may take a while" % cls.N_FIXTURE_REMOTE_LOC) response = requests.get(cls.N_FIXTURE_REMOTE_LOC, stream=True) response.raise_for_status() with open(cls.N_FIXTURE_FILENAME, 'wb+') as handle: for block in response.iter_content(1024): handle.write(block) try: tar = tarfile.open(cls.N_FIXTURE_FILENAME) tar.extractall(path=settings.DATA_DIR_PATH) tar.close() except Exception as e: raise Exception( "Could not extract tar file - %s. You may want need to remove the fixtures file %s manually to fix this." % (e, cls.N_FIXTURE_FILENAME)) if not os.path.exists(cls.N_NOTIFICATION_DB_NAME): raise Exception("Error downloading fixtures at %s" % cls.N_NOTIFICATION_DB_NAME) settings.NOTIFICATION_DB_PATH = cls.N_NOTIFICATION_DB_NAME ndb = NotificationDB.instance() ndb.start()
async def setup_and_start(loop): parser = argparse.ArgumentParser() # Network options group_network_container = parser.add_argument_group( title="Network options") group_network = group_network_container.add_mutually_exclusive_group( required=True) group_network.add_argument("--mainnet", action="store_true", default=False, help="Use MainNet") group_network.add_argument("--testnet", action="store_true", default=False, help="Use TestNet") group_network.add_argument("--privnet", action="store_true", default=False, help="Use PrivNet") group_network.add_argument("--coznet", action="store_true", default=False, help="Use CozNet") group_network.add_argument("--config", action="store", help="Use a specific config file") # Ports for RPC and REST api group_modes = parser.add_argument_group(title="Mode(s)") group_modes.add_argument( "--port-rpc", type=int, help="port to use for the json-rpc api (eg. 10332)") group_modes.add_argument("--port-rest", type=int, help="port to use for the rest api (eg. 80)") # Advanced logging setup group_logging = parser.add_argument_group(title="Logging options") group_logging.add_argument("--logfile", action="store", type=str, help="Logfile") group_logging.add_argument( "--syslog", action="store_true", help= "Log to syslog instead of to log file ('user' is the default facility)" ) group_logging.add_argument( "--syslog-local", action="store", type=int, choices=range(0, 7 + 1), metavar="[0-7]", help= "Log to a local syslog facility instead of 'user'. Value must be between 0 and 7 (e.g. 0 for 'local0')." ) group_logging.add_argument("--disable-stderr", action="store_true", help="Disable stderr logger") # Where to store stuff parser.add_argument("--datadir", action="store", help="Absolute path to use for database directories") # peers parser.add_argument("--minpeers", action="store", type=int, choices=range(1, 10 + 1), metavar="[1-10]", help="Min peers to use for P2P Joining") parser.add_argument("--maxpeers", action="store", type=int, choices=range(1, 10 + 1), metavar="[1-10]", help="Max peers to use for P2P Joining") # If a wallet should be opened parser.add_argument( "--wallet", action="store", help= "Open wallet. Will allow you to use methods that require an open wallet" ) # host parser.add_argument("--host", action="store", type=str, help="Hostname ( for example 127.0.0.1)", default="0.0.0.0") # Now parse args = parser.parse_args() # print(args) if not args.port_rpc and not args.port_rest: print("Error: specify at least one of --port-rpc / --port-rest") parser.print_help() raise SystemExit if args.port_rpc == args.port_rest: print("Error: --port-rpc and --port-rest cannot be the same") parser.print_help() raise SystemExit if args.logfile and (args.syslog or args.syslog_local): print("Error: Cannot only use logfile or syslog at once") parser.print_help() raise SystemExit # Setting the datadir must come before setting the network, else the wrong path is checked at net setup. if args.datadir: settings.set_data_dir(args.datadir) # Network configuration depending on command line arguments. By default, the testnet settings are already loaded. if args.config: settings.setup(args.config) elif args.mainnet: settings.setup_mainnet() elif args.testnet: settings.setup_testnet() elif args.privnet: settings.setup_privnet() elif args.coznet: settings.setup_coznet() def set_min_peers(num_peers) -> bool: try: settings.set_min_peers(num_peers) print("Minpeers set to ", num_peers) return True except ValueError: print("Please supply a positive integer for minpeers") return False def set_max_peers(num_peers) -> bool: try: settings.set_max_peers(num_peers) print("Maxpeers set to ", num_peers) return True except ValueError: print("Please supply a positive integer for maxpeers") return False minpeers = args.minpeers maxpeers = args.maxpeers if minpeers and maxpeers: if minpeers > maxpeers: print("minpeers setting cannot be bigger than maxpeers setting") return if not set_min_peers(minpeers) or not set_max_peers(maxpeers): return elif minpeers: if not set_min_peers(minpeers): return if minpeers > settings.CONNECTED_PEER_MAX: if not set_max_peers(minpeers): return elif maxpeers: if not set_max_peers(maxpeers): return if maxpeers < settings.CONNECTED_PEER_MIN: if not set_min_peers(maxpeers): return if args.syslog or args.syslog_local is not None: # Setup the syslog facility if args.syslog_local is not None: print("Logging to syslog local%s facility" % args.syslog_local) syslog_facility = SysLogHandler.LOG_LOCAL0 + args.syslog_local else: print("Logging to syslog user facility") syslog_facility = SysLogHandler.LOG_USER # Setup logzero to only use the syslog handler logzero.syslog(facility=syslog_facility) else: # Setup file logging if args.logfile: logfile = os.path.abspath(args.logfile) if args.disable_stderr: print("Logging to logfile: %s" % logfile) else: print("Logging to stderr and logfile: %s" % logfile) logzero.logfile(logfile, maxBytes=LOGFILE_MAX_BYTES, backupCount=LOGFILE_BACKUP_COUNT, disableStderrLogger=args.disable_stderr) else: print("Logging to stdout and stderr") if args.wallet: if not os.path.exists(args.wallet): print("Wallet file not found") return passwd = os.environ.get('NEO_PYTHON_JSONRPC_WALLET_PASSWORD', None) if not passwd: try: passwd = prompt("[password]> ", is_password=True) except KeyboardInterrupt: print("Wallet opening cancelled") return password_key = to_aes_key(passwd) try: wallet = UserWallet.Open(args.wallet, password_key) asyncio.create_task( wallet.sync_wallet(start_block=wallet._current_height)) except Exception as e: print(f"Could not open wallet {e}") return else: wallet = None # Disable logging smart contract events settings.set_log_smart_contract_events(False) # Write a PID file to easily quit the service write_pid_file() # Instantiate the blockchain and subscribe to notifications blockchain = Blockchain(getBlockchainDB()) Blockchain.RegisterBlockchain(blockchain) p2p = NetworkService() p2p_task = loop.create_task(p2p.start()) loop.create_task(custom_background_code()) NotificationDB.instance().start() if args.port_rpc: logger.info("Starting json-rpc api server on http://%s:%s" % (args.host, args.port_rpc)) try: rpc_class = load_class_from_path(settings.RPC_SERVER) except ValueError as err: logger.error(err) sys.exit() api_server_rpc = rpc_class(wallet=wallet) runner = web.AppRunner(api_server_rpc.app) await runner.setup() site = web.TCPSite(runner, args.host, args.port_rpc) await site.start() if args.port_rest: logger.info("Starting REST api server on http://%s:%s" % (args.host, args.port_rest)) try: rest_api = load_class_from_path(settings.REST_SERVER) except ValueError as err: logger.error(err) sys.exit() api_server_rest = rest_api() runner = web.AppRunner(api_server_rest.app) await runner.setup() site = web.TCPSite(runner, args.host, args.port_rpc) await site.start() return wallet
def tearDownClass(cls): NotificationDB.instance().close() shutil.rmtree(settings.NOTIFICATION_DB_PATH)
def test_1_ok(self): ndb = NotificationDB.instance() events = ndb.get_by_block(9583) self.assertEqual(len(events), 1)