def getMessageFromDb(self, transId, retry=True, silentErrors=False): for _ in range(2): cmd = "%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand = 'db.Messages.findOne( { "transaction_id": "%s" } )' % ( transId) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) try: trans = Node.runMongoCmdReturnJson(cmd.split(), subcommand) if trans is not None: return trans except subprocess.CalledProcessError as ex: if not silentErrors: msg = ex.output.decode("utf-8") Utils.Print( "ERROR: Exception during get db node get message. %s" % (msg)) return None if not retry: break if self.mongoSyncTime is not None: if Utils.Debug: Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None
def createAccount(self, account, creatorAccount, stakedDeposit=1000, waitForTransBlock=False): 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 = Node.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.waitForTransIdOnNode( 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.waitForTransIdOnNode(transId): return None return trans
def isTransInBlock(self, transId, blockId): """Check if transId is within block identified by blockId""" assert (transId) assert (isinstance(transId, str)) assert (blockId) assert (isinstance(blockId, str)) block = self.getBlock(blockId) transactions = None try: transactions = block["transactions"] except (AssertionError, TypeError, KeyError) as _: Utils.Print("Failed to parse block. %s" % (block)) raise if transactions is not None: for trans in transactions: assert (trans) try: myTransId = trans["trx"]["id"] if transId == myTransId: return True except (TypeError, KeyError) as _: Utils.Print("Failed to parse block transactions. %s" % (trans)) return False
def getBlockIdByTransId(self, transId): """Given a transaction Id (string), will return block id (string) containing the transaction""" assert (transId) assert (isinstance(transId, str)) trans = self.getTransaction(transId) assert (trans) refBlockNum = None try: refBlockNum = trans["trx"]["trx"]["ref_block_num"] refBlockNum = int(refBlockNum) + 1 except (TypeError, ValueError, KeyError) as _: Utils.Print("transaction parsing failed. Transaction: %s" % (trans)) raise headBlockNum = self.getIrreversibleBlockNum() assert (headBlockNum) try: headBlockNum = int(headBlockNum) except (ValueError) as _: Utils.Print("Info parsing failed. %s" % (headBlockNum)) for blockNum in range(refBlockNum, headBlockNum + 1): if self.isTransInBlock(str(transId), str(blockNum)): return str(blockNum) return None
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 kill node (%s)." % (self.cmd)) return False # mark node as killed self.pid = None self.killed = True return True
def relaunch(self, nodeId, chainArg): running = True try: os.kill(self.pid, 0) # check if process with pid is running except OSError as _: running = False if running: Utils.Print( "WARNING: A process with pid (%d) is already running." % (self.pid)) else: if Utils.Debug: Utils.Print("Launching node process, Id: %d" % (nodeId)) 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)) Utils.Print("cmd: %s" % (cmd)) popen = subprocess.Popen(cmd.split(), stdout=sout, stderr=serr) self.pid = popen.pid self.killed = False return True
def parseProducerKeys(configFile, nodeName): """Parse node config file for producer keys. Returns dictionary. (Keys: account name; Values: dictionary objects (Keys: ["name", "node", "private","public"]; Values: account name, node id returned by nodeNameToId(nodeName), private key(string)and public key(string))).""" configStr = None with open(configFile, 'r') as f: configStr = f.read() pattern = r"^\s*private-key\s*=\W+(\w+)\W+(\w+)\W+$" m = re.search(pattern, configStr, re.MULTILINE) if m is None: if Utils.Debug: Utils.Print("Failed to find producer keys") return None pubKey = m.group(1) privateKey = m.group(2) pattern = r"^\s*producer-name\s*=\W*(\w+)\W*$" matches = re.findall(pattern, configStr, re.MULTILINE) if matches is None: if Utils.Debug: Utils.Print("Failed to find producers.") return None producerKeys = {} for m in matches: if Utils.Debug: Utils.Print("Found producer : %s" % (m)) nodeId = Cluster.nodeNameToId(nodeName) keys = { "name": m, "node": nodeId, "private": privateKey, "public": pubKey } producerKeys[m] = keys return producerKeys
def verifyAccount(self, account): if not self.enableMongo: ret = self.getEosAccount(account.name) if ret is not None: account_name = ret["account_name"] if account_name is None: Utils.Print("ERROR: Failed to verify account creation.", account.name) return None return ret else: for _ in range(2): ret = self.getEosAccountFromDb(account.name) if ret is not None: account_name = ret["name"] if account_name is None: Utils.Print( "ERROR: Failed to verify account creation.", account.name) return None return ret if self.mongoSyncTime is not None: if Utils.Debug: Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None
def initializeNodesFromJson(self, nodesJsonStr): nodesObj = json.loads(nodesJsonStr) if nodesObj is None: Utils.Print("ERROR: Invalid Json string.") return False if "keys" in nodesObj: keysMap = nodesObj["keys"] if "defproduceraPrivateKey" in keysMap: defproduceraPrivateKey = keysMap["defproduceraPrivateKey"] self.defproduceraAccount.ownerPrivateKey = defproduceraPrivateKey if "defproducerbPrivateKey" in keysMap: defproducerbPrivateKey = keysMap["defproducerbPrivateKey"] self.defproducerbAccount.ownerPrivateKey = defproducerbPrivateKey nArr = nodesObj["nodes"] nodes = [] for n in nArr: port = n["port"] host = n["host"] node = Node(host, port) node.setWalletEndpointArgs(self.walletEndpointArgs) if Utils.Debug: Utils.Print("Node:", node) node.checkPulse() nodes.append(node) self.nodes = nodes return True
def transferFunds(self, source, destination, amount, memo="memo", force=False): assert isinstance(amount, str) cmd = "%s %s -v transfer -j %s %s" % (Utils.EosClientPath, self.endpointArgs, source.name, destination.name) cmdArr = cmd.split() cmdArr.append(amount) cmdArr.append(memo) if force: cmdArr.append("-f") s = " ".join(cmdArr) if Utils.Debug: Utils.Print("cmd: %s" % (s)) trans = None try: trans = Node.__runCmdArrReturnJson(cmdArr) return trans except subprocess.CalledProcessError as ex: msg = ex.output.decode("utf-8") Utils.Print("ERROR: Exception during funds transfer. %s" % (msg)) return None
def createAccounts(self, creator, waitForTransBlock=True, stakedDeposit=1000): if self.accounts is None: return True transId = None for account in self.accounts: if Utils.Debug: Utils.Print("Create account %s." % (account.name)) trans = self.createAccountAndVerify(account, creator, stakedDeposit) if trans is None: Utils.Print("ERROR: Failed to create account %s." % (account.name)) return False if Utils.Debug: Utils.Print("Account %s created." % (account.name)) transId = Node.getTransId(trans) if waitForTransBlock and transId is not None: node = self.nodes[0] if Utils.Debug: Utils.Print("Wait for transaction id %s on server port %d." % (transId, node.port)) if node.waitForTransIdOnNode(transId) is False: Utils.Print( "ERROR: Failed waiting for transaction id %s on server port %d." % (transId, node.port)) return False return True
def lockWallet(self, wallet): cmd = "%s %s wallet lock --name %s" % (Utils.EosClientPath, self.endpointArgs, wallet.name) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) if 0 != subprocess.call(cmd.split(), stdout=Utils.FNull): Utils.Print("ERROR: Failed to lock wallet %s." % (wallet.name)) return False return True
def lockAllWallets(self): cmd = "%s %s wallet lock_all" % (Utils.EosClientPath, self.endpointArgs) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) if 0 != subprocess.call(cmd.split(), stdout=Utils.FNull): Utils.Print("ERROR: Failed to lock all wallets.") return False return True
def dumpErrorDetailImpl(fileName): Utils.Print( "=================================================================" ) Utils.Print("Contents of %s:" % (fileName)) if os.path.exists(fileName): with open(fileName, "r") as f: shutil.copyfileobj(f, sys.stdout) else: Utils.Print("File %s not found." % (fileName))
def isMongodDbRunning(self): cmd = "%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand = "db.version()" if Utils.Debug: Utils.Print("echo %s | %s" % (subcommand, cmd)) ret, outs, errs = Node.stdinAndCheckOutput(cmd.split(), subcommand) if ret is not 0: Utils.Print("ERROR: Failed to check database version: %s" % (Node.byteArrToStr(errs))) return False if Utils.Debug: Utils.Print("MongoDb response: %s" % (outs)) return True
def dumpErrorDetails(self): Utils.Print( "=================================================================" ) if self.__walletPid is not None: Utils.Print("Contents of %s:" % (WalletMgr.__walletLogFile)) Utils.Print( "=================================================================" ) with open(WalletMgr.__walletLogFile, "r") as f: shutil.copyfileobj(f, sys.stdout)
def getInfo(self, silentErrors=False): cmd = "%s %s get info" % (Utils.EosClientPath, self.endpointArgs) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans = Node.runCmdReturnJson(cmd) 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 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 = Node.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 getTableRow(self, contract, scope, table, idx): if idx < 0: Utils.Print("ERROR: Table index cannot be negative. idx: %d" % (idx)) return None rows = self.getTableRows(contract, scope, table) if rows is None or idx >= len(rows): Utils.Print("ERROR: Retrieved table does not contain row %d" % idx) return None row = rows[idx] return row
def getEosAccount(self, name): assert (isinstance(name, str)) cmd = "%s %s get account -j %s" % (Utils.EosClientPath, self.endpointArgs, name) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans = Node.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
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 = Node.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 getCurrencyStats(self, contract, symbol=""): cmd = "%s %s get currency0000 stats %s %s" % ( Utils.EosClientPath, self.endpointArgs, contract, symbol) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) try: trans = Node.runCmdReturnJson(cmd) return trans except subprocess.CalledProcessError as ex: msg = ex.output.decode("utf-8") Utils.Print("ERROR: Exception during get currency0000 stats. %s" % (msg)) return None
def getEosAccountFromDb(self, name): cmd = "%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand = 'db.Accounts.findOne({"name" : "%s"})' % (name) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) try: trans = Node.runMongoCmdReturnJson(cmd.split(), subcommand) return trans except subprocess.CalledProcessError as ex: msg = ex.output.decode("utf-8") Utils.Print("ERROR: Exception during get account from db. %s" % (msg)) return None
def getBlockFromDb(self, idx): cmd = "%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand = "db.Blocks.find().sort({\"_id\":%d}).limit(1).pretty()" % ( idx) if Utils.Debug: Utils.Print("cmd: echo \"%s\" | %s" % (subcommand, cmd)) try: trans = Node.runMongoCmdReturnJson(cmd.split(), subcommand) return trans except subprocess.CalledProcessError as ex: msg = ex.output.decode("utf-8") Utils.Print("ERROR: Exception during get db block. %s" % (msg)) return None
def cleanup(self): for f in glob.glob("var/lib/node_*"): shutil.rmtree(f) for f in glob.glob("etc/eosio/node_*"): shutil.rmtree(f) if self.enableMongo: cmd = "%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand = "db.dropDatabase()" if Utils.Debug: Utils.Print("echo %s | %s" % (subcommand, cmd)) ret, _, errs = Node.stdinAndCheckOutput(cmd.split(), subcommand) if ret is not 0: Utils.Print("ERROR: Failed to drop database: %s" % (Node.byteArrToStr(errs)))
def unlockWallet(self, wallet): cmd = "%s %s wallet unlock --name %s" % ( Utils.EosClientPath, self.endpointArgs, wallet.name) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) popen = subprocess.Popen(cmd.split(), stdout=Utils.FNull, stdin=subprocess.PIPE) _, errs = popen.communicate(input=wallet.password.encode("utf-8")) if 0 != popen.wait(): Utils.Print("ERROR: Failed to unlock wallet %s: %s" % (wallet.name, errs.decode("utf-8"))) return False return True
def getKeys(self): keys = [] p = re.compile(r'\n\s+\"(\w+)\"\n', re.MULTILINE) cmd = "%s %s wallet keys" % (Utils.EosClientPath, self.endpointArgs) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) retStr = subprocess.check_output(cmd.split()).decode("utf-8") # Utils.Print("retStr: %s" % (retStr)) m = p.findall(retStr) if m is None: Utils.Print("ERROR: wallet keys parser failure") return None keys = m return keys
def validateSpreadFunds(self, expectedTotal): for node in self.nodes: if not node.killed: if Utils.Debug: Utils.Print("Validate funds on %s server port %d." % (Utils.EosServerName, node.port)) if node.validateSpreadFundsOnNode(self.defproduceraAccount, self.accounts, expectedTotal) is False: Utils.Print( "ERROR: Failed to validate funds on eos node port: %d" % (node.port)) return False return True
def discoverLocalNodes(self, totalNodes, timeout=0): nodes = [] pgrepOpts = "-fl" # pylint: disable=deprecated-method if platform.linux_distribution()[0] in [ "Ubuntu", "LinuxMint", "Fedora", "CentOS Linux", "arch" ]: pgrepOpts = "-a" cmd = "pgrep %s %s" % (pgrepOpts, Utils.EosServerName) def myFunc(): psOut = None try: if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) psOut = subprocess.check_output(cmd.split()).decode("utf-8") return psOut except subprocess.CalledProcessError as _: pass return None psOut = Utils.waitForObj(myFunc, timeout) if psOut is None: Utils.Print("ERROR: No nodes discovered.") return nodes if Utils.Debug: Utils.Print("pgrep output: \"%s\"" % psOut) for i in range(0, totalNodes): pattern = r"[\n]?(\d+) (.* --data-dir var/lib/node_%02d)" % (i) m = re.search(pattern, psOut, re.MULTILINE) if m is None: Utils.Print("ERROR: Failed to find %s pid. Pattern %s" % (Utils.EosServerName, pattern)) break instance = Node(self.host, self.port + i, pid=int(m.group(1)), cmd=m.group(2), enableMongo=self.enableMongo, mongoHost=self.mongoHost, mongoPort=self.mongoPort, mongoDb=self.mongoDb) instance.setWalletEndpointArgs(self.walletEndpointArgs) if Utils.Debug: Utils.Print("Node>", instance) nodes.append(instance) return nodes
def initializeNodes(self, defproduceraPrvtKey=None, defproducerbPrvtKey=None, onlyBios=False): port = Cluster.__BiosPort if onlyBios else self.port host = Cluster.__BiosHost if onlyBios else self.host node = Node(host, port, enableMongo=self.enableMongo, mongoHost=self.mongoHost, mongoPort=self.mongoPort, mongoDb=self.mongoDb) node.setWalletEndpointArgs(self.walletEndpointArgs) if Utils.Debug: Utils.Print("Node:", node) node.checkPulse() self.nodes = [node] if defproduceraPrvtKey is not None: self.defproduceraAccount.ownerPrivateKey = defproduceraPrvtKey self.defproduceraAccount.activePrivateKey = defproduceraPrvtKey if defproducerbPrvtKey is not None: self.defproducerbAccount.ownerPrivateKey = defproducerbPrvtKey self.defproducerbAccount.activePrivateKey = defproducerbPrvtKey return True