def run(): realnets = dict((name, net) for name, net in networks.nets.iteritems() if '_testnet' not in name) parser = fixargparse.FixedArgumentParser(description='p2pool (version %s)' % (p2pool.__version__,), fromfile_prefix_chars='@') parser.add_argument('--version', action='version', version=p2pool.__version__) parser.add_argument('--net', help='use specified network (default: bitbar)', action='store', choices=sorted(realnets), default='bitbar', dest='net_name') parser.add_argument('--testnet', help='''use the network's testnet''', action='store_const', const=True, default=False, dest='testnet') parser.add_argument('--debug', help='enable debugging mode', action='store_const', const=True, default=False, dest='debug') parser.add_argument('--datadir', help='store data in this directory (default: <directory run_p2pool.py is in>/data)', type=str, action='store', default=None, dest='datadir') parser.add_argument('--logfile', help='''log to this file (default: data/<NET>/log)''', type=str, action='store', default=None, dest='logfile') parser.add_argument('--merged', help='call getauxblock on this url to get work for merged mining (example: http://ncuser:[email protected]:10332/)', type=str, action='append', default=[], dest='merged_urls') parser.add_argument('--give-author', metavar='DONATION_PERCENTAGE', help='donate this percentage of work towards the development of p2pool (default: 0.0)', type=float, action='store', default=0.0, dest='donation_percentage') parser.add_argument('--iocp', help='use Windows IOCP API in order to avoid errors due to large number of sockets being open', action='store_true', default=False, dest='iocp') parser.add_argument('--irc-announce', help='announce any blocks found on irc://irc.freenode.net/#p2pool', action='store_true', default=False, dest='irc_announce') parser.add_argument('--no-bugreport', help='disable submitting caught exceptions to the author', action='store_true', default=False, dest='no_bugreport') p2pool_group = parser.add_argument_group('p2pool interface') p2pool_group.add_argument('--p2pool-port', metavar='PORT', help='use port PORT to listen for connections (forward this port from your router!) (default: %s)' % ', '.join('%s:%i' % (name, net.P2P_PORT) for name, net in sorted(realnets.items())), type=int, action='store', default=None, dest='p2pool_port') p2pool_group.add_argument('-n', '--p2pool-node', metavar='ADDR[:PORT]', help='connect to existing p2pool node at ADDR listening on port PORT (defaults to default p2pool P2P port) in addition to builtin addresses', type=str, action='append', default=[], dest='p2pool_nodes') parser.add_argument('--disable-upnp', help='''don't attempt to use UPnP to forward p2pool's P2P port from the Internet to this computer''', action='store_false', default=True, dest='upnp') p2pool_group.add_argument('--max-conns', metavar='CONNS', help='maximum incoming connections (default: 40)', type=int, action='store', default=40, dest='p2pool_conns') p2pool_group.add_argument('--outgoing-conns', metavar='CONNS', help='outgoing connections (default: 6)', type=int, action='store', default=6, dest='p2pool_outgoing_conns') worker_group = parser.add_argument_group('worker interface') worker_group.add_argument('-w', '--worker-port', metavar='PORT or ADDR:PORT', help='listen on PORT on interface with ADDR for RPC connections from miners (default: all interfaces, %s)' % ', '.join('%s:%i' % (name, net.WORKER_PORT) for name, net in sorted(realnets.items())), type=str, action='store', default=None, dest='worker_endpoint') worker_group.add_argument('-f', '--fee', metavar='FEE_PERCENTAGE', help='''charge workers mining to their own bitcoin address (by setting their miner's username to a bitcoin address) this percentage fee to mine on your p2pool instance. Amount displayed at http://127.0.0.1:WORKER_PORT/fee (default: 0)''', type=float, action='store', default=0, dest='worker_fee') bitcoind_group = parser.add_argument_group('bitcoind interface') bitcoind_group.add_argument('--bitcoind-address', metavar='BITCOIND_ADDRESS', help='connect to this address (default: 127.0.0.1)', type=str, action='store', default='127.0.0.1', dest='bitcoind_address') bitcoind_group.add_argument('--bitcoind-rpc-port', metavar='BITCOIND_RPC_PORT', help='''connect to JSON-RPC interface at this port (default: %s <read from bitcoin.conf if password not provided>)''' % ', '.join('%s:%i' % (name, net.PARENT.RPC_PORT) for name, net in sorted(realnets.items())), type=int, action='store', default=None, dest='bitcoind_rpc_port') bitcoind_group.add_argument('--bitcoind-rpc-ssl', help='connect to JSON-RPC interface using SSL', action='store_true', default=False, dest='bitcoind_rpc_ssl') bitcoind_group.add_argument('--bitcoind-p2p-port', metavar='BITCOIND_P2P_PORT', help='''connect to P2P interface at this port (default: %s <read from bitcoin.conf if password not provided>)''' % ', '.join('%s:%i' % (name, net.PARENT.P2P_PORT) for name, net in sorted(realnets.items())), type=int, action='store', default=None, dest='bitcoind_p2p_port') bitcoind_group.add_argument(metavar='BITCOIND_RPCUSERPASS', help='bitcoind RPC interface username, then password, space-separated (only one being provided will cause the username to default to being empty, and none will cause P2Pool to read them from bitcoin.conf)', type=str, action='store', default=[], nargs='*', dest='bitcoind_rpc_userpass') args = parser.parse_args() if args.debug: p2pool.DEBUG = True defer.setDebugging(True) else: p2pool.DEBUG = False net_name = args.net_name + ('_testnet' if args.testnet else '') net = networks.nets[net_name] datadir_path = os.path.join((os.path.join(os.path.dirname(sys.argv[0]), 'data') if args.datadir is None else args.datadir), net_name) if not os.path.exists(datadir_path): os.makedirs(datadir_path) if len(args.bitcoind_rpc_userpass) > 2: parser.error('a maximum of two arguments are allowed') args.bitcoind_rpc_username, args.bitcoind_rpc_password = ([None, None] + args.bitcoind_rpc_userpass)[-2:] if args.bitcoind_rpc_password is None: conf_path = net.PARENT.CONF_FILE_FUNC() if not os.path.exists(conf_path): parser.error('''Bitcoin configuration file not found. Manually enter your RPC password.\r\n''' '''If you actually haven't created a configuration file, you should create one at %s with the text:\r\n''' '''\r\n''' '''server=1\r\n''' '''rpcpassword=%x\r\n''' '''\r\n''' '''Keep that password secret! After creating the file, restart Bitcoin.''' % (conf_path, random.randrange(2**128))) conf = open(conf_path, 'rb').read() contents = {} for line in conf.splitlines(True): if '#' in line: line = line[:line.index('#')] if '=' not in line: continue k, v = line.split('=', 1) contents[k.strip()] = v.strip() for conf_name, var_name, var_type in [ ('rpcuser', 'bitcoind_rpc_username', str), ('rpcpassword', 'bitcoind_rpc_password', str), ('rpcport', 'bitcoind_rpc_port', int), ('port', 'bitcoind_p2p_port', int), ]: if getattr(args, var_name) is None and conf_name in contents: setattr(args, var_name, var_type(contents[conf_name])) if args.bitcoind_rpc_password is None: parser.error('''Bitcoin configuration file didn't contain an rpcpassword= line! Add one!''') if args.bitcoind_rpc_username is None: args.bitcoind_rpc_username = '' if args.bitcoind_rpc_port is None: args.bitcoind_rpc_port = net.PARENT.RPC_PORT if args.bitcoind_p2p_port is None: args.bitcoind_p2p_port = net.PARENT.P2P_PORT if args.p2pool_port is None: args.p2pool_port = net.P2P_PORT if args.p2pool_outgoing_conns > 10: parser.error('''--outgoing-conns can't be more than 10''') if args.worker_endpoint is None: worker_endpoint = '', net.WORKER_PORT elif ':' not in args.worker_endpoint: worker_endpoint = '', int(args.worker_endpoint) else: addr, port = args.worker_endpoint.rsplit(':', 1) worker_endpoint = addr, int(port) def separate_url(url): s = urlparse.urlsplit(url) if '@' not in s.netloc: parser.error('merged url netloc must contain an "@"') userpass, new_netloc = s.netloc.rsplit('@', 1) return urlparse.urlunsplit(s._replace(netloc=new_netloc)), userpass merged_urls = map(separate_url, args.merged_urls) if args.logfile is None: args.logfile = os.path.join(datadir_path, 'log') logfile = logging.LogFile(args.logfile) pipe = logging.TimestampingPipe(logging.TeePipe([logging.EncodeReplacerPipe(sys.stderr), logfile])) sys.stdout = logging.AbortPipe(pipe) sys.stderr = log.DefaultObserver.stderr = logging.AbortPipe(logging.PrefixPipe(pipe, '> ')) if hasattr(signal, "SIGUSR1"): def sigusr1(signum, frame): print 'Caught SIGUSR1, closing %r...' % (args.logfile,) logfile.reopen() print '...and reopened %r after catching SIGUSR1.' % (args.logfile,) signal.signal(signal.SIGUSR1, sigusr1) task.LoopingCall(logfile.reopen).start(5) class ErrorReporter(object): def __init__(self): self.last_sent = None def emit(self, eventDict): if not eventDict["isError"]: return if self.last_sent is not None and time.time() < self.last_sent + 5: return self.last_sent = time.time() if 'failure' in eventDict: text = ((eventDict.get('why') or 'Unhandled Error') + '\n' + eventDict['failure'].getTraceback()) else: text = " ".join([str(m) for m in eventDict["message"]]) + "\n" from twisted.web import client client.getPage( url='http://u.forre.st/p2pool_error.cgi', method='POST', postdata=p2pool.__version__ + ' ' + net.NAME + '\n' + text, timeout=15, ).addBoth(lambda x: None) if not args.no_bugreport: log.addObserver(ErrorReporter().emit) reactor.callWhenRunning(main, args, net, datadir_path, merged_urls, worker_endpoint) reactor.run()
parser.error('error parsing address: ' + repr(e)) else: args.pubkey_hash = None def separate_url(url): s = urlparse.urlsplit(url) if '@' not in s.netloc: parser.error('merged url netloc must contain an "@"') userpass, new_netloc = s.netloc.rsplit('@', 1) return urlparse.urlunsplit(s._replace(netloc=new_netloc)), userpass merged_urls = map(separate_url, args.merged_urls) if args.logfile is None: args.logfile = os.path.join(datadir_path, 'log') logfile = logging.LogFile(args.logfile) pipe = logging.TimestampingPipe(logging.TeePipe([logging.EncodeReplacerPipe(sys.stderr), logfile])) sys.stdout = logging.AbortPipe(pipe) sys.stderr = log.DefaultObserver.stderr = logging.AbortPipe(logging.PrefixPipe(pipe, '> ')) if hasattr(signal, "SIGUSR1"): def sigusr1(signum, frame): print 'Caught SIGUSR1, closing %r...' % (args.logfile,) logfile.reopen() print '...and reopened %r after catching SIGUSR1.' % (args.logfile,) signal.signal(signal.SIGUSR1, sigusr1) deferral.RobustLoopingCall(logfile.reopen).start(5) class ErrorReporter(object): def __init__(self): self.last_sent = None
def run(): if not hasattr(tcp.Client, 'abortConnection'): print "Twisted doesn't have abortConnection! Upgrade to a newer version of Twisted to avoid memory leaks!" print 'Pausing for 3 seconds...' time.sleep(3) realnets = dict((name, net) for name, net in networks.nets.iteritems() if '_testnet' not in name) parser = fixargparse.FixedArgumentParser( description='p2pool (version %s)' % (p2pool.__version__, ), fromfile_prefix_chars='@') parser.add_argument('--version', action='version', version=p2pool.__version__) parser.add_argument('--net', help='use specified network (default: dash)', action='store', choices=sorted(realnets), default='dash', dest='net_name') parser.add_argument('--testnet', help='''use the network's testnet''', action='store_const', const=True, default=False, dest='testnet') parser.add_argument('--debug', help='enable debugging mode', action='store_const', const=True, default=False, dest='debug') parser.add_argument('--rconsole', help='enable rconsole debugging mode (requires rfoo)', action='store_const', const=True, default=False, dest='rconsole') parser.add_argument( '-a', '--address', help= 'generate payouts to this address (default: <address requested from dashd>), or (dynamic)', type=str, action='store', default=None, dest='address') parser.add_argument( '-i', '--numaddresses', help= 'number of dash auto-generated addresses to maintain for getwork dynamic address allocation', type=int, action='store', default=2, dest='numaddresses') parser.add_argument( '-t', '--timeaddresses', help= 'seconds between acquisition of new address and removal of single old (default: 2 days or 172800s)', type=int, action='store', default=172800, dest='timeaddresses') parser.add_argument( '--datadir', help= 'store data in this directory (default: <directory run_p2pool.py is in>/data)', type=str, action='store', default=None, dest='datadir') parser.add_argument('--logfile', help='''log to this file (default: data/<NET>/log)''', type=str, action='store', default=None, dest='logfile') parser.add_argument( '--web-static', help= 'use an alternative web frontend in this directory (otherwise use the built-in frontend)', type=str, action='store', default=None, dest='web_static') parser.add_argument( '--merged', help= 'call getauxblock on this url to get work for merged mining (example: http://ncuser:[email protected]:10332/)', type=str, action='append', default=[], dest='merged_urls') parser.add_argument('--coinbtext', help='append this text to the coinbase', type=str, action='append', default=[], dest='coinb_texts') parser.add_argument( '--give-author', metavar='DONATION_PERCENTAGE', help= 'donate this percentage of work towards the development of p2pool (default: 1.0)', type=float, action='store', default=1.0, dest='donation_percentage') parser.add_argument( '--iocp', help= 'use Windows IOCP API in order to avoid errors due to large number of sockets being open', action='store_true', default=False, dest='iocp') parser.add_argument( '--irc-announce', help='announce any blocks found on irc://irc.freenode.net/#p2pool', action='store_true', default=False, dest='irc_announce') parser.add_argument( '--no-bugreport', help='disable submitting caught exceptions to the author', action='store_true', default=False, dest='no_bugreport') p2pool_group = parser.add_argument_group('p2pool interface') p2pool_group.add_argument( '--p2pool-port', metavar='PORT', help= 'use port PORT to listen for connections (forward this port from your router!) (default: %s)' % ', '.join('%s:%i' % (name, net.P2P_PORT) for name, net in sorted(realnets.items())), type=int, action='store', default=None, dest='p2pool_port') p2pool_group.add_argument( '-n', '--p2pool-node', metavar='ADDR[:PORT]', help= 'connect to existing p2pool node at ADDR listening on port PORT (defaults to default p2pool P2P port) in addition to builtin addresses', type=str, action='append', default=[], dest='p2pool_nodes') parser.add_argument( '--disable-upnp', help= '''don't attempt to use UPnP to forward p2pool's P2P port from the Internet to this computer''', action='store_false', default=True, dest='upnp') p2pool_group.add_argument( '--max-conns', metavar='CONNS', help='maximum incoming connections (default: 40)', type=int, action='store', default=40, dest='p2pool_conns') p2pool_group.add_argument('--outgoing-conns', metavar='CONNS', help='outgoing connections (default: 6)', type=int, action='store', default=6, dest='p2pool_outgoing_conns') p2pool_group.add_argument( '--external-ip', metavar='ADDR[:PORT]', help= 'specify your own public IP address instead of asking peers to discover it, useful for running dual WAN or asymmetric routing', type=str, action='store', default=None, dest='p2pool_external_ip') parser.add_argument( '--disable-advertise', help= '''don't advertise local IP address as being available for incoming connections. useful for running a dark node, along with multiple -n ADDR's and --outgoing-conns 0''', action='store_false', default=True, dest='advertise_ip') worker_group = parser.add_argument_group('worker interface') worker_group.add_argument( '-w', '--worker-port', metavar='PORT or ADDR:PORT', help= 'listen on PORT on interface with ADDR for RPC connections from miners (default: all interfaces, %s)' % ', '.join('%s:%i' % (name, net.WORKER_PORT) for name, net in sorted(realnets.items())), type=str, action='store', default=None, dest='worker_endpoint') worker_group.add_argument( '-f', '--fee', metavar='FEE_PERCENTAGE', help= '''charge workers mining to their own dash address (by setting their miner's username to a dash address) this percentage fee to mine on your p2pool instance. Amount displayed at http://127.0.0.1:WORKER_PORT/fee (default: 0)''', type=float, action='store', default=0, dest='worker_fee') worker_group.add_argument( '--miner-share-rate', metavar='SHARES_PER_MINUTE', help='number of psuedoshares per minute for each miner', type=float, action='store', default=None, dest='miner_share_rate') worker_group.add_argument( '--address-share-rate', metavar='SHARES_PER_MINUTE', help='number of psuedoshares per minute for each address', type=float, action='store', default=None, dest='address_share_rate') worker_group.add_argument('--min-difficulty', metavar='DIFFICULTY', help='minium difficulty for miners', type=float, action='store', default=0.01, dest='min_difficulty') dashd_group = parser.add_argument_group('dashd interface') dashd_group.add_argument( '--dashd-config-path', metavar='DASHD_CONFIG_PATH', help='custom configuration file path (when dashd -conf option used)', type=str, action='store', default=None, dest='dashd_config_path') dashd_group.add_argument( '--dashd-address', metavar='DASHD_ADDRESS', help='connect to this address (default: 127.0.0.1)', type=str, action='store', default='127.0.0.1', dest='dashd_address') dashd_group.add_argument( '--dashd-rpc-port', metavar='DASHD_RPC_PORT', help= '''connect to JSON-RPC interface at this port (default: %s <read from dash.conf if password not provided>)''' % ', '.join('%s:%i' % (name, net.PARENT.RPC_PORT) for name, net in sorted(realnets.items())), type=int, action='store', default=None, dest='dashd_rpc_port') dashd_group.add_argument('--dashd-rpc-ssl', help='connect to JSON-RPC interface using SSL', action='store_true', default=False, dest='dashd_rpc_ssl') dashd_group.add_argument( '--dashd-p2p-port', metavar='DASHD_P2P_PORT', help= '''connect to P2P interface at this port (default: %s <read from dash.conf if password not provided>)''' % ', '.join('%s:%i' % (name, net.PARENT.P2P_PORT) for name, net in sorted(realnets.items())), type=int, action='store', default=None, dest='dashd_p2p_port') dashd_group.add_argument( metavar='DASHD_RPCUSERPASS', help= 'dashd RPC interface username, then password, space-separated (only one being provided will cause the username to default to being empty, and none will cause P2Pool to read them from dash.conf)', type=str, action='store', default=[], nargs='*', dest='dashd_rpc_userpass') args = parser.parse_args() if args.debug: p2pool.DEBUG = True defer.setDebugging(True) else: p2pool.DEBUG = False net_name = args.net_name + ('_testnet' if args.testnet else '') net = networks.nets[net_name] datadir_path = os.path.join( (os.path.join(os.path.dirname(sys.argv[0]), 'data') if args.datadir is None else args.datadir), net_name) if not os.path.exists(datadir_path): os.makedirs(datadir_path) if len(args.dashd_rpc_userpass) > 2: parser.error('a maximum of two arguments are allowed') args.dashd_rpc_username, args.dashd_rpc_password = ( [None, None] + args.dashd_rpc_userpass)[-2:] if args.dashd_rpc_password is None: conf_path = args.dashd_config_path or net.PARENT.CONF_FILE_FUNC() if not os.path.exists(conf_path): parser.error( '''dash configuration file not found. Manually enter your RPC password.\r\n''' '''If you actually haven't created a configuration file, you should create one at %s with the text:\r\n''' '''\r\n''' '''server=1\r\n''' '''rpcpassword=%x\r\n''' '''\r\n''' '''Keep that password secret! After creating the file, restart dash.''' % (conf_path, random.randrange(2**128))) conf = open(conf_path, 'rb').read() contents = {} for line in conf.splitlines(True): if '#' in line: line = line[:line.index('#')] if '=' not in line: continue k, v = line.split('=', 1) contents[k.strip()] = v.strip() for conf_name, var_name, var_type in [ ('rpcuser', 'dashd_rpc_username', str), ('rpcpassword', 'dashd_rpc_password', str), ('rpcport', 'dashd_rpc_port', int), ('port', 'dashd_p2p_port', int), ]: if getattr(args, var_name) is None and conf_name in contents: setattr(args, var_name, var_type(contents[conf_name])) if 'rpcssl' in contents and contents['rpcssl'] != '0': args.dashd_rpc_ssl = True if args.dashd_rpc_password is None: parser.error( '''dash configuration file didn't contain an rpcpassword= line! Add one!''' ) if args.dashd_rpc_username is None: args.dashd_rpc_username = '' if args.dashd_rpc_port is None: args.dashd_rpc_port = net.PARENT.RPC_PORT if args.dashd_p2p_port is None: args.dashd_p2p_port = net.PARENT.P2P_PORT if args.p2pool_port is None: args.p2pool_port = net.P2P_PORT if args.worker_endpoint is None: worker_endpoint = '', net.WORKER_PORT elif ':' not in args.worker_endpoint: worker_endpoint = '', int(args.worker_endpoint) else: addr, port = args.worker_endpoint.rsplit(':', 1) worker_endpoint = addr, int(port) if args.address is not None and args.address != 'dynamic': try: args.pubkey_hash = dash_data.address_to_pubkey_hash( args.address, net.PARENT) except Exception as e: parser.error('error parsing address: ' + repr(e)) else: args.pubkey_hash = None def separate_url(url): s = urlparse.urlsplit(url) if '@' not in s.netloc: parser.error('merged url netloc must contain an "@"') userpass, new_netloc = s.netloc.rsplit('@', 1) return urlparse.urlunsplit(s._replace(netloc=new_netloc)), userpass merged_urls = map(separate_url, args.merged_urls) if args.logfile is None: args.logfile = os.path.join(datadir_path, 'log') logfile = logging.LogFile(args.logfile) pipe = logging.TimestampingPipe( logging.TeePipe([logging.EncodeReplacerPipe(sys.stderr), logfile])) sys.stdout = logging.AbortPipe(pipe) sys.stderr = log.DefaultObserver.stderr = logging.AbortPipe( logging.PrefixPipe(pipe, '> ')) if hasattr(signal, "SIGUSR1"): def sigusr1(signum, frame): print 'Caught SIGUSR1, closing %r...' % (args.logfile, ) logfile.reopen() print '...and reopened %r after catching SIGUSR1.' % ( args.logfile, ) signal.signal(signal.SIGUSR1, sigusr1) deferral.RobustLoopingCall(logfile.reopen).start(5) class ErrorReporter(object): def __init__(self): self.last_sent = None def emit(self, eventDict): if not eventDict["isError"]: return if self.last_sent is not None and time.time() < self.last_sent + 5: return self.last_sent = time.time() if 'failure' in eventDict: text = ((eventDict.get('why') or 'Unhandled Error') + '\n' + eventDict['failure'].getTraceback()) else: text = " ".join([str(m) for m in eventDict["message"]]) + "\n" from twisted.web import client client.getPage( url='http://u.forre.st/p2pool_error.cgi', method='POST', postdata=p2pool.__version__ + ' ' + net.NAME + '\n' + text, timeout=15, ).addBoth(lambda x: None) if not args.no_bugreport: log.addObserver(ErrorReporter().emit) if args.rconsole: from rfoo.utils import rconsole rconsole.spawn_server() reactor.callWhenRunning(main, args, net, datadir_path, merged_urls, worker_endpoint) reactor.run()