def importKey(self, account, wallet, ignoreDupKeyWarning=False): warningMsg="Key already in wallet" cmd="%s %s wallet import --name %s --private-key %s" % ( Utils.EosClientPath, self.endpointArgs, wallet.name, account.ownerPrivateKey) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: Utils.checkOutput(cmd.split()) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") if warningMsg in msg: if not ignoreDupKeyWarning: Utils.Print("WARNING: This key is already imported into the wallet.") else: Utils.Print("ERROR: Failed to import account owner key %s. %s" % (account.ownerPrivateKey, msg)) return False if account.activePrivateKey is None: Utils.Print("WARNING: Active private key is not defined for account \"%s\"" % (account.name)) else: cmd="%s %s wallet import --name %s --private-key %s" % ( Utils.EosClientPath, self.endpointArgs, wallet.name, account.activePrivateKey) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: Utils.checkOutput(cmd.split()) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") if warningMsg in msg: if not ignoreDupKeyWarning: Utils.Print("WARNING: This key is already imported into the wallet.") else: Utils.Print("ERROR: Failed to import account active key %s. %s" % (account.activePrivateKey, msg)) return False return True
def vote(node, account, producers): Print("Votes for %s" % (account.name)) trans=node.vote(account, producers, waitForTransBlock=False) if trans is None: Utils.cmdError("voting with %s" % (account.name)) errorExit("Failed to vote with account %s" % (account.name)) return trans
def validBlockProducer(prodsActive, prodsSeen, blockNum, node): blockProducer=getBlockProducer(node, blockNum) if blockProducer not in prodsActive: Utils.cmdError("unexpected block producer %s at blockNum=%s" % (blockProducer,blockNum)) errorExit("Failed because of invalid block producer") if not prodsActive[blockProducer]: Utils.cmdError("block producer %s for blockNum=%s not elected, belongs to node %s" % (blockProducer, blockNum, ProducerToNode.map[blockProducer])) errorExit("Failed because of incorrect block producer") prodsSeen[blockProducer]=True
def getBlockProducer(node, blockNum): node.waitForBlock(blockNum) block=node.getBlock(blockNum) if block is None: Utils.cmdError("could not get block number %s" % (blockNum)) errorExit("Failed to get block") blockProducer=block["producer"] if blockProducer is None: Utils.cmdError("could not get producer for block number %s" % (blockNum)) errorExit("Failed to get block's producer") return blockProducer
def getBlock(self, blockNum, silentErrors=False): """Given a blockId will return block details.""" assert(isinstance(blockNum, int)) if not self.enableMongo: cmd="%s %s get block %d" % (Utils.EosClientPath, self.endpointArgs, blockNum) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: block=Utils.runCmdReturnJson(cmd) return block except subprocess.CalledProcessError as ex: if not silentErrors: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during get block. %s" % (msg)) return None else: cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand='db.blocks.findOne( { "block_num": %d } )' % (blockNum) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) try: block=Node.runMongoCmdReturnJson(cmd.split(), subcommand) if block is not None: return block except subprocess.CalledProcessError as ex: if not silentErrors: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during get db node get block. %s" % (msg)) return None return None
def createInitializeAccount(self, account, creatorAccount, stakedDeposit=1000, waitForTransBlock=False, stakeNet=100, stakeCPU=100, buyRAM=100): cmd='%s %s system newaccount -j %s %s %s %s --stake-net "%s %s" --stake-cpu "%s %s" --buy-ram "%s %s"' % ( Utils.EosClientPath, self.endpointArgs, creatorAccount.name, account.name, account.ownerPublicKey, account.activePublicKey, stakeNet, CORE_SYMBOL, stakeCPU, CORE_SYMBOL, buyRAM, CORE_SYMBOL) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) trans=None try: trans=Utils.runCmdReturnJson(cmd) transId=Node.getTransId(trans) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during account creation. %s" % (msg)) return None if stakedDeposit > 0: self.waitForTransInBlock(transId) # seems like account creation needs to be finalized before transfer can happen trans = self.transferFunds(creatorAccount, account, Node.currencyIntToStr(stakedDeposit, CORE_SYMBOL), "init") transId=Node.getTransId(trans) if waitForTransBlock and not self.waitForTransInBlock(transId): return None return trans
def createAccount(self, account, creatorAccount, stakedDeposit=1000, waitForTransBlock=False): """Create account and return creation transactions. Return transaction json object. waitForTransBlock: wait on creation transaction id to appear in a block.""" cmd="%s %s create account -j %s %s %s %s" % ( Utils.EosClientPath, self.endpointArgs, creatorAccount.name, account.name, account.ownerPublicKey, account.activePublicKey) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) trans=None try: trans=Utils.runCmdReturnJson(cmd) transId=Node.getTransId(trans) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during account creation. %s" % (msg)) return None if stakedDeposit > 0: self.waitForTransInBlock(transId) # seems like account creation needs to be finlized before transfer can happen trans = self.transferFunds(creatorAccount, account, "%0.04f %s" % (stakedDeposit/10000, CORE_SYMBOL), "init") transId=Node.getTransId(trans) if waitForTransBlock and not self.waitForTransInBlock(transId): return None return trans
def transferFunds(self, source, destination, amountStr, memo="memo", force=False, waitForTransBlock=False): assert isinstance(amountStr, str) assert(source) assert(isinstance(source, Account)) assert(destination) assert(isinstance(destination, Account)) cmd="%s %s -v transfer -j %s %s" % ( Utils.EosClientPath, self.endpointArgs, source.name, destination.name) cmdArr=cmd.split() cmdArr.append(amountStr) cmdArr.append(memo) if force: cmdArr.append("-f") s=" ".join(cmdArr) if Utils.Debug: Utils.Print("cmd: %s" % (s)) trans=None try: trans=Utils.runCmdArrReturnJson(cmdArr) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during funds transfer. %s" % (msg)) return None assert(trans) transId=Node.getTransId(trans) if waitForTransBlock and not self.waitForTransInBlock(transId): return None return trans
def runMongoCmdReturnJson(cmd, subcommand, trace=False): """Run mongodb subcommand and return response.""" assert(cmd) assert(isinstance(cmd, list)) assert(subcommand) assert(isinstance(subcommand, str)) retId,outs,errs=Node.stdinAndCheckOutput(cmd, subcommand) if retId is not 0: Utils.Print("ERROR: mongodb call failed. %s" % (errs)) return None outStr=Node.byteArrToStr(outs) if not outStr: return None extJStr=Utils.filterJsonObject(outStr) if not extJStr: return None jStr=Node.normalizeJsonObject(extJStr) if not jStr: return None if trace: Utils.Print ("RAW > %s"% (outStr)) if trace: Utils.Print ("JSON> %s"% jStr) try: jsonData=json.loads(jStr) except json.decoder.JSONDecodeError as _: Utils.Print ("ERROR: JSONDecodeError") Utils.Print ("Raw MongoDB response: > %s"% (outStr)) Utils.Print ("Normalized MongoDB response: > %s"% (jStr)) raise return jsonData
def publishContract(self, account, contractDir, wastFile, abiFile, waitForTransBlock=False, shouldFail=False): cmd="%s %s -v set contract -j %s %s" % (Utils.EosClientPath, self.endpointArgs, account, contractDir) cmd += "" if wastFile is None else (" "+ wastFile) cmd += "" if abiFile is None else (" " + abiFile) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) trans=None try: trans=Utils.runCmdReturnJson(cmd, trace=False) except subprocess.CalledProcessError as ex: if not shouldFail: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during code hash retrieval. %s" % (msg)) return None else: retMap={} retMap["returncode"]=ex.returncode retMap["cmd"]=ex.cmd retMap["output"]=ex.output # commented below as they are available only in Python3.5 and above # retMap["stdout"]=ex.stdout # retMap["stderr"]=ex.stderr return retMap if shouldFail: Utils.Print("ERROR: The publish contract did not fail as expected.") return None Node.validateTransaction(trans) transId=Node.getTransId(trans) if waitForTransBlock and not self.waitForTransInBlock(transId): return None return trans
def kill(self, killSignal): if Utils.Debug: Utils.Print("Killing node: %s" % (self.cmd)) assert(self.pid is not None) try: os.kill(self.pid, killSignal) except OSError as ex: Utils.Print("ERROR: Failed to kill node (%d)." % (self.cmd), ex) return False # wait for kill validation def myFunc(): try: os.kill(self.pid, 0) #check if process with pid is running except OSError as _: return True return False if not Utils.waitForBool(myFunc): Utils.Print("ERROR: Failed to validate node shutdown.") return False # mark node as killed self.pid=None self.killed=True return True
def createAccountKeys(count): accounts=[] p = re.compile('Private key: (.+)\nPublic key: (.+)\n', re.MULTILINE) for _ in range(0, count): try: cmd="%s create key" % (Utils.EosClientPath) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) keyStr=Utils.checkOutput(cmd.split()) m=p.search(keyStr) if m is None: Utils.Print("ERROR: Owner key creation regex mismatch") break ownerPrivate=m.group(1) ownerPublic=m.group(2) cmd="%s create key" % (Utils.EosClientPath) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) keyStr=Utils.checkOutput(cmd.split()) m=p.match(keyStr) if m is None: Utils.Print("ERROR: Active key creation regex mismatch") break activePrivate=m.group(1) activePublic=m.group(2) name=''.join(random.choice(string.ascii_lowercase) for _ in range(12)) account=Account(name) account.ownerPrivateKey=ownerPrivate account.ownerPublicKey=ownerPublic account.activePrivateKey=activePrivate account.activePublicKey=activePublic accounts.append(account) if Utils.Debug: Utils.Print("name: %s, key(owner): ['%s', '%s], key(active): ['%s', '%s']" % (name, ownerPublic, ownerPrivate, activePublic, activePrivate)) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during key creation. %s" % (msg)) break if count != len(accounts): Utils.Print("Account keys creation failed. Expected %d, actual: %d" % (count, len(accounts))) return None return accounts
def myFunc(): psOut=None try: if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) psOut=Utils.checkOutput(cmd.split()) return psOut except subprocess.CalledProcessError as _: pass return None
def getServants(self, name): cmd="%s %s get servants %s" % (Utils.EosClientPath, self.endpointArgs, name) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans=Utils.runCmdReturnJson(cmd) return trans except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during servants retrieval. %s" % (msg)) return None
def getTable(self, contract, scope, table): cmd="%s %s get table %s %s %s" % (Utils.EosClientPath, self.endpointArgs, contract, scope, table) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans=Utils.runCmdReturnJson(cmd) return trans except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during table retrieval. %s" % (msg)) return None
def getAccountsByKey(self, key): cmd="%s %s get accounts %s" % (Utils.EosClientPath, self.endpointArgs, key) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans=Utils.runCmdReturnJson(cmd) return trans except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during accounts by key retrieval. %s" % (msg)) return None
def getInfo(self, silentErrors=False): cmd="%s %s get info" % (Utils.EosClientPath, self.endpointArgs) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans=Utils.runCmdReturnJson(cmd, silentErrors=silentErrors) return trans except subprocess.CalledProcessError as ex: if not silentErrors: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during get info. %s" % (msg)) return None
def relaunch(self, nodeId, chainArg, newChain=False, timeout=Utils.systemWaitTimeout): assert(self.pid is None) assert(self.killed) if Utils.Debug: Utils.Print("Launching node process, Id: %d" % (nodeId)) cmdArr=[] myCmd=self.cmd if not newChain: skip=False for i in self.cmd.split(): Utils.Print("\"%s\"" % (i)) if skip: skip=False continue if "--genesis-json" == i or "--genesis-timestamp" == i: skip=True continue cmdArr.append(i) myCmd=" ".join(cmdArr) dataDir="var/lib/node_%02d" % (nodeId) dt = datetime.datetime.now() dateStr="%d_%02d_%02d_%02d_%02d_%02d" % ( dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second) stdoutFile="%s/stdout.%s.txt" % (dataDir, dateStr) stderrFile="%s/stderr.%s.txt" % (dataDir, dateStr) with open(stdoutFile, 'w') as sout, open(stderrFile, 'w') as serr: #cmd=self.cmd + ("" if chainArg is None else (" " + chainArg)) cmd=myCmd + ("" if chainArg is None else (" " + chainArg)) Utils.Print("cmd: %s" % (cmd)) popen=subprocess.Popen(cmd.split(), stdout=sout, stderr=serr) self.pid=popen.pid def isNodeAlive(): """wait for node to be responsive.""" try: return True if self.checkPulse() else False except (TypeError) as _: pass return False isAlive=Utils.waitForBool(isNodeAlive, timeout) if isAlive: Utils.Print("Node relaunch was successfull.") else: Utils.Print("ERROR: Node relaunch Failed.") self.pid=None return False self.killed=False return True
def getEosAccount(self, name): assert(isinstance(name, str)) if not self.enableMongo: cmd="%s %s get account -j %s" % (Utils.EosClientPath, self.endpointArgs, name) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans=Utils.runCmdReturnJson(cmd) return trans except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during get account. %s" % (msg)) return None else: return self.getEosAccountFromDb(name)
def processCmd(self, cmd, cmdDesc, waitForTransBlock): if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) trans=None try: trans=Utils.runCmdReturnJson(cmd) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during %s. %s" % (cmdDesc, msg)) return None transId=Node.getTransId(trans) if waitForTransBlock and not self.waitForTransInBlock(transId): return None return trans
def getCurrencyStats(self, contract, symbol=CORE_SYMBOL): """returns Json output from get currency stats.""" assert(contract) assert(isinstance(contract, str)) assert(symbol) assert(isinstance(symbol, str)) cmd="%s %s get currency stats %s %s" % (Utils.EosClientPath, self.endpointArgs, contract, symbol) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans=Utils.runCmdReturnJson(cmd) return trans except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during get currency stats. %s" % (msg)) return None
def getOpenWallets(self): wallets=[] p = re.compile(r'\s+\"(\w+)\s\*\",?\n', re.MULTILINE) cmd="%s %s wallet list" % (Utils.EosClientPath, self.endpointArgs) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) retStr=Utils.checkOutput(cmd.split()) #Utils.Print("retStr: %s" % (retStr)) m=p.findall(retStr) if m is None: Utils.Print("ERROR: wallet list parser failure") return None wallets=m return wallets
def getKeys(self, wallet): keys=[] p = re.compile(r'\n\s+\"(\w+)\"\n', re.MULTILINE) cmd="%s %s wallet private_keys --name %s --password %s " % (Utils.EosClientPath, self.endpointArgs, wallet.name, wallet.password) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) retStr=Utils.checkOutput(cmd.split()) #Utils.Print("retStr: %s" % (retStr)) m=p.findall(retStr) if m is None: Utils.Print("ERROR: wallet private_keys parser failure") return None keys=m return keys
def setPermission(self, account, code, pType, requirement, waitForTransBlock=False): cmd="%s %s set action permission -j %s %s %s %s" % ( Utils.EosClientPath, self.endpointArgs, account, code, pType, requirement) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) trans=None try: trans=Utils.runCmdReturnJson(cmd) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during set permission. %s" % (msg)) return None transId=Node.getTransId(trans) if waitForTransBlock and not self.waitForTransInBlock(transId): return None return trans
def getActions(self, account, pos=-1, offset=-1): assert(isinstance(account, Account)) assert(isinstance(pos, int)) assert(isinstance(offset, int)) if not self.enableMongo: cmd="%s %s get actions -j %s %d %d" % (Utils.EosClientPath, self.endpointArgs, account.name, pos, offset) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: actions=Utils.runCmdReturnJson(cmd) return actions except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during actions by account retrieval. %s" % (msg)) return None else: return self.getActionsMdb(account, pos, offset)
def pushMessage(self, account, action, data, opts, silentErrors=False): cmd="%s %s push action -j %s %s" % (Utils.EosClientPath, self.endpointArgs, account, action) cmdArr=cmd.split() if data is not None: cmdArr.append(data) if opts is not None: cmdArr += opts.split() s=" ".join(cmdArr) if Utils.Debug: Utils.Print("cmd: %s" % (s)) try: trans=Utils.runCmdArrReturnJson(cmdArr) return (True, trans) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") if not silentErrors: Utils.Print("ERROR: Exception during push message. %s" % (msg)) return (False, msg)
def getAccountCodeHash(self, account): cmd="%s %s get code %s" % (Utils.EosClientPath, self.endpointArgs, account) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: retStr=Utils.checkOutput(cmd.split()) #Utils.Print ("get code> %s"% retStr) p=re.compile(r'code\shash: (\w+)\n', re.MULTILINE) m=p.search(retStr) if m is None: msg="Failed to parse code hash." Utils.Print("ERROR: "+ msg) return None return m.group(1) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during code hash retrieval. %s" % (msg)) return None
def waitOnClusterBlockNumSync(self, targetBlockNum, timeout=None): """Wait for all nodes to have targetBlockNum finalized.""" assert(self.nodes) def doNodesHaveBlockNum(nodes, targetBlockNum): for node in nodes: try: if (not node.killed) and (not node.isBlockPresent(targetBlockNum)): #if (not node.killed) and (not node.isBlockFinalized(targetBlockNum)): return False except (TypeError) as _: # This can happen if client connects before server is listening return False return True lam = lambda: doNodesHaveBlockNum(self.nodes, targetBlockNum) ret=Utils.waitForBool(lam, timeout) return ret
def getTransaction(self, transId, silentErrors=False): if not self.enableMongo: cmd="%s %s get transaction %s" % (Utils.EosClientPath, self.endpointArgs, transId) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans=Utils.runCmdReturnJson(cmd) return trans except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") if "Failed to connect" in msg: Utils.Print("ERROR: Node is unreachable. %s" % (msg)) raise if not silentErrors: Utils.Print("ERROR: Exception during transaction retrieval. %s" % (msg)) return None else: return self.getTransactionMdb(transId, silentErrors) return None
def getClientVersion(verbose=False): """Returns client version (string)""" p = re.compile(r'^Build version:\s(\w+)\n$') try: cmd="%s version client" % (Utils.EosClientPath) if verbose: Utils.Print("cmd: %s" % (cmd)) response=Utils.checkOutput(cmd.split()) assert(response) assert(isinstance(response, str)) if verbose: Utils.Print("response: <%s>" % (response)) m=p.match(response) if m is None: Utils.Print("ERROR: client version regex mismatch") return None verStr=m.group(1) return verStr except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") Utils.Print("ERROR: Exception during client version query. %s" % (msg)) raise
def verifyProductionRounds(trans, node, prodsActive, rounds): blockNum = node.getNextCleanProductionCycle(trans) Utils.Print("Validating blockNum=%s" % (blockNum)) temp = Utils.Debug Utils.Debug = False Utils.Print("FIND VALID BLOCK PRODUCER") blockProducer = node.getBlockProducerByNum(blockNum) lastBlockProducer = blockProducer adjust = False while not isValidBlockProducer(prodsActive, blockNum, node): adjust = True blockProducer = node.getBlockProducerByNum(blockNum) if lastBlockProducer != blockProducer: Utils.Print( "blockProducer=%s for blockNum=%s is for node=%s" % (blockProducer, blockNum, ProducerToNode.map[blockProducer])) lastBlockProducer = blockProducer blockNum += 1 Utils.Print("VALID BLOCK PRODUCER") saw = 0 sawHigh = 0 startingFrom = blockNum doPrint = 0 invalidCount = 0 while adjust: invalidCount += 1 if lastBlockProducer == blockProducer: saw += 1 else: if saw >= 12: startingFrom = blockNum if saw > 12: Utils.Print( "ERROR!!!!!!!!!!!!!! saw=%s, blockProducer=%s, blockNum=%s" % (saw, blockProducer, blockNum)) break else: if saw > sawHigh: sawHigh = saw Utils.Print("sawHigh=%s" % (sawHigh)) if doPrint < 5: doPrint += 1 Utils.Print("saw=%s, blockProducer=%s, blockNum=%s" % (saw, blockProducer, blockNum)) lastBlockProducer = blockProducer saw = 1 blockProducer = node.getBlockProducerByNum(blockNum) blockNum += 1 if adjust: blockNum -= 1 Utils.Print("ADJUSTED %s blocks" % (invalidCount - 1)) prodsSeen = None reportFirstMissedBlock = False Utils.Print("Verify %s complete rounds of all producers producing" % (rounds)) prodsSize = len(prodsActive) for i in range(0, rounds): prodsSeen = {} lastBlockProducer = None for j in range(0, prodsSize): # each new set of 12 blocks should have a different blockProducer if lastBlockProducer is not None and lastBlockProducer == node.getBlockProducerByNum( blockNum): Utils.cmdError( "expected blockNum %s to be produced by any of the valid producers except %s" % (blockNum, lastBlockProducer)) Utils.errorExit( "Failed because of incorrect block producer order") # make sure that the next set of 12 blocks all have the same blockProducer lastBlockProducer = node.getBlockProducerByNum(blockNum) for k in range(0, 12): blockProducer = validBlockProducer(prodsActive, prodsSeen, blockNum, node1) if lastBlockProducer != blockProducer: if not reportFirstMissedBlock: printStr = "" newBlockNum = blockNum - 18 for l in range(0, 36): printStr += "%s" % (newBlockNum) printStr += ":" newBlockProducer = node.getBlockProducerByNum( newBlockNum) printStr += "%s" % (newBlockProducer) printStr += " " newBlockNum += 1 Utils.Print( "NOTE: expected blockNum %s (started from %s) to be produced by %s, but produded by %s: round=%s, prod slot=%s, prod num=%s - %s" % (blockNum, startingFrom, lastBlockProducer, blockProducer, i, j, k, printStr)) reportFirstMissedBlock = True break blockNum += 1 # make sure that we have seen all 21 producers prodsSeenKeys = prodsSeen.keys() if len(prodsSeenKeys) != prodsSize: Utils.cmdError( "only saw %s producers of expected %d. At blockNum %s only the following producers were seen: %s" % (len(prodsSeenKeys), prodsSize, blockNum, ",".join(prodsSeenKeys))) Utils.errorExit("Failed because of missing block producers") Utils.Debug = temp
def importKey(self, account, wallet, ignoreDupKeyWarning=False): warningMsg = "Key already in wallet" cmd = "%s %s wallet import --name %s --private-key %s" % ( Utils.BitconchClientPath, self.getArgs(), wallet.name, account.ownerPrivateKey) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: Utils.checkOutput(cmd.split()) except subprocess.CalledProcessError as ex: msg = ex.output.decode("utf-8") if warningMsg in msg: if not ignoreDupKeyWarning: Utils.Print( "WARNING: This key is already imported into the wallet." ) else: Utils.Print( "ERROR: Failed to import account owner key %s. %s" % (account.ownerPrivateKey, msg)) return False if account.activePrivateKey is None: Utils.Print( "WARNING: Active private key is not defined for account \"%s\"" % (account.name)) else: cmd = "%s %s wallet import --name %s --private-key %s" % ( Utils.BitconchClientPath, self.getArgs(), wallet.name, account.activePrivateKey) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: Utils.checkOutput(cmd.split()) except subprocess.CalledProcessError as ex: msg = ex.output.decode("utf-8") if warningMsg in msg: if not ignoreDupKeyWarning: Utils.Print( "WARNING: This key is already imported into the wallet." ) else: Utils.Print( "ERROR: Failed to import account active key %s. %s" % (account.activePrivateKey, msg)) return False return True
def waitUntilBlockBecomeIrr(node, blockNum, timeout=60): def hasBlockBecomeIrr(): return node.getIrreversibleBlockNum() >= blockNum return Utils.waitForBool(hasBlockBecomeIrr, timeout)
cluster.cleanup() assert cluster.launch( pnodes=1, prodCount=1, totalProducers=1, totalNodes=2, useBiosBootFile=False, loadSystemContract=False, specificExtraNodeosArgs={1: "--validation-mode light"}) producerNode = cluster.getNode(0) validationNode = cluster.getNode(1) # Create a transaction to create an account Utils.Print("create a new account payloadless from the producer node") payloadlessAcc = Account("payloadless") payloadlessAcc.ownerPublicKey = "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" payloadlessAcc.activePublicKey = "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" producerNode.createAccount(payloadlessAcc, cluster.eosioAccount) contractDir = "unittests/test-contracts/payloadless" wasmFile = "payloadless.wasm" abiFile = "payloadless.abi" Utils.Print("Publish payloadless contract") trans = producerNode.publishContract(payloadlessAcc, contractDir, wasmFile, abiFile, waitForTransBlock=True)
def removeReversibleBlks(nodeId): dataDir = Utils.getNodeDataDir(nodeId) reversibleBlks = os.path.join(dataDir, "blocks", "reversible") shutil.rmtree(reversibleBlks, ignore_errors=True)
def populate(node, num): for prod in node.producers: ProducerToNode.map[prod]=num Utils.Print("Producer=%s for nodeNum=%s" % (prod,num))
testSuccessful=False killEosInstances=not dontKill killWallet=not dontKill WalletdName=Utils.EosWalletName ClientName="cleos" try: TestHelper.printSystemInfo("BEGIN") cluster.setWalletMgr(walletMgr) cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") if cluster.launch(prodCount=prodCount, onlyBios=False, pnodes=totalNodes, totalNodes=totalNodes, totalProducers=totalNodes*21, p2pPlugin=p2pPlugin, useBiosBootFile=False) is False: Utils.cmdError("launcher") Utils.errorExit("Failed to stand up eos cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) accounts=cluster.createAccountKeys(5) if accounts is None: Utils.errorExit("FAILURE - create keys") accounts[0].name="tester111111" accounts[1].name="tester222222" accounts[2].name="tester333333" accounts[3].name="tester444444" accounts[4].name="tester555555" testWalletName="test"
cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") specificExtraNodeosArgs = {} # producer nodes will be mapped to 0 through totalProducerNodes-1, so the number totalProducerNodes will be the non-producing node specificExtraNodeosArgs[totalProducerNodes] = "--plugin eosio::test_control_api_plugin" # *** setup topogrophy *** # "bridge" shape connects defprocera through defproducerk (in node0) to each other and defproducerl through defproduceru (in node01) # and the only connection between those 2 groups is through the bridge node if cluster.launch(prodCount=prodCount, topo="bridge", pnodes=totalProducerNodes, totalNodes=totalNodes, totalProducers=totalProducers, useBiosBootFile=False, specificExtraNodeosArgs=specificExtraNodeosArgs) is False: Utils.cmdError("launcher") Utils.errorExit("Failed to stand up eos cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) # *** create accounts to vote in desired producers *** accounts = cluster.createAccountKeys(5) if accounts is None: Utils.errorExit("FAILURE - create keys") accounts[0].name = "tester111111" accounts[1].name = "tester222222" accounts[2].name = "tester333333" accounts[3].name = "tester444444" accounts[4].name = "tester555555"
dontLaunch = args.dont_launch dontKill = args.leave_running killAll = args.clean_run p2pPlugin = args.p2p_plugin Utils.Debug = debug cluster = Cluster(walletd=True, defproduceraPrvtKey=defproduceraPrvtKey) walletMgr = WalletMgr(True) testSuccessful = False killEosInstances = not dontKill killWallet = not dontKill WalletdName = Utils.EosWalletName ClientName = "cleos" timeout = .5 * 12 * 2 + 60 # time for finalization with 1 producer + 60 seconds padding Utils.setIrreversibleTimeout(timeout) try: TestHelper.printSystemInfo("BEGIN") cluster.setWalletMgr(walletMgr) if not dontLaunch: cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") if cluster.launch(pnodes=4, p2pPlugin=p2pPlugin) is False: cmdError("launcher") errorExit("Failed to stand up eos cluster.") else: walletMgr.killall(allInstances=killAll)
cluster.cleanup() Print("Stand up cluster") specificExtraNodgstArgs={} # producer nodes will be mapped to 0 through totalProducerNodes-1, so the number totalProducerNodes will be the non-producing node specificExtraNodgstArgs[totalProducerNodes]="--plugin bcio::test_control_api_plugin" # *** setup topogrophy *** # "bridge" shape connects defprocera through defproducerk (in node0) to each other and defproducerl through defproduceru (in node01) # and the only connection between those 2 groups is through the bridge node if cluster.launch(prodCount=prodCount, onlyBios=False, topo="bridge", pnodes=totalProducerNodes, totalNodes=totalNodes, totalProducers=totalProducers, p2pPlugin=p2pPlugin, useBiosBootFile=False, specificExtraNodgstArgs=specificExtraNodgstArgs) is False: Utils.cmdError("launcher") Utils.errorExit("Failed to stand up bc cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) # *** create accounts to vote in desired producers *** accounts=cluster.createAccountKeys(5) if accounts is None: Utils.errorExit("FAILURE - create keys") accounts[0].name="tester111111" accounts[1].name="tester222222" accounts[2].name="tester333333" accounts[3].name="tester444444" accounts[4].name="tester555555"
def getLatestSnapshot(nodeId): snapshotDir = os.path.join(Utils.getNodeDataDir(nodeId), "snapshots") snapshotDirContents = os.listdir(snapshotDir) assert len(snapshotDirContents) > 0 snapshotDirContents.sort() return os.path.join(snapshotDir, snapshotDirContents[-1])
def analyzeBPs(bps0, bps1, expectDivergence): start = 0 index = None length = len(bps0) firstDivergence = None errorInDivergence = False analysysPass = 0 bpsStr = None bpsStr0 = None bpsStr1 = None while start < length: analysysPass += 1 bpsStr = None for i in range(start, length): bp0 = bps0[i] bp1 = bps1[i] if bpsStr is None: bpsStr = "" else: bpsStr += ", " blockNum0 = bp0["blockNum"] prod0 = bp0["prod"] blockNum1 = bp1["blockNum"] prod1 = bp1["prod"] numDiff = True if blockNum0 != blockNum1 else False prodDiff = True if prod0 != prod1 else False if numDiff or prodDiff: index = i if firstDivergence is None: firstDivergence = min(blockNum0, blockNum1) if not expectDivergence: errorInDivergence = True break bpsStr += str(blockNum0) + "->" + prod0 if index is None: if expectDivergence: errorInDivergence = True break return None bpsStr0 = None bpsStr2 = None start = length for i in range(index, length): if bpsStr0 is None: bpsStr0 = "" bpsStr1 = "" else: bpsStr0 += ", " bpsStr1 += ", " bp0 = bps0[i] bp1 = bps1[i] blockNum0 = bp0["blockNum"] prod0 = bp0["prod"] blockNum1 = bp1["blockNum"] prod1 = bp1["prod"] numDiff = "*" if blockNum0 != blockNum1 else "" prodDiff = "*" if prod0 != prod1 else "" if not numDiff and not prodDiff: start = i index = None if expectDivergence: errorInDivergence = True break bpsStr0 += str(blockNum0) + numDiff + "->" + prod0 + prodDiff bpsStr1 += str(blockNum1) + numDiff + "->" + prod1 + prodDiff if errorInDivergence: break if errorInDivergence: msg = "Failed analyzing block producers - " if expectDivergence: msg += "nodes do not indicate different block producers for the same blocks, but they are expected to diverge at some point." else: msg += "did not expect nodes to indicate different block producers for the same blocks." msg += "\n Matching Blocks= %s \n Diverging branch node0= %s \n Diverging branch node1= %s" % ( bpsStr, bpsStr0, bpsStr1) Utils.errorExit(msg) return firstDivergence
def waitForNextBlock(self, timeout=None): num = self.getHeadBlockNum() lam = lambda: self.getHeadBlockNum() > num ret = Utils.waitForBool(lam, timeout) return ret
def launch(self): if not self.walletd: Utils.Print( "ERROR: Wallet Manager wasn't configured to launch kbitconchd") return False if self.isLaunched(): return True if self.isLocal(): self.port = self.findAvailablePort() pgrepCmd = Utils.pgrepCmd(Utils.BitconchWalletName) if Utils.Debug: portTaken = False if self.isLocal(): if not Utils.arePortsAvailable(self.port): portTaken = True psOut = Utils.checkOutput(pgrepCmd.split(), ignoreError=True) if psOut or portTaken: statusMsg = "" if psOut: statusMsg += " %s - {%s}." % (pgrepCmd, psOut) if portTaken: statusMsg += " port %d is NOT available." % (self.port) Utils.Print( "Launching %s, note similar processes running. %s" % (Utils.BitconchWalletName, statusMsg)) cmd = "%s --data-dir %s --config-dir %s --http-server-address=%s:%d --verbose-http-errors" % ( Utils.BitconchWalletPath, WalletMgr.__walletDataDir, WalletMgr.__walletDataDir, self.host, self.port) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) with open(WalletMgr.__walletLogOutFile, 'w') as sout, open(WalletMgr.__walletLogErrFile, 'w') as serr: popen = subprocess.Popen(cmd.split(), stdout=sout, stderr=serr) self.__walletPid = popen.pid # Give kbitconchd time to warm up time.sleep(2) try: if Utils.Debug: Utils.Print("Checking if %s launched. %s" % (Utils.BitconchWalletName, pgrepCmd)) psOut = Utils.checkOutput(pgrepCmd.split()) if Utils.Debug: Utils.Print("Launched %s. {%s}" % (Utils.BitconchWalletName, psOut)) except subprocess.CalledProcessError as ex: Utils.errorExit("Failed to launch the wallet manager") return True
return node.getIrreversibleBlockNum() >= blockNum return Utils.waitForBool(hasBlockBecomeIrr, timeout) # List to contain the test result message testSuccessful = False try: TestHelper.printSystemInfo("BEGIN") cluster.killall(allInstances=killAll) cluster.cleanup() # Create a cluster of 4 nodes, each node has 1 producer. The first 3 nodes use the latest vesion, # While the 4th node use the version that doesn't support protocol feature activation (i.e. 1.7.0) associatedNodeLabels = {"3": "170"} Utils.Print("Alternate Version Labels File is {}".format( alternateVersionLabelsFile)) assert exists(alternateVersionLabelsFile ), "Alternate version labels file does not exist" # version 1.7 did not provide a default value for "--last-block-time-offset-us" so this is needed to # avoid dropping late blocks assert cluster.launch( pnodes=4, totalNodes=4, prodCount=1, totalProducers=4, extraNodpicoArgs=" --plugin picoio::producer_api_plugin ", useBiosBootFile=False, specificExtraNodpicoArgs={ 0: "--http-max-response-time-ms 990000", 1: "--http-max-response-time-ms 990000", 2: "--http-max-response-time-ms 990000",
def waitForBlock(node, blockNum, blockType=BlockType.head, timeout=None, reportInterval=20): if not node.waitForBlock(blockNum, timeout=timeout, blockType=blockType, reportInterval=reportInterval): info=node.getInfo() headBlockNum=info["head_block_num"] libBlockNum=info["last_irreversible_block_num"] Utils.errorExit("Failed to get to %s block number %d. Last had head block number %d and lib %d" % (blockType, blockNum, headBlockNum, libBlockNum))
TestHelper.printSystemInfo("BEGIN") cluster.setWalletMgr(walletMgr) cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") if cluster.launch(prodCount=prodCount, onlyBios=False, pnodes=totalNodes, totalNodes=totalNodes, totalProducers=totalNodes, useBiosBootFile=False, onlySetProds=True, sharedProducers=1) is False: Utils.cmdError("launcher") Utils.errorExit("Failed to stand up ltn cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) node0 = cluster.getNode(0) node1 = cluster.getNode(1) node2 = cluster.getNode(2) node = node0 numprod = totalNodes + 1 trans = None prodsActive = {} prodsActive["shrproducera"] = True
def get_block(self, params: str, node: Node) -> json: base_cmd_str = ("curl http://%s:%s/v1/") % (TestHelper.LOCAL_HOST, node.port) cmd_str = base_cmd_str + "trace_api/get_block -X POST -d " + ("'{\"block_num\":%s}'") % params return Utils.runCmdReturnJson(cmd_str)
walletMgr=WalletMgr(True) testSuccessful=False killRsnInstances=not dontKill killWallet=not dontKill WalletdName="awallet" ClientName="arisecli" try: TestHelper.printSystemInfo("BEGIN") cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") if cluster.launch(prodCount=prodCount, onlyBios=False, dontKill=dontKill, pnodes=totalNodes, totalNodes=totalNodes, totalProducers=totalNodes*21, p2pPlugin=p2pPlugin, useBiosBootFile=False) is False: Utils.cmdError("launcher") Utils.errorExit("Failed to stand up ARISEN cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) accounts=cluster.createAccountKeys(5) if accounts is None: Utils.errorExit("FAILURE - create keys") accounts[0].name="tester111111" accounts[1].name="tester222222" accounts[2].name="tester333333" accounts[3].name="tester444444" accounts[4].name="tester555555" testWalletName="test"
ClientName="clroxe" try: TestHelper.printSystemInfo("BEGIN") cluster.setWalletMgr(walletMgr) cluster.killall(allInstances=killAll) cluster.cleanup() specificExtraNodroxeArgs={} txnGenNodeNum=pnodes # next node after producer nodes for nodeNum in range(txnGenNodeNum, txnGenNodeNum+startedNonProdNodes): specificExtraNodroxeArgs[nodeNum]="--plugin roxe::txn_test_gen_plugin --txn-test-gen-account-prefix txntestacct" Print("Stand up cluster") if cluster.launch(prodCount=prodCount, onlyBios=False, pnodes=pnodes, totalNodes=totalNodes, totalProducers=pnodes*prodCount, useBiosBootFile=False, specificExtraNodroxeArgs=specificExtraNodroxeArgs, unstartedNodes=catchupCount, loadSystemContract=False) is False: Utils.errorExit("Failed to stand up roxe cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) Print("Create txn generate nodes") txnGenNodes=[] for nodeNum in range(txnGenNodeNum, txnGenNodeNum+startedNonProdNodes): txnGenNodes.append(cluster.getNode(nodeNum)) Print("Create accounts for generated txns") txnGenNodes[0].txnGenCreateTestAccounts(cluster.roxeAccount.name, cluster.roxeAccount.activePrivateKey) def lib(node): return node.getBlockNum(BlockType.lib)
def get_successful_constructed_block_numbers_for_node(nodeId): result = [] for filename in glob.glob(os.path.join(Utils.getNodeDataDir(nodeId), 'stderr.*.txt')): result.extend(get_successful_constructed_block_numbers_in_file(filename)) return set(result)
WalletdName="kbesd" ClientName="clbes" try: TestHelper.printSystemInfo("BEGIN") cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") minRAMFlag="--chain-state-db-guard-size-mb" minRAMValue=1002 maxRAMFlag="--chain-state-db-size-mb" maxRAMValue=1010 extraNodbesArgs=" %s %d %s %d " % (minRAMFlag, minRAMValue, maxRAMFlag, maxRAMValue) if cluster.launch(onlyBios=False, dontKill=dontKill, pnodes=totalNodes, totalNodes=totalNodes, totalProducers=totalNodes, extraNodbesArgs=extraNodbesArgs) is False: Utils.cmdError("launcher") errorExit("Failed to stand up bes cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) Print("creating accounts") namedAccounts=NamedAccounts(cluster,10) accounts=namedAccounts.accounts testWalletName="test" Print("Creating wallet \"%s\"." % (testWalletName)) walletMgr.killall(allInstances=killAll) walletMgr.cleanup() if walletMgr.launch() is False:
def removeState(nodeId): dataDir = Utils.getNodeDataDir(nodeId) state = os.path.join(dataDir, "state") shutil.rmtree(state, ignore_errors=True)
useBiosBootFile=False, pfSetupPolicy=PFSetupPolicy.NONE, extraNodmtpArgs= " --plugin mtpio::producer_api_plugin --http-max-response-time-ms 990000 " ) is False: cmdError("launcher") errorExit("Failed to stand up mtp cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) node = cluster.getNode(0) cmd = "curl %s/v1/producer/get_supported_protocol_features" % ( node.endpointHttp) Print("try to get supported feature list from Node 0 with cmd: %s" % (cmd)) feature0 = Utils.runCmdReturnJson(cmd) node = cluster.getNode(1) cmd = "curl %s/v1/producer/get_supported_protocol_features" % ( node.endpointHttp) Print("try to get supported feature list from Node 1 with cmd: %s" % (cmd)) feature1 = Utils.runCmdReturnJson(cmd) if feature0 != feature1: errorExit("feature list mismatch between node 0 and node 1") else: Print("feature list from node 0 matches with that from node 1") if len(feature0) == 0: errorExit("No supported feature list")
reset_statement="DROP TABLE IF EXISTS BlockData; DROP TABLE IF EXISTS SnapshotData; SELECT lo_unlink(l.oid) FROM pg_largeobject_metadata l;" subprocess.check_call(['scripts/postgres_control.sh', 'start', reset_statement]) if not dontKill: atexit.register(subprocess.call, ['scripts/postgres_control.sh', 'stop']) extraProducerAccounts = Cluster.createAccountKeys(1) vltproducerAccount = extraProducerAccounts[0] Print("Stand up cluster") if cluster.launch(onlyBios=False, pnodes=1, totalNodes=totalNodes, useBiosBootFile=False, onlySetProds=False, extraNodeosArgs=" --blocks-log-stride 20 --max-retained-block-files 3 --logconf %s" % loggingFile, specificExtraNodeosArgs={ 1:"--plugin eosio::blockvault_client_plugin --block-vault-backend postgresql://postgres:password@localhost"}, manualProducerNodeConf={ 1: { 'key': vltproducerAccount, 'names': ['vltproducera']}}) is False: Utils.cmdError("launcher") Utils.errorExit("Failed to stand up eos cluster.") Print("Validating system accounts after bootstrap") cluster.validateAccounts(None) node0 = cluster.getNode(0) node1 = cluster.getNode(1) Print("Wait for blocks produced by vltproducera(node 1) seen by node 0") assert node0.waitForIrreversibleBlockProducedBy("vltproducera"), "failed to see blocks produced by vltproducera" Print("Wait until block 1 is no longer retrievable, this ensures newly joined nodeos cannot sync from net plugin") while os.path.exists('var/lib/node_00/archive/blocks-1-20.log'): time.sleep(2)
def waitForBlock(self, blockNum, timeout=None): lam = lambda: self.getHeadBlockNum() > blockNum ret = Utils.waitForBool(lam, timeout) return ret
def waitForTransFinalization(self, transId, timeout=None): """Wait for trans id to be finalized.""" assert (isinstance(transId, str)) lam = lambda: self.isTransFinalized(transId) ret = Utils.waitForBool(lam, timeout) return ret
def printTrans(trans): Utils.Print("ERROR: Failure in transaction validation.") Utils.Print("Transaction: %s" % (json.dumps(trans, indent=1)))
def create(self, name, accounts=None, exitOnError=True): wallet = self.wallets.get(name) if wallet is not None: if Utils.Debug: Utils.Print("Wallet \"%s\" already exists. Returning same." % name) return wallet p = re.compile(r'\n\"(\w+)\"\n', re.MULTILINE) cmdDesc = "wallet create" cmd = "%s %s %s --name %s --to-console" % ( Utils.BitconchClientPath, self.getArgs(), cmdDesc, name) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) retStr = None maxRetryCount = 4 retryCount = 0 while True: try: retStr = Utils.checkOutput(cmd.split()) break except subprocess.CalledProcessError as ex: retryCount += 1 if retryCount < maxRetryCount: delay = 10 pgrepCmd = Utils.pgrepCmd(Utils.BitconchWalletName) psOut = Utils.checkOutput(pgrepCmd.split()) portStatus = "N/A" if self.isLocal(): if Utils.arePortsAvailable(self.port): portStatus = "AVAILABLE" else: portStatus = "NOT AVAILABLE" if Utils.Debug: Utils.Print( "%s was not accepted, delaying for %d seconds and trying again. port %d is %s. %s - {%s}" % (cmdDesc, delay, self.port, pgrepCmd, psOut)) time.sleep(delay) continue msg = ex.output.decode("utf-8") errorMsg = "ERROR: Failed to create wallet - %s. %s" % (name, msg) if exitOnError: Utils.errorExit("%s" % (errorMsg)) Utils.Print("%s" % (errorMsg)) return None m = p.search(retStr) if m is None: if exitOnError: Utils.cmdError("could not create wallet %s" % (name)) Utils.errorExit("Failed to create wallet %s" % (name)) Utils.Print("ERROR: wallet password parser failure") return None p = m.group(1) wallet = Wallet(name, p, self.host, self.port) self.wallets[name] = wallet if accounts: self.importKeys(accounts, wallet) return wallet
def waitForIrreversibleBlock(self, blockNum, timeout=None): lam = lambda: self.getIrreversibleBlockNum() >= blockNum ret = Utils.waitForBool(lam, timeout) return ret