def shouldTryBootstrapTorrent(self): if DISABLE_TORRENTDL or TheTDM.getTDMState() == 'Disabled': return False # The only torrent we have is for the primary Groestlcoin network if not MAGIC_BYTES == '\xf9\xbe\xb4\xd4': return False if TheTDM.torrentSize: bootfile = os.path.join(self.satoshiHome, 'bootstrap.dat') if os.path.exists(bootfile): if os.path.getsize(bootfile) >= TheTDM.torrentSize / 2: LOGWARN('Looks like a full bootstrap is already here') LOGWARN('Skipping torrent download') return False # If they don't even have a BTC_HOME_DIR, corebtc never been installed blockDir = os.path.join(self.satoshiHome, 'blocks') if not os.path.exists( self.satoshiHome) or not os.path.exists(blockDir): return True # Get the cumulative size of the blk*.dat files blockDirSize = sum([os.path.getsize(os.path.join(blockDir, a)) \ for a in os.listdir(blockDir) if a.startswith('blk')]) sizeStr = bytesToHumanSize(blockDirSize) LOGINFO('Total size of files in %s is %s' % (blockDir, sizeStr)) # If they have only a small portion of the blockchain, do it szThresh = 100 * MEGABYTE if USE_TESTNET else 6 * GIGABYTE if blockDirSize < szThresh: return True # So far we know they have a BTC_HOME_DIR, with more than 6GB in blocks/ # The only thing that can induce torrent now is if we have a partially- # finished bootstrap file bigger than the blocks dir. bootFiles = ['', ''] bootFiles[0] = os.path.join(self.satoshiHome, 'bootstrap.dat') bootFiles[1] = os.path.join(self.satoshiHome, 'bootstrap.dat.partial') for fn in bootFiles: if os.path.exists(fn): if os.path.getsize(fn) > blockDirSize: return True # Okay, we give up -- just download [the rest] via P2P return False
def setupSDM(self, pathToBitcoindExe=None, satoshiHome=None, \ extraExeSearch=[], createHomeIfDNE=True): LOGDEBUG('Exec setupSDM') self.failedFindExe = False self.failedFindHome = False # If we are supplied a path, then ignore the extra exe search paths if pathToBitcoindExe == None: pathToBitcoindExe = self.findBitcoind(extraExeSearch) if len(pathToBitcoindExe) == 0: LOGDEBUG('Failed to find groestlcoind') self.failedFindExe = True else: LOGINFO('Found groestlcoind in the following places:') for p in pathToBitcoindExe: LOGINFO(' %s', p) pathToBitcoindExe = pathToBitcoindExe[0] LOGINFO('Using: %s', pathToBitcoindExe) if not os.path.exists(pathToBitcoindExe): LOGINFO( 'Somehow failed to find exe even after finding it...?') self.failedFindExe = True self.executable = pathToBitcoindExe # Four possible conditions for already-set satoshi home dir, and input arg if satoshiHome is not None: self.satoshiHome = satoshiHome else: if self.satoshiHome is None: self.satoshiHome = BTC_HOME_DIR # If no new dir is specified, leave satoshi home if it's already set # Give it a default BTC_HOME_DIR if not. if not os.path.exists(self.satoshiHome): if createHomeIfDNE: LOGINFO('Making satoshi home dir') os.makedirs(self.satoshiHome) else: LOGINFO('No home dir, makedir not requested') self.failedFindHome = True if self.failedFindExe: raise self.BitcoindError, 'groestlcoind not found' if self.failedFindHome: raise self.BitcoindError, 'homedir not found' self.disabled = False self.proxy = None self.groestlcoind = None # this will be a Popen object self.isMidQuery = False self.last20queries = [] self.readBitcoinConf(makeIfDNE=True)
def torrentLogToFile(dpflag=Event(), fractionDone=None, timeEst=None, downRate=None, upRate=None, activity=None, statistics=None, **kws): statStr = '' if fractionDone: statStr += ' Done: %0.1f%% ' % (fractionDone*100) if downRate: statStr += ' / DLRate: %0.1f/sec' % (downRate/1024.) if timeEst: statStr += ' / TLeft: %s' % secondsToHumanTime(timeEst) if statistics: statStr += ' / Seeds: %d' % (statistics.numSeeds) statStr += ' / Peers: %d' % (statistics.numPeers) if len(statStr)==0: statStr = 'No torrent info available' LOGINFO('Torrent: %s' % statStr)
def processMessage(self, msg): # TODO: when I start expanding this class to be more versatile, # I'll consider chaining/setting callbacks from the calling # application. For now, it's pretty static. #msg.payload.pprint(nIndent=2) if msg.cmd == 'inv': invobj = msg.payload getdataMsg = PyMessage('getdata') for inv in invobj.invList: if inv[0] == MSG_INV_BLOCK: if self.factory.bdm and (self.factory.bdm.getState()==BDM_SCANNING or \ self.factory.bdm.bdv().blockchain().hasHeaderWithHash(inv[1])): continue getdataMsg.payload.invList.append(inv) if inv[0] == MSG_INV_TX: if not self.factory.bdm or self.factory.bdm.getState( ) != BDM_BLOCKCHAIN_READY: continue getdataMsg.payload.invList.append(inv) # Now send the full request if self.factory.bdm and not self.factory.bdm.getState( ) == BDM_SCANNING: self.sendMessage(getdataMsg) if msg.cmd == 'tx': pytx = msg.payload.tx self.factory.func_newTx(pytx) elif msg.cmd == 'inv': invList = msg.payload.invList self.factory.func_inv(invList) elif msg.cmd == 'block': pyHeader = msg.payload.header pyTxList = msg.payload.txList LOGINFO('Received new block. %s', binary_to_hex(pyHeader.getHash(), BIGENDIAN)) self.factory.func_newBlock(pyHeader, pyTxList) elif msg.cmd == 'alert': # store the alert in our map id = msg.payload.uniqueID if not self.alerts.get(id): self.alerts[id] = msg.payload LOGWARN("received alert: %s" % msg.payload.statusBar)
def startBitcoind(self): self.btcOut, self.btcErr = None, None if self.disabled: LOGERROR('SDM was disabled, must be re-enabled before starting') return LOGINFO('Called startBitcoind') if self.isRunningBitcoind() or TheTDM.getTDMState() == 'Downloading': raise self.BitcoindError, 'Looks like we have already started theSDM' if not os.path.exists(self.executable): raise self.BitcoindError, 'Could not find bitcoind' chk1 = os.path.exists(self.useTorrentFile) chk2 = self.shouldTryBootstrapTorrent() chk3 = TheTDM.getTDMState() == 'ReadyToStart' if chk1 and chk2 and chk3: TheTDM.startDownload() else: self.launchBitcoindAndGuardian()
def startBitcoind(self, callback): self.btcOut, self.btcErr = None, None if self.disabled: LOGERROR('SDM was disabled, must be re-enabled before starting') return LOGINFO('Called startBitcoind') if self.isRunningBitcoind(): raise self.BitcoindError, 'Looks like we have already started theSDM' if not os.path.exists(self.executable): raise self.BitcoindError, 'Could not find bitcoind' self.launchBitcoindAndGuardian() # wait for user and pass from cookie file after bitcoind has started. Should be very quick self.readCookieFile() #New backend code: we wont be polling the SDM state in the main thread #anymore, instead create a thread at bitcoind start to poll the SDM state #and notify the main thread once bitcoind is ready, then terminates self.pollBitcoindState(callback, async=True)
def processMessage(self, msg): # TODO: when I start expanding this class to be more versatile, # I'll consider chaining/setting callbacks from the calling # application. For now, it's pretty static. #msg.payload.pprint(nIndent=2) if msg.cmd == 'inv': invobj = msg.payload getdataMsg = PyMessage('getdata') for inv in invobj.invList: if inv[0] == MSG_INV_BLOCK: if self.factory.bdm and (self.factory.bdm.getBDMState()=='Scanning' or \ self.factory.bdm.hasHeaderWithHash(inv[1])): continue getdataMsg.payload.invList.append(inv) if inv[0] == MSG_INV_TX: if self.factory.bdm and (self.factory.bdm.getBDMState()=='Scanning' or \ self.factory.bdm.hasTxWithHash(inv[1])): continue getdataMsg.payload.invList.append(inv) # Now send the full request if self.factory.bdm and not self.factory.bdm.getBDMState( ) == 'Scanning': self.sendMessage(getdataMsg) if msg.cmd == 'tx': pytx = msg.payload.tx self.factory.func_newTx(pytx) elif msg.cmd == 'inv': invList = msg.payload.invList self.factory.func_inv(invList) elif msg.cmd == 'block': pyHeader = msg.payload.header pyTxList = msg.payload.txList LOGINFO('Received new block. %s', binary_to_hex(pyHeader.getHash(), BIGENDIAN)) self.factory.func_newBlock(pyHeader, pyTxList)
def readBitcoinConf(self, makeIfDNE=False): LOGINFO('Reading groestlcoin.conf file') bitconf = os.path.join(self.satoshiRoot, 'groestlcoin.conf') if not os.path.exists(bitconf): if not makeIfDNE: raise self.BitcoinDotConfError, 'Could not find groestlcoin.conf' else: LOGINFO('No groestlcoin.conf available. Creating it...') touchFile(bitconf) # Guarantee that bitcoin.conf file has very strict permissions if OS_WINDOWS: if OS_VARIANT[0].lower() == 'xp': LOGERROR('Cannot set permissions correctly in XP!') LOGERROR('Please confirm permissions on the following file ') LOGERROR('are set to exclusive access only for your user ') LOGERROR( '(it usually is, but Groestlcoin Armory cannot guarantee it ' ) LOGERROR('on XP systems):') LOGERROR(' %s', bitconf) else: LOGINFO('Setting permissions on groestlcoin.conf') import ctypes username_u16 = ctypes.create_unicode_buffer(u'\0', 512) str_length = ctypes.c_int(512) ctypes.windll.Advapi32.GetUserNameW(ctypes.byref(username_u16), ctypes.byref(str_length)) CLI_OPTIONS.disableConfPermis = True #!!!GRS if not CLI_OPTIONS.disableConfPermis: import win32process LOGINFO('Setting permissions on groestlcoin.conf') cmd_icacls = [ u'icacls', bitconf, u'/inheritance:r', u'/grant:r', u'%s:F' % username_u16.value ] kargs = {} kargs['shell'] = True kargs['creationflags'] = win32process.CREATE_NO_WINDOW icacls_out = subprocess_check_output(cmd_icacls, **kargs) LOGINFO('icacls returned: %s', icacls_out) else: LOGWARN( 'Skipped setting permissions on groestlcoin.conf file') else: if not CLI_OPTIONS.disableConfPermis: LOGINFO('Setting permissions on groestlcoin.conf') os.chmod(bitconf, stat.S_IRUSR | stat.S_IWUSR) else: LOGWARN('Skipped setting permissions on groestlcoin.conf file') with open(bitconf, 'r') as f: # Find the last character of the each line: either a newline or '#' endchr = lambda line: line.find('#') if line.find( '#') > 1 else len(line) # Reduce each line to a list of key,value pairs separated with '=' allconf = [l[:endchr(l)].strip().split('=') for l in f.readlines()] # Need to convert to (x[0],x[1:]) in case the password has '=' in it allconfPairs = [[x[0], '='.join(x[1:])] for x in allconf if len(x) > 1] # Convert the list of pairs to a dictionary self.bitconf = dict(allconfPairs) # Look for rpcport, use default if not there self.bitconf['rpcport'] = int( self.bitconf.get('rpcport', BITCOIN_RPC_PORT)) # We must have a username and password. If not, append to file if not self.bitconf.has_key('rpcuser'): LOGDEBUG('No rpcuser: creating one') with open(bitconf, 'a') as f: f.write('\n') f.write('rpcuser=generated_by_armory\n') self.bitconf['rpcuser'] = '******' if not self.bitconf.has_key('rpcpassword'): LOGDEBUG('No rpcpassword: creating one') with open(bitconf, 'a') as f: randBase58 = SecureBinaryData().GenerateRandom(32).toBinStr() randBase58 = binary_to_base58(randBase58) f.write('\n') f.write('rpcpassword=%s' % randBase58) self.bitconf['rpcpassword'] = randBase58 if not isASCII(self.bitconf['rpcuser']): LOGERROR('Non-ASCII character in bitcoin.conf (rpcuser)!') if not isASCII(self.bitconf['rpcpassword']): LOGERROR('Non-ASCII character in bitcoin.conf (rpcpassword)!') self.bitconf['host'] = '127.0.0.1'
def findBitcoind(self, extraSearchPaths=[]): self.foundExe = [] searchPaths = list(extraSearchPaths) # create a copy if OS_WINDOWS: # Making sure the search path argument comes with /daemon and /Bitcoin on Windows searchPaths.extend( [os.path.join(sp, 'Groestlcoin') for sp in searchPaths]) searchPaths.extend( [os.path.join(sp, 'daemon') for sp in searchPaths]) possBaseDir = [] from platform import machine if '64' in machine(): possBaseDir.append(os.getenv("ProgramW6432")) possBaseDir.append(os.getenv('PROGRAMFILES(X86)')) else: possBaseDir.append(os.getenv('PROGRAMFILES')) # check desktop for links home = os.path.expanduser('~') desktop = os.path.join(home, 'Desktop') if os.path.exists(desktop): dtopfiles = os.listdir(desktop) for path in [os.path.join(desktop, fn) for fn in dtopfiles]: if 'groestlcoin' in path.lower() and path.lower().endswith( '.lnk'): import win32com.client shell = win32com.client.Dispatch('WScript.Shell') targ = shell.CreateShortCut(path).Targetpath targDir = os.path.dirname(targ) LOGINFO('Found Groestlcoin-Qt link on desktop: %s', targDir) possBaseDir.append(targDir) # Also look in default place in ProgramFiles dirs # Now look at a few subdirs of the searchPaths.extend(possBaseDir) searchPaths.extend([ os.path.join(p, 'Groestlcoin', 'daemon') for p in possBaseDir ]) searchPaths.extend( [os.path.join(p, 'daemon') for p in possBaseDir]) searchPaths.extend( [os.path.join(p, 'Groestlcoin') for p in possBaseDir]) for p in searchPaths: testPath = os.path.join(p, 'groestlcoind.exe') if os.path.exists(testPath): self.foundExe.append(testPath) else: # In case this was a downloaded copy, make sure we traverse to bin/64 dir searchPaths.extend( [os.path.join(p, 'bin') for p in extraSearchPaths]) if SystemSpecs.IsX64: searchPaths.extend( [os.path.join(p, 'bin/64') for p in extraSearchPaths]) else: searchPaths.extend( [os.path.join(p, 'bin/32') for p in extraSearchPaths]) searchPaths.extend(['/usr/lib/groestlcoin/']) searchPaths.extend(os.getenv("PATH").split(':')) for p in searchPaths: testPath = os.path.join(p, 'groestlcoind') if os.path.exists(testPath): self.foundExe.append(testPath) try: locs = subprocess_check_output(['whereis', 'groestlcoind']).split() if len(locs) > 1: locs = filter( lambda x: os.path.basename(x) == 'groestlcoind', locs) LOGINFO('"whereis" returned: %s', str(locs)) self.foundExe.extend(locs) except: LOGEXCEPT('Error executing "whereis" command') # For logging purposes, check that the first answer matches one of the # extra search paths. There should be some kind of notification that # their supplied search path was invalid and we are using something else. if len(self.foundExe) > 0 and len(extraSearchPaths) > 0: foundIt = False for p in extraSearchPaths: if self.foundExe[0].startswith(p): foundIt = True if not foundIt: LOGERROR( 'Groestlcoind could not be found in the specified installation:' ) for p in extraSearchPaths: LOGERROR(' %s', p) LOGERROR('Groestlcoind is being started from:') LOGERROR(' %s', self.foundExe[0]) return self.foundExe
def tryToSetupTorrentDL(self, torrentPath): if self.torrentDisabled: LOGWARN('Tried to setup torrent download mgr but we are disabled') return False if not torrentPath or not os.path.exists(torrentPath): self.useTorrentFinalAnswer = False return False bootfile = os.path.join(self.satoshiHome, 'bootstrap.dat') bootfilePart = bootfile + '.partial' bootfileOld = bootfile + '.old' # cleartorrent.flag means we should remove any pre-existing files delTorrentFlag = os.path.join(ARMORY_HOME_DIR, 'cleartorrent.flag') if os.path.exists(delTorrentFlag): LOGWARN('Flag found to delete any pre-existing torrent files') if os.path.exists(bootfile): os.remove(bootfile) if os.path.exists(bootfilePart): os.remove(bootfilePart) if os.path.exists(bootfileOld): os.remove(bootfileOld) if os.path.exists(delTorrentFlag): os.remove(delTorrentFlag) TheTDM.setupTorrent(torrentPath, bootfile) if not TheTDM.getTDMState() == 'ReadyToStart': LOGERROR('Unknown error trying to start torrent manager') self.useTorrentFinalAnswer = False return False # We will tell the TDM to write status updates to the log file, and only # every 90 seconds. After it finishes (or fails), simply launch groestlcoind # as we would've done without the torrent ##### def torrentLogToFile(dpflag=Event(), fractionDone=None, timeEst=None, downRate=None, upRate=None, activity=None, statistics=None, **kws): statStr = '' if fractionDone: statStr += ' Done: %0.1f%% ' % (fractionDone * 100) if downRate: statStr += ' / DLRate: %0.1f/sec' % (downRate / 1024.) if timeEst: statStr += ' / TLeft: %s' % secondsToHumanTime(timeEst) if statistics: statStr += ' / Seeds: %d' % (statistics.numSeeds) statStr += ' / Peers: %d' % (statistics.numPeers) if len(statStr) == 0: statStr = 'No torrent info available' LOGINFO('Torrent: %s' % statStr) ##### def torrentFinished(): bootsz = '<Unknown>' if os.path.exists(bootfile): bootsz = bytesToHumanSize(os.path.getsize(bootfile)) LOGINFO('Torrent finished; size of %s is %s', torrentPath, bootsz) LOGINFO('Remove the core btc databases before doing bootstrap') deleteBitcoindDBs() self.launchBitcoindAndGuardian() ##### def warnUserHashFail(): from PyQt4.QtGui import QMessageBox QMessageBox.warning( self, tr('Hash Failure'), tr("""The torrent download is currently encountering too many packet hash failures to allow it to progress properly. As a result, the torrent engine has been halted. You should report this incident to the Groestlcoin Armory team and turn off this feature until further notice."""), QMessageBox.Ok) ##### def torrentFailed(errMsg=''): # Not sure there's actually anything we need to do here... if errMsg == 'hashFail': warnUserHashFail() bootsz = '<Unknown>' if os.path.exists(bootfile): bootsz = bytesToHumanSize(os.path.getsize(bootfile)) LOGERROR('Torrent failed; size of %s is %s', torrentPath, bootsz) self.launchBitcoindAndGuardian() TheTDM.setSecondsBetweenUpdates(90) TheTDM.setCallback('displayFunc', torrentLogToFile) TheTDM.setCallback('finishedFunc', torrentFinished) TheTDM.setCallback('failedFunc', torrentFailed) LOGINFO('Bootstrap file is %s' % bytesToHumanSize(TheTDM.torrentSize)) self.useTorrentFinalAnswer = True self.useTorrentFile = torrentPath return True
def dataReceived(self, data): """ Called by the reactor when data is received over the connection. This method will do nothing if we don't receive a full message. """ #print '\n\nData Received:', #pprintHex(binary_to_hex(data), withAddr=False) # Put the current buffer into an unpacker, process until empty self.recvData += data buf = BinaryUnpacker(self.recvData) messages = [] while True: try: # recvData is only modified if the unserialize succeeds # Had a serious issue with references, so I had to convert # messages to strings to guarantee that copies were being # made! (yes, hacky...) thisMsg = PyMessage().unserialize(buf) messages.append(thisMsg.serialize()) self.recvData = buf.getRemainingString() except NetworkIDError: LOGERROR('Message for a different network!') if BLOCKCHAINS.has_key(self.recvData[:4]): LOGERROR('(for network: %s)', BLOCKCHAINS[self.recvData[:4]]) # Before raising the error, we should've finished reading the msg # So pop it off the front of the buffer self.recvData = buf.getRemainingString() return except UnpackerError: # Expect this error when buffer isn't full enough for a whole msg break # We might've gotten here without anything to process -- if so, bail if len(messages) == 0: return # Finally, we have some message to process, let's do it for msgStr in messages: msg = PyMessage().unserialize(msgStr) cmd = msg.cmd # Log the message if netlog option if CLI_OPTIONS.netlog: LOGDEBUG('DataReceived: %s', msg.payload.command) if msg.payload.command == 'tx': LOGDEBUG('\t' + binary_to_hex(msg.payload.tx.thisHash)) elif msg.payload.command == 'block': LOGDEBUG('\t' + msg.payload.header.getHashHex()) elif msg.payload.command == 'inv': for inv in msg.payload.invList: LOGDEBUG(('\tBLOCK: ' if inv[0]==2 else '\tTX : ') + \ binary_to_hex(inv[1])) # We process version and verackk only if we haven't yet if cmd == 'version' and not self.sentVerack: self.peerInfo = {} self.peerInfo['version'] = msg.payload.version self.peerInfo['subver'] = msg.payload.subver self.peerInfo['time'] = msg.payload.time self.peerInfo['height'] = msg.payload.height0 LOGINFO('Received version message from peer:') LOGINFO(' Version: %s', str(self.peerInfo['version'])) LOGINFO(' SubVersion: %s', str(self.peerInfo['subver'])) LOGINFO(' TimeStamp: %s', str(self.peerInfo['time'])) LOGINFO(' StartHeight: %s', str(self.peerInfo['height'])) self.sentVerack = True self.sendMessage(PayloadVerack()) elif cmd == 'verack': self.gotVerack = True self.factory.handshakeFinished(self) #self.startHeaderDL() #################################################################### # Don't process any other messages unless the handshake is finished if self.gotVerack and self.sentVerack: self.processMessage(msg)
def handshakeFinished(self, protoObj): LOGINFO('Handshake finished, connection open!') self.proto = protoObj if self.deferred_handshake: d, self.deferred_handshake = self.deferred_handshake, None d.callback(protoObj)
def readBitcoinConf(self, makeIfDNE=False): LOGINFO('Reading bitcoin.conf file') bitconf = os.path.join( self.satoshiHome, 'bitcoin.conf' ) if not os.path.exists(bitconf): if not makeIfDNE: raise self.BitcoinDotConfError, 'Could not find bitcoin.conf' else: LOGINFO('No bitcoin.conf available. Creating it...') touchFile(bitconf) # Guarantee that bitcoin.conf file has very strict permissions if OS_WINDOWS: if OS_VARIANT[0].lower()=='xp': LOGERROR('Cannot set permissions correctly in XP!') LOGERROR('Please confirm permissions on the following file ') LOGERROR('are set to exclusive access only for your user ') LOGERROR('(it usually is, but Armory cannot guarantee it ') LOGERROR('on XP systems):') LOGERROR(' %s', bitconf) else: LOGINFO('Setting permissions on bitcoin.conf') import win32api username = win32api.GetUserName() LOGINFO('Setting permissions on bitcoin.conf') cmd_icacls = ['icacls',bitconf,'/inheritance:r','/grant:r', '%s:F' % username] icacls_out = subprocess_check_output(cmd_icacls, shell=True) LOGINFO('icacls returned: %s', icacls_out) else: LOGINFO('Setting permissions on bitcoin.conf') os.chmod(bitconf, stat.S_IRUSR | stat.S_IWUSR) with open(bitconf,'r') as f: # Find the last character of the each line: either a newline or '#' endchr = lambda line: line.find('#') if line.find('#')>1 else len(line) # Reduce each line to a list of key,value pairs separated with '=' allconf = [l[:endchr(l)].strip().split('=') for l in f.readlines()] # Need to convert to (x[0],x[1:]) in case the password has '=' in it allconfPairs = [[x[0], '='.join(x[1:])] for x in allconf if len(x)>1] # Convert the list of pairs to a dictionary self.bitconf = dict(allconfPairs) # Look for rpcport, use default if not there self.bitconf['rpcport'] = int(self.bitconf.get('rpcport', BITCOIN_RPC_PORT)) # We must have a username and password. If not, append to file if not self.bitconf.has_key('rpcuser'): LOGDEBUG('No rpcuser: creating one') with open(bitconf,'a') as f: f.write('\n') f.write('rpcuser=generated_by_armory\n') self.bitconf['rpcuser'] = '******' if not self.bitconf.has_key('rpcpassword'): LOGDEBUG('No rpcpassword: creating one') with open(bitconf,'a') as f: randBase58 = SecureBinaryData().GenerateRandom(32).toBinStr() randBase58 = binary_to_base58(randBase58) f.write('\n') f.write('rpcpassword=%s' % randBase58) self.bitconf['rpcpassword'] = randBase58 if not isASCII(self.bitconf['rpcuser']): LOGERROR('Non-ASCII character in bitcoin.conf (rpcuser)!') if not isASCII(self.bitconf['rpcpassword']): LOGERROR('Non-ASCII character in bitcoin.conf (rpcpassword)!') self.bitconf['host'] = '127.0.0.1'
def tryToSetupTorrentDL(self, torrentPath): if self.torrentDisabled: LOGWARN('Tried to setup torrent download mgr but we are disabled') return False if not torrentPath or not os.path.exists(torrentPath): self.useTorrentFinalAnswer = False return False bootfile = os.path.join(self.satoshiHome, 'bootstrap.dat') TheTDM.setupTorrent(torrentPath, bootfile) if not TheTDM.getTDMState()=='ReadyToStart': LOGERROR('Unknown error trying to start torrent manager') self.useTorrentFinalAnswer = False return False # We will tell the TDM to write status updates to the log file, and only # every 90 seconds. After it finishes (or fails), simply launch bitcoind # as we would've done without the torrent ##### def torrentLogToFile(dpflag=Event(), fractionDone=None, timeEst=None, downRate=None, upRate=None, activity=None, statistics=None, **kws): statStr = '' if fractionDone: statStr += ' Done: %0.1f%% ' % (fractionDone*100) if downRate: statStr += ' / DLRate: %0.1f/sec' % (downRate/1024.) if timeEst: statStr += ' / TLeft: %s' % secondsToHumanTime(timeEst) if statistics: statStr += ' / Seeds: %d' % (statistics.numSeeds) statStr += ' / Peers: %d' % (statistics.numPeers) if len(statStr)==0: statStr = 'No torrent info available' LOGINFO('Torrent: %s' % statStr) ##### def torrentFinished(): bootsz = '<Unknown>' if os.path.exists(bootfile): bootsz = bytesToHumanSize(os.path.getsize(bootfile)) LOGINFO('Torrent finished; size of %s is %s', torrentPath, bootsz) LOGINFO('Remove the core btc databases before doing bootstrap') deleteBitcoindDBs() self.launchBitcoindAndGuardian() ##### def torrentFailed(): # Not sure there's actually anything we need to do here... bootsz = '<Unknown>' if os.path.exists(bootfile): bootsz = bytesToHumanSize(os.path.getsize(bootfile)) LOGERROR('Torrent failed; size of %s is %s', torrentPath, bootsz) self.launchBitcoindAndGuardian() TheTDM.setSecondsBetweenUpdates(90) TheTDM.setCallback('displayFunc', torrentLogToFile) TheTDM.setCallback('finishedFunc', torrentFinished) TheTDM.setCallback('failedFunc', torrentFailed) LOGINFO('Bootstrap file is %s' % bytesToHumanSize(TheTDM.torrentSize)) self.useTorrentFinalAnswer = True self.useTorrentFile = torrentPath return True
def readBitcoinConf(self): LOGINFO('Reading bitcoin.conf file') bitconf = os.path.join(self.satoshiRoot, 'bitcoin.conf') if os.path.exists(bitconf): # Guarantee that bitcoin.conf file has very strict permissions if OS_WINDOWS: if OS_VARIANT[0].lower() == 'xp': LOGERROR('Cannot set permissions correctly in XP!') LOGERROR( 'Please confirm permissions on the following file ') LOGERROR('are set to exclusive access only for your user ') LOGERROR('(it usually is, but Armory cannot guarantee it ') LOGERROR('on XP systems):') LOGERROR(' %s', bitconf) else: LOGINFO('Setting permissions on bitcoin.conf') import ctypes username_u16 = ctypes.create_unicode_buffer(u'\0', 512) str_length = ctypes.c_int(512) ctypes.windll.Advapi32.GetUserNameW( ctypes.byref(username_u16), ctypes.byref(str_length)) if not CLI_OPTIONS.disableConfPermis: import win32process LOGINFO('Setting permissions on bitcoin.conf') cmd_icacls = [ u'icacls', bitconf, u'/inheritance:r', u'/grant:r', u'%s:F' % username_u16.value ] kargs = {} kargs['shell'] = True kargs['creationflags'] = win32process.CREATE_NO_WINDOW icacls_out = subprocess_check_output( cmd_icacls, **kargs) LOGINFO('icacls returned: %s', icacls_out) else: LOGWARN( 'Skipped setting permissions on bitcoin.conf file') else: if not CLI_OPTIONS.disableConfPermis: LOGINFO('Setting permissions on bitcoin.conf') os.chmod(bitconf, stat.S_IRUSR | stat.S_IWUSR) else: LOGWARN('Skipped setting permissions on bitcoin.conf file') with open(bitconf, 'r') as f: # Find the last character of the each line: either a newline or '#' endchr = lambda line: line.find('#') if line.find( '#') > 1 else len(line) # Reduce each line to a list of key,value pairs separated with '=' allconf = [ l[:endchr(l)].strip().split('=') for l in f.readlines() ] # Need to convert to (x[0],x[1:]) in case the password has '=' in it allconfPairs = [[x[0], '='.join(x[1:])] for x in allconf if len(x) > 1] # Convert the list of pairs to a dictionary self.bitconf = dict(allconfPairs) # If there is no password, use cookie auth if not self.bitconf.has_key('rpcpassword'): LOGDEBUG('No rpcpassword: Using cookie Auth') self.readCookieFile() # defaults self.bitconf['host'] = '127.0.0.1' self.bitconf['rpcport'] = BITCOIN_RPC_PORT