def do_clean(args): # Intercept the config # Set default config file if not specified by user if args.config is None: args.config = ['txnvalidator.js'] # Convert any comma-delimited argument strings to list elements for arglist in [args.config]: if arglist is not None: for arg in arglist: if ',' in arg: loc = arglist.index(arg) arglist.pop(loc) for element in reversed(arg.split(',')): arglist.insert(loc, element) options_config = ArgparseOptionsConfig( [ ('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('log_config', 'LogConfigFile'), ('key_dir', 'KeyDirectory'), ('verbose', 'Verbose') ], args) cfg = get_validator_configuration(args.config, options_config) if args.state is True: do_clean_state(cfg, args) if args.keys is True: do_delete_keys(cfg, args) if args.state is False and args.keys is False: raise CliException("Please specify at least one object to clean.")
def do_genesis(args): # Get ledger config: # set the default value of config because argparse 'default' in # combination with action='append' does the wrong thing. if args.config is None: args.config = ['txnvalidator.js'] # convert any comma-delimited argument strings to list elements for arglist in [args.config]: if arglist is not None: for arg in arglist: if ',' in arg: loc = arglist.index(arg) arglist.pop(loc) for element in reversed(arg.split(',')): arglist.insert(loc, element) options_config = ArgparseOptionsConfig([('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('type', 'LedgerType'), ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('node', 'NodeName'), ('verbose', 'Verbose'), ('family', 'TransactionFamilies')], args) cfg = get_validator_configuration(args.config, options_config) # Perform requisite overrides and validation: cfg['GenesisLedger'] = True cfg['Restore'] = False # should check that sigining key exists... # debug report for key, value in cfg.iteritems(): LOGGER.debug("CONFIG: %s = %s", key, value) # instantiate ledger (from node) nd = node_from_config(cfg) # in future, dynamically select ledger obj based on LedgerType ledger = PoetJournal(nd, **cfg) # may need to add transaction family objects ad hoc from cfg dfl_txn_families = [endpoint_registry, integer_key] for txnfamily in dfl_txn_families: txnfamily.register_transaction_types(ledger) # ...skipping onNodeDisconnect handler (using ledger, not validator...) # Create genesis block: # we should make sure there is no current chain here, or fail # calling initialization_complete will create the genesis block ledger.initialization_complete() # simulate receiving the genesis block msg from reactor to force commit msg = ledger.gossip.MessageQueue.pop() (_, msg_handler) = ledger.MessageHandlerMap[msg.MessageType] msg_handler(msg, ledger) # Report, then shutdown to save state: head = ledger.MostRecentCommittedBlockID n_blks = ledger.CommittedBlockCount LOGGER.info('current chain head: %s; current chain len: %s', head, n_blks) ledger.shutdown() return (head, n_blks) # return values for unit and/or integration tests
def get_configuration(args, os_name=os.name, config_files_required=None): options = parse_command_line(args) options_config = ArgparseOptionsConfig( [ ('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('delay_start', 'DelayStart'), ('run_dir', 'RunDirectory'), ('type', 'LedgerType'), ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('node', 'NodeName'), ('restore', 'Restore'), ('peers', 'Peers'), ('genesis', 'GenesisLedger'), ('url', 'LedgerURL'), ('verbose', 'Verbose'), ('pidfile', 'PidFile'), ('daemon', 'Daemonize'), ('check_elevated', 'CheckElevated'), ('listen', 'Listen'), ('family', 'TransactionFamilies') ], options) return get_validator_configuration(options.config, options_config, os_name, config_files_required)
def do_clean(args): # Intercept the config # Set default config file if not specified by user if args.config is None: args.config = ['txnvalidator.js'] # Convert any comma-delimited argument strings to list elements for arglist in [args.config]: if arglist is not None: for arg in arglist: if ',' in arg: loc = arglist.index(arg) arglist.pop(loc) for element in reversed(arg.split(',')): arglist.insert(loc, element) options_config = ArgparseOptionsConfig([('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('log_config', 'LogConfigFile'), ('key_dir', 'KeyDirectory'), ('verbose', 'Verbose')], args) cfg = get_validator_configuration(args.config, options_config) if args.state is True: do_clean_state(cfg, args) if args.keys is True: do_delete_keys(cfg, args) if args.state is False and args.keys is False: raise CliException("Please specify at least one object to clean.")
def get_configuration(args, os_name=os.name, config_files_required=None): options = parse_command_line(args) options_config = ArgparseOptionsConfig( [ ('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('delay_start', 'DelayStart'), ('run_dir', 'RunDirectory'), ('type', 'LedgerType'), ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('node', 'NodeName'), ('peers', 'Peers'), ('url', 'LedgerURL'), ('verbose', 'Verbose'), ('pidfile', 'PidFile'), ('daemon', 'Daemonize'), ('check_elevated', 'CheckElevated'), ('listen', 'Listen'), ('family', 'TransactionFamilies') ], options) return get_validator_configuration(options.config, options_config, os_name, config_files_required)
def __init__(self, host_name='localhost', verbose=False): self._host_name = host_name self._verbose = verbose self._base_config = get_validator_configuration([], {}) self._v0_cfg = { "InitialConnectivity": 0, } self._nodes = {}
def __init__(self, host_name='localhost', verbose=False): self._host_name = host_name self._verbose = verbose self._base_config = get_validator_configuration([], {}) # Additional configuration for the genesis validator self._genesis_cfg = { "InitialConnectivity": 0, } # Additional configuration for the non-genesis validators self._non_genesis_cfg = { "InitialConnectivity": 1, } self._nodes = {}
def __init__(self, host_name='localhost', verbose=False): self._host_name = host_name self._verbose = verbose self._base_config = get_validator_configuration([], {}) # Additional configuration for the genesis validator self._genesis_cfg = { "InitialConnectivity": 0, } # Additional configuration for the non-genesis validators self._non_genesis_cfg = { "InitialConnectivity": 1, } self._nodes = {}
def get_configuration(args, os_name=os.name, config_files_required=True): options = parse_command_line(args) options_config = ArgparseOptionsConfig([ ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('conf_dir', 'ConfigDirectory'), ('url', 'LedgerURL'), ('node', 'NodeName'), ('verbose', 'Verbose'), ], options) return get_validator_configuration(options.config, options_config, os_name, config_files_required)
def get_configuration(args, os_name=os.name, config_files_required=True): options = parse_command_line(args) options_config = ArgparseOptionsConfig( [ ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('conf_dir', 'ConfigDirectory'), ('url', 'LedgerURL'), ('node', 'NodeName'), ('verbose', 'Verbose'), ], options) return get_validator_configuration(options.config, options_config, os_name, config_files_required)
def __init__(self, host_name='localhost', verbose=False, state_dir=None): self._host_name = host_name self._verbose = verbose self._base_config = get_validator_configuration([], {}) self._v0_cfg = { "InitialConnectivity": 0, } if state_dir is None: state_dir = \ os.path.join(os.path.expanduser("~"), '.sawtooth', 'cluster') if not os.path.exists(state_dir): os.makedirs(state_dir) self._state_dir = state_dir
def __init__(self, host_name='localhost', verbose=False, state_dir=None): self._host_name = host_name self._verbose = verbose self._base_config = get_validator_configuration([], {}) # Additional configuration for the genesis validator self._genesis_cfg = { "InitialConnectivity": 0, } # Additional configuration for the non-genesis validators self._non_genesis_cfg = { "InitialConnectivity": 1, } if state_dir is None: state_dir = \ os.path.join(os.path.expanduser("~"), '.sawtooth', 'cluster') if not os.path.exists(state_dir): os.makedirs(state_dir) self._state_dir = state_dir
def get_massaged_validator_configuration(self): ''' Isolates a work around regarding the environmental variable CURRENCYHOME in order to leverage the sawtooth library to produce base configs useful for test validators. Args: currency_home: (str) directory path for validator related files Returns: validator_config: (dict) ''' # setup env for get_validator_configuration old_currency_home = os.getenv('CURRENCYHOME') try: os.environ['CURRENCYHOME'] = self.currency_home validator_config = get_validator_configuration([], {}) finally: # Restore environmental vars if old_currency_home is None: os.unsetenv('CURRENCYHOME') else: os.environ['CURRENCYHOME'] = old_currency_home return validator_config
def get_massaged_validator_configuration(self): ''' Isolates a work around regarding the environmental variable CURRENCYHOME in order to leverage the sawtooth library to produce base configs useful for test validators. Args: currency_home: (str) directory path for validator related files Returns: validator_config: (dict) ''' # setup env for get_validator_configuration old_currency_home = os.getenv('CURRENCYHOME') try: os.environ['CURRENCYHOME'] = self.currency_home validator_config = get_validator_configuration([], {}) finally: # Restore environmental vars if old_currency_home is None: os.unsetenv('CURRENCYHOME') else: os.environ['CURRENCYHOME'] = old_currency_home return validator_config
def mirror_validator_parsing(args): # Get ledger config: # ...set the default value of config because argparse 'default' in # ...combination with action='append' does the wrong thing. if args.config is None: args.config = ['txnvalidator.js'] # ...convert any comma-delimited argument strings to list elements for arglist in [args.config]: if arglist is not None: for arg in arglist: if ',' in arg: loc = arglist.index(arg) arglist.pop(loc) for element in reversed(arg.split(',')): arglist.insert(loc, element) options_config = ArgparseOptionsConfig([('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('type', 'LedgerType'), ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('node', 'NodeName'), ('verbose', 'Verbose'), ('family', 'TransactionFamilies')], args) cfg = get_validator_configuration(args.config, options_config) # Duplicate some configuration massaging done by validator_cli from txnintegration.utils import read_key_file # avoids dependency issue if "KeyFile" in cfg: keyfile = cfg["KeyFile"] if os.path.isfile(keyfile): LOGGER.info('read signing key from %s', keyfile) key = read_key_file(keyfile) cfg['SigningKey'] = key else: LOGGER.warn('unable to locate key file %s', keyfile) else: LOGGER.warn('no key file specified') return cfg
def do_poet0_genesis(args): # Get ledger config: # ...set the default value of config because argparse 'default' in # ...combination with action='append' does the wrong thing. if args.config is None: args.config = ['txnvalidator.js'] # ...convert any comma-delimited argument strings to list elements for arglist in [args.config]: if arglist is not None: for arg in arglist: if ',' in arg: loc = arglist.index(arg) arglist.pop(loc) for element in reversed(arg.split(',')): arglist.insert(loc, element) options_config = ArgparseOptionsConfig( [ ('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('type', 'LedgerType'), ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('node', 'NodeName'), ('verbose', 'Verbose'), ('family', 'TransactionFamilies') ], args) cfg = get_validator_configuration(args.config, options_config) # Obtain Journal object: # ...set WaitTimer globals target_wait_time = cfg.get("TargetWaitTime") initial_wait_time = cfg.get("InitialWaitTime") certificate_sample_length = cfg.get('CertificateSampleLength') fixed_duration_blocks = cfg.get("FixedDurationBlocks") from journal.consensus.poet0.wait_timer import set_wait_timer_globals set_wait_timer_globals(target_wait_time, initial_wait_time, certificate_sample_length, fixed_duration_blocks, ) # ...build Gossip dependency (nd, _) = parse_networking_info(cfg) minimum_retries = cfg.get("MinimumRetries") retry_interval = cfg.get("RetryInterval") gossiper = Gossip(nd, minimum_retries, retry_interval) # ...build Journal min_txn_per_block = cfg.get("MinimumTransactionsPerBlock") max_txn_per_block = cfg.get("MaxTransactionsPerBlock") max_txn_age = cfg.get("MaxTxnAge") genesis_ledger = cfg.get("GenesisLedger") data_directory = cfg.get("DataDirectory") store_type = cfg.get("StoreType") stat_domains = {} from journal.consensus.poet0.poet_consensus import PoetConsensus consensus_obj = PoetConsensus(cfg) journal = Journal(gossiper.LocalNode, gossiper, gossiper.dispatcher, consensus_obj, stat_domains, minimum_transactions_per_block=min_txn_per_block, max_transactions_per_block=max_txn_per_block, max_txn_age=max_txn_age, genesis_ledger=genesis_ledger, data_directory=data_directory, store_type=store_type, ) # ...add 'built in' txn families default_transaction_families = [ endpoint_registry ] for txn_family in default_transaction_families: txn_family.register_transaction_types(journal) # ...add auxiliary transaction families for txn_family_module_name in cfg.get("TransactionFamilies", []): txn_family = importlib.import_module(txn_family_module_name) txn_family.register_transaction_types(journal) # Make genesis block: # ...make sure there is no current chain here, or fail # ...create block g_block g_block = journal.build_block(genesis=True) journal.claim_block(g_block) # ...simulate receiving the genesis block msg from reactor to force commit g_block_msg = gossiper.IncomingMessageQueue.pop() journal.dispatcher.dispatch(g_block_msg) journal.initialization_complete() head = journal.most_recent_committed_block_id chain_len = len(journal.committed_block_ids()) # Run shutdown: # ...persist new state journal.shutdown() # ...release gossip obj's UDP port gossiper.Listener.loseConnection() gossiper.Listener.connectionLost(reason=None) # Log genesis data, then write it out to ease dissemination genesis_data = { 'GenesisId': head, 'ChainLength': chain_len, } gblock_fname = genesis_info_file_name(cfg['DataDirectory']) LOGGER.info('genesis data: %s', genesis_data) LOGGER.info('writing genesis data to %s', gblock_fname) with open(gblock_fname, 'w') as f: f.write(json.dumps(genesis_data))
def test_genesis_util(self): print old_home = os.getenv('CURRENCYHOME') tmp_home = tempfile.mkdtemp() vcc = None try: # Set up env and config v_file = find_txn_validator() os.environ['CURRENCYHOME'] = tmp_home cfg = get_validator_configuration([], {}) # ...rewire for ValidatorManager compatibility cfg['KeyDirectory'] = tmp_home cfg['DataDirectory'] = tmp_home cfg['LogDirectory'] = tmp_home # En route, test keygen client via main key_name = cfg['NodeName'] key_dir = cfg['KeyDirectory'] cmd = 'keygen %s --key-dir %s' % (key_name, key_dir) entry_point(args=cmd.split(), with_loggers=False) base_name = key_dir + os.path.sep + key_name self.assertTrue(os.path.exists('%s.wif' % base_name)) self.assertTrue(os.path.exists('%s.addr' % base_name)) cfg['KeyFile'] = '%s.wif' % base_name # Test admin poet0-genesis tool fname = get_genesis_block_id_file_name(cfg['DataDirectory']) self.assertFalse(os.path.exists(fname)) config_file = tmp_home + os.path.sep + 'cfg.json' with open(config_file, 'w') as f: f.write(json.dumps(cfg, indent=4) + '\n') cmd = 'admin poet0-genesis --config %s' % config_file entry_point(args=cmd.split(), with_loggers=False) self.assertTrue(os.path.exists(fname)) dat = None with open(fname, 'r') as f: dat = json.load(f) self.assertTrue('GenesisId' in dat.keys()) tgt_block = dat['GenesisId'] # Verify genesis tool (also tests blockchain restoration) # ...initial connectivity must be zero for the initial validator cfg['InitialConnectivity'] = 0 # ...launch validator net_cfg = NetworkConfig.from_config_list([cfg]) vcc = ValidatorCollectionController(net_cfg, data_dir=tmp_home, txnvalidator=v_file) vcc.activate(0, probe_seconds=120) # ...verify validator is extending tgt_block to = TimeOut(64) blk_lists = None prog_str = 'TEST ROOT RESTORATION (expect %s)' % tgt_block with Progress(prog_str) as p: print while not to.is_timed_out() and blk_lists is None: try: blk_lists = get_blocklists(['http://localhost:8800']) print 'block_lists: %s' % blk_lists if len(blk_lists) < 1 or len(blk_lists[0]) < 2: blk_lists = None except MessageException as e: pass time.sleep(1) p.step() self.assertIsNotNone(blk_lists) root = blk_lists[0][0] self.assertEqual(tgt_block, root) finally: # Shut down validator if vcc is not None: vcc.shutdown() # Restore environmental vars if old_home is None: os.unsetenv('CURRENCYHOME') else: os.environ['CURRENCYHOME'] = old_home # Delete temp dir if os.path.exists(tmp_home): shutil.rmtree(tmp_home)
def do_poet0_genesis(args): # Get ledger config: # set the default value of config because argparse 'default' in # combination with action='append' does the wrong thing. if args.config is None: args.config = ['txnvalidator.js'] # convert any comma-delimited argument strings to list elements for arglist in [args.config]: if arglist is not None: for arg in arglist: if ',' in arg: loc = arglist.index(arg) arglist.pop(loc) for element in reversed(arg.split(',')): arglist.insert(loc, element) options_config = ArgparseOptionsConfig( [ ('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('type', 'LedgerType'), ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('node', 'NodeName'), ('verbose', 'Verbose'), ('family', 'TransactionFamilies') ], args) cfg = get_validator_configuration(args.config, options_config) # Perform requisite overrides and validation: cfg['GenesisLedger'] = True # should check that sigining key exists... # debug report for key, value in cfg.iteritems(): LOGGER.debug("CONFIG: %s = %s", key, value) # set WaitTimer globals target_wait_time = cfg.get("TargetWaitTime") initial_wait_time = cfg.get("InitialWaitTime") certificate_sample_length = cfg.get('CertificateSampleLength') fixed_duration_blocks = cfg.get("FixedDurationBlocks") from journal.consensus.poet0.wait_timer \ import set_wait_timer_globals set_wait_timer_globals(target_wait_time, initial_wait_time, certificate_sample_length, fixed_duration_blocks, ) # build gossiper (nd, _) = parse_networking_info(cfg) minimum_retries = cfg.get("MinimumRetries") retry_interval = cfg.get("RetryInterval") gossiper = Gossip(nd, minimum_retries, retry_interval) # build journal min_txn_per_block = cfg.get("MinimumTransactionsPerBlock") max_txn_per_block = cfg.get("MaxTransactionsPerBlock") max_txn_age = cfg.get("MaxTxnAge") genesis_ledger = cfg.get("GenesisLedger") data_directory = cfg.get("DataDirectory") store_type = cfg.get("StoreType") stat_domains = {} # in future, dynamically select consensus obj based on ConsensusType journal = Journal(gossiper.LocalNode, gossiper, gossiper.dispatcher, PoetConsensus(cfg), stat_domains, minimum_transactions_per_block=min_txn_per_block, max_transactions_per_block=max_txn_per_block, max_txn_age=max_txn_age, genesis_ledger=genesis_ledger, data_directory=data_directory, store_type=store_type, ) # may need to add transaction family objects ad hoc from cfg dfl_txn_families = [endpoint_registry, integer_key] for txnfamily in dfl_txn_families: txnfamily.register_transaction_types(journal) # ...skipping onNodeDisconnect handler (using ledger, not validator...) # Create genesis block: # we should make sure there is no current chain here, or fail # calling initialization_complete will create the genesis block journal.initialization_complete() # simulate receiving the genesis block msg from reactor to force commit msg = journal.gossip.IncomingMessageQueue.pop() (_, msg_handler) = journal.dispatcher.message_handler_map[msg.MessageType] msg_handler(msg, journal) # Gather data, then shutdown to save state: head = journal.most_recent_committed_block_id # ...not sure why n_blocks is experimentally 0 and not 1 # ...if we only make the genesis, it would be good to check n_blks = 1 n_blks = journal.committed_block_count journal.shutdown() # log genesis data, then write it out to ease dissemination genesis_data = { 'GenesisId': head, 'ChainLength': n_blks, } gblock_fname = get_genesis_block_id_file_name(cfg['DataDirectory']) LOGGER.info('genesis data: %s', genesis_data) LOGGER.info('writing genesis data to %s', gblock_fname) with open(gblock_fname, 'w') as f: f.write(json.dumps(genesis_data))
def do_poet0_genesis(args): # Get ledger config: # ...set the default value of config because argparse 'default' in # ...combination with action='append' does the wrong thing. if args.config is None: args.config = ['txnvalidator.js'] # ...convert any comma-delimited argument strings to list elements for arglist in [args.config]: if arglist is not None: for arg in arglist: if ',' in arg: loc = arglist.index(arg) arglist.pop(loc) for element in reversed(arg.split(',')): arglist.insert(loc, element) options_config = ArgparseOptionsConfig([('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('type', 'LedgerType'), ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('node', 'NodeName'), ('verbose', 'Verbose'), ('family', 'TransactionFamilies')], args) cfg = get_validator_configuration(args.config, options_config) # Obtain Journal object: # ...set WaitTimer globals target_wait_time = cfg.get("TargetWaitTime") initial_wait_time = cfg.get("InitialWaitTime") certificate_sample_length = cfg.get('CertificateSampleLength') fixed_duration_blocks = cfg.get("FixedDurationBlocks") from journal.consensus.poet0.wait_timer import set_wait_timer_globals set_wait_timer_globals( target_wait_time, initial_wait_time, certificate_sample_length, fixed_duration_blocks, ) # ...build Gossip dependency (nd, _) = parse_networking_info(cfg) minimum_retries = cfg.get("MinimumRetries") retry_interval = cfg.get("RetryInterval") gossiper = Gossip(nd, minimum_retries, retry_interval) # ...build Journal min_txn_per_block = cfg.get("MinimumTransactionsPerBlock") max_txn_per_block = cfg.get("MaxTransactionsPerBlock") max_txn_age = cfg.get("MaxTxnAge") genesis_ledger = cfg.get("GenesisLedger") data_directory = cfg.get("DataDirectory") store_type = cfg.get("StoreType") stat_domains = {} from journal.consensus.poet0.poet_consensus import PoetConsensus consensus_obj = PoetConsensus(cfg) journal = Journal( gossiper.LocalNode, gossiper, gossiper.dispatcher, consensus_obj, stat_domains, minimum_transactions_per_block=min_txn_per_block, max_transactions_per_block=max_txn_per_block, max_txn_age=max_txn_age, genesis_ledger=genesis_ledger, data_directory=data_directory, store_type=store_type, ) # ...add 'built in' txn families default_transaction_families = [endpoint_registry] for txn_family in default_transaction_families: txn_family.register_transaction_types(journal) # ...add auxiliary transaction families for txn_family_module_name in cfg.get("TransactionFamilies", []): txn_family = importlib.import_module(txn_family_module_name) txn_family.register_transaction_types(journal) # Make genesis block: # ...make sure there is no current chain here, or fail # ...create block g_block g_block = journal.build_block(genesis=True) journal.claim_block(g_block) # ...simulate receiving the genesis block msg from reactor to force commit g_block_msg = gossiper.IncomingMessageQueue.pop() journal.dispatcher.dispatch(g_block_msg) journal.initialization_complete() head = journal.most_recent_committed_block_id chain_len = len(journal.committed_block_ids()) # Run shutdown: # ...persist new state journal.shutdown() # ...release gossip obj's UDP port gossiper.Listener.loseConnection() gossiper.Listener.connectionLost(reason=None) # Log genesis data, then write it out to ease dissemination genesis_data = { 'GenesisId': head, 'ChainLength': chain_len, } gblock_fname = genesis_info_file_name(cfg['DataDirectory']) LOGGER.info('genesis data: %s', genesis_data) LOGGER.info('writing genesis data to %s', gblock_fname) with open(gblock_fname, 'w') as f: f.write(json.dumps(genesis_data))
def do_genesis(args): # Get ledger config: # set the default value of config because argparse 'default' in # combination with action='append' does the wrong thing. if args.config is None: args.config = ['txnvalidator.js'] # convert any comma-delimited argument strings to list elements for arglist in [args.config]: if arglist is not None: for arg in arglist: if ',' in arg: loc = arglist.index(arg) arglist.pop(loc) for element in reversed(arg.split(',')): arglist.insert(loc, element) options_config = ArgparseOptionsConfig( [ ('conf_dir', 'ConfigDirectory'), ('data_dir', 'DataDirectory'), ('type', 'LedgerType'), ('log_config', 'LogConfigFile'), ('keyfile', 'KeyFile'), ('node', 'NodeName'), ('verbose', 'Verbose'), ('family', 'TransactionFamilies') ], args) cfg = get_validator_configuration(args.config, options_config) # Perform requisite overrides and validation: cfg['GenesisLedger'] = True cfg['Restore'] = False # should check that sigining key exists... # debug report for key, value in cfg.iteritems(): LOGGER.debug("CONFIG: %s = %s", key, value) # instantiate ledger (from node) nd = node_from_config(cfg) # in future, dynamically select ledger obj based on LedgerType ledger = PoetJournal(nd, **cfg) # may need to add transaction family objects ad hoc from cfg dfl_txn_families = [endpoint_registry, integer_key] for txnfamily in dfl_txn_families: txnfamily.register_transaction_types(ledger) # ...skipping onNodeDisconnect handler (using ledger, not validator...) # Create genesis block: # we should make sure there is no current chain here, or fail # calling initialization_complete will create the genesis block ledger.initialization_complete() # simulate receiving the genesis block msg from reactor to force commit msg = ledger.MessageQueue.pop() (_, msg_handler) = ledger.MessageHandlerMap[msg.MessageType] msg_handler(msg, ledger) # Report, then shutdown to save state: head = ledger.MostRecentCommittedBlockID n_blks = ledger.CommittedBlockCount LOGGER.info('current chain head: %s; current chain len: %s', head, n_blks) ledger.shutdown() return (head, n_blks) # return values for unit and/or integration tests