def setUpClass(self): # Handle both calling the this test from the context of the test directory # and calling this test from the context of the main directory. # The latter happens if you run all of the tests in the directory if os.path.exists(TIAB_ZIPFILE_NAME): tiabZipPath = TIAB_ZIPFILE_NAME elif os.path.exists(os.path.join('pytest', TIAB_ZIPFILE_NAME)): tiabZipPath = (os.path.join('pytest', TIAB_ZIPFILE_NAME)) else: self.fail(NEED_TIAB_MSG) self.tiab = TiabSession(tiabZipPath=tiabZipPath) # Need to destroy whatever BDM may have been created automatically CppBlockUtils.BlockDataManager().DestroyBDM() newTheBDM() TheBDM.setDaemon(True) TheBDM.start() TheBDM.setSatoshiDir( os.path.join(self.tiab.tiabDirectory, 'tiab', '1', 'testnet3')) self.armoryHomeDir = os.path.join(self.tiab.tiabDirectory, 'tiab', 'armory') TheBDM.setLevelDBDir( os.path.join(self.tiab.tiabDirectory, 'tiab', 'armory', 'databases')) TheBDM.setBlocking(True) TheBDM.setOnlineMode(wait=True) i = 0 while not TheBDM.getBDMState() == 'BlockchainReady' and i < 10: time.sleep(2) i += 1 if i >= 10: raise RuntimeError( "Timeout waiting for TheBDM to get into BlockchainReady state." )
def __init__(self, isOffline=False): super(BlockDataManager, self).__init__() #register callbacks self.callback = PySide_CallBack(self).__disown__() self.inject = BDM_Inject().__disown__() self.armoryDBDir = "" #dbType self.dbType = Cpp.ARMORY_DB_BARE if ENABLE_SUPERNODE: self.dbType = Cpp.ARMORY_DB_SUPER self.bdmThread = Cpp.BlockDataManagerThread( self.bdmConfig(forInit=True)) # Flags self.aboutToRescan = False self.errorOut = 0 self.currentActivity = 'None' self.walletsToRegister = [] if isOffline == True: self.bdmState = BDM_OFFLINE else: self.bdmState = BDM_UNINITIALIZED self.btcdir = BTC_HOME_DIR self.armoryDBDir = ARMORY_DB_DIR self.lastPctLoad = 0 self.topBlockHeight = 0 self.cppNotificationListenerList = []
def instantiateBDV(self, port): if self.bdmState == BDM_OFFLINE: return socketType = Cpp.SocketFcgi if self.remoteDB: socketType = Cpp.SocketHttp self.bdv_ = Cpp.BlockDataViewer_getNewBDV(\ str(ARMORYDB_IP), str(port), socketType)
def run(self, action, arg, block): try: act = '' arglist = [] # AOTODO replace with constants if action == Cpp.BDMAction_Ready: print 'BDM is ready!' act = FINISH_LOAD_BLOCKCHAIN_ACTION TheBDM.topBlockHeight = block TheBDM.setState(BDM_BLOCKCHAIN_READY) elif action == Cpp.BDMAction_ZC: act = NEW_ZC_ACTION castArg = Cpp.BtcUtils_cast_to_LedgerVector(arg) arglist = castArg elif action == Cpp.BDMAction_NewBlock: act = NEW_BLOCK_ACTION castArg = Cpp.BtcUtils_cast_to_int(arg) arglist.append(castArg) TheBDM.topBlockHeight = block elif action == Cpp.BDMAction_Refresh: act = REFRESH_ACTION castArg = Cpp.BtcUtils_cast_to_BinaryDataVector(arg) arglist = castArg elif action == Cpp.BDMAction_Exited: act = STOPPED_ACTION elif action == Cpp.BDMAction_ErrorMsg: act = WARNING_ACTION argstr = Cpp.BtcUtils_cast_to_string(arg) arglist.append(argstr) elif action == Cpp.BDMAction_StartedWalletScan: act = SCAN_ACTION argstr = Cpp.BtcUtils_cast_to_string_vec(arg) arglist.append(argstr) listenerList = TheBDM.getListenerList() for cppNotificationListener in listenerList: cppNotificationListener(act, arglist) except: LOGEXCEPT('Error in running callback') print sys.exc_info() raise
def instantiateBDV(self): if self.bdmState == BDM_OFFLINE: return socketType = Cpp.SocketFcgi if ARMORYDB_IP != ARMORYDB_DEFAULT_IP or ARMORYDB_PORT != ARMORYDB_DEFAULT_PORT: socketType = Cpp.SocketHttp self.remoteDB = True self.bdv_ = Cpp.BlockDataViewer_getNewBDV(ARMORYDB_IP, ARMORYDB_PORT, socketType)
def bdmConfig(self, forInit=False): blkdir = "" if forInit == False: # Check for the existence of the Bitcoin-Qt directory if not os.path.exists(self.btcdir): raise FileExistsError, ('Directory does not exist: %s' % self.btcdir) blkdir = os.path.join(self.btcdir, 'blocks') blk1st = os.path.join(blkdir, 'blk00000.dat') # ... and its blk000X.dat files if not os.path.exists(blk1st): LOGERROR('Blockchain data not available: %s', blk1st) raise FileExistsError, ('Blockchain data not available: %s' % blk1st) blockdir = blkdir armoryDBDir = self.armoryDBDir if OS_WINDOWS: if isinstance(blkdir, unicode): blockdir = blkdir.encode('utf8') if isinstance(self.armoryDBDir, unicode): armoryDBDir = self.armoryDBDir.encode('utf8') bdmConfig = Cpp.BlockDataManagerConfig() bdmConfig.armoryDbType = self.dbType bdmConfig.pruneType = Cpp.DB_PRUNE_NONE bdmConfig.blkFileLocation = blockdir bdmConfig.levelDBLocation = armoryDBDir bdmConfig.setGenesisBlockHash(GENESIS_BLOCK_HASH) bdmConfig.setGenesisTxHash(GENESIS_TX_HASH) bdmConfig.setMagicBytes(MAGIC_BYTES) return bdmConfig
def getCookie(self): if self.cookie == None: self.cookie = Cpp.BlockDataManagerConfig_getCookie( str(self.datadir)) return self.cookie
# NOTE: "TheBDM" is sometimes used in the C++ code to reference the # singleton BlockDataManager_LevelDB class object. Here, # "TheBDM" refers to a python BlockDataManagerThead class # object that wraps the C++ version. It implements some of # it's own methods, and then passes through anything it # doesn't recognize to the C++ object. LOGINFO('Using the asynchronous/multi-threaded BlockDataManager.') LOGINFO('Blockchain operations will happen in the background. ') LOGINFO('Devs: check TheBDM.getState() before asking for data.') LOGINFO('Registering addresses during rescans will queue them for ') LOGINFO('inclusion after the current scan is completed.') TheBDM = BlockDataManager(isOffline=False) cppLogFile = os.path.join(ARMORY_HOME_DIR, 'armorycpplog.txt') cpplf = cppLogFile if OS_WINDOWS and isinstance(cppLogFile, unicode): cpplf = cppLogFile.encode('utf8') Cpp.StartCppLogging(cpplf, 4) Cpp.EnableCppLogStdOut() #LOGINFO('LevelDB max-open-files is %d', TheBDM.getMaxOpenFiles()) # Also load the might-be-needed SatoshiDaemonManager TheSDM = SatoshiDaemonManager() # Put the import at the end to avoid circular reference problem from armoryengine.MultiSigUtils import MultiSigLockbox from armoryengine.Transaction import PyTx # kate: indent-width 3; replace-tabs on;
def randomk(): # Using Crypto++ CSPRNG instead of python's sbdRandK = CppBlockUtils.SecureBinaryData().GenerateRandom(32) hexRandK = sbdRandK.toBinStr().encode('hex_codec') return int(hexRandK, 16)
blkfile = os.path.expanduser( '~/Library/Application Support/Bitcoin/blk0001.dat') if len(sys.argv) > 1: blkfile = sys.argv[1] print '*' * 80 print 'Importing BlockUtils module...', #from CppBlockUtils import * import CppBlockUtils as Cpp print 'Done!' print '' print 'Constructing BlockDataManager... ', bdm = Cpp.BlockDataManager().getBDM() print 'Done!' print '' print 'Loading blk0001.dat... ' bdm.readBlkFile_FromScratch(blkfile) print 'Done!' print '' print 'Organizing the blockchain... ', bdm.organizeChain() print 'Done!' print '' print '*' * 80 print 'Getting top block of the chain... ',
def tearDownClass(self): CppBlockUtils.BlockDataManager().DestroyBDM() self.tiab.clean()
def getPrivDataForKey(self, key): if key in self.privData: return self.privData[key] else: return Cpp.SecureBinaryData()
def addAddress(self, addrData, pubKeyStr='', firstSeenData=[], lastSeenData=[]): """ There are a plethora of ways to add your key/address/wallet data to a PyBtcWallet object: - PubKeyHash160 (only the 20-byte address) - Public Key (which computes address) - Private Key (which computes public key and address) - Private and Public key (assumes they match, skips verification) - Existing PyBtcAddress object Scanning the blockchain for transactions is remarkably faster when you have information about the first and last time we've seen data in the blockchain. That way, we can skip over parts of the chain where wallet data couldn't possibly exist. """ print 'Adding new address to wallet: ', addr160 = None if isinstance(addrData, PyBtcAddress) and addrData.isInitialized(): addr160 = addrData.getAddr160() self.addrMap[addr160] = addrData elif isinstance(addrData, str): if len(addrData) == 20: addr160 = addrData self.addrMap[addr160] = PyBtcAddress( ).createFromPublicKeyHash160(addr160) elif 64 <= len(addrData) <= 65: addr160 = hash160(addrData.rjust(65, '\x04')) self.addrMap[addr160] = PyBtcAddress().createFromPublicKey( pubKeyStr) elif len(addrData) == 32: newPrivAddr = PyBtcAddress() if len(pubKeyStr) > 0: newPrivAddr.createFromKeyData(addrData, pubKeyStr, False) else: newPrivAddr.createFromPrivateKey(addrData) addr160 = newPrivAddr.getAddr160() self.addrMap[addr160] = newPrivAddr else: print '<ERROR>' raise BadAddressError, 'Improper address supplied to "addAddress()"' print binary_to_hex(addr160) # Now make sure the C++ wallet is sync'd addrObj = self.addrMap[addr160] cppAddr = Cpp.BtcAddress() cppAddr.setAddrStr20(addr160) if addrObj.hasPubKey(): cppAddr.setPubKey65(addrObj.pubKey_serialize()) if addrObj.hasPrivKey(): cppAddr.setPrivKey32(addrObj.privKey_serialize()) if len(firstSeenData) > 0: cppAddr.setFirstTimestamp(firstSeenData[0]) if len(firstSeenData) > 1: cppAddr.setFirstBlockNum(firstSeenData[1]) if len(lastSeenData) > 0: cppAddr.setLastTimestamp(lastSeenData[0]) if len(lastSeenData) > 1: cppAddr.setLastBlockNum(lastSeenData[1]) if not self.cppWallet: self.cppWallet = Cpp.BtcWallet() self.cppWallet.addAddress_BtcAddress_(cppAddr)
# ################################################################################ from pybtcengine import * import CppBlockUtils as Cpp from datetime import datetime from os import path from sys import argv class WalletLockError(Exception): pass ################################################################################ # Might as well create the BDM right here -- there will only ever be one, anyway bdm = Cpp.BlockDataManager().getBDM() ################################################################################ def loadBlockchainFile(blkfile=None, testnet=False): """ Looks for the blk0001.dat file in the default location for your operating system. If it is found, it is loaded into RAM and the longest chain is computed. Access to any information in the blockchain can be found via the bdm object. """ import platform opsys = platform.system() if blkfile == None: if not testnet: if 'win' in opsys.lower():