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 waitOnClusterBlockNumSync(self, targetHeadBlockNum, timeout=None): def doNodesHaveBlockNum(nodes, targetHeadBlockNum): for node in nodes: if (not node.killed) and ( not node.doesNodeHaveBlockNum(targetHeadBlockNum)): return False return True lam = lambda: doNodesHaveBlockNum(self.nodes, targetHeadBlockNum) ret = Utils.waitForBool(lam, timeout) return ret
def waitForNextBlock(self, timeout=None): num = self.getIrreversibleBlockNum() lam = lambda: self.getIrreversibleBlockNum() > num ret = Utils.waitForBool(lam, timeout) return ret
def waitForTransIdOnNode(self, transId, timeout=None): lam = lambda: self.doesNodeHaveTransId(transId) ret = Utils.waitForBool(lam, timeout) return ret
def waitForBlockNumOnNode(self, blockNum, timeout=None): lam = lambda: self.doesNodeHaveBlockNum(blockNum) ret = Utils.waitForBool(lam, timeout) return ret
def bootstrap(totalNodes, prodCount, biosHost, biosPort, dontKill=False, onlyBios=False): """Create 'prodCount' init accounts and deposits 10000000000 EOS in each. If prodCount is -1 will initialize all possible producers. Ensure nodes are inter-connected prior to this call. One way to validate this will be to check if every node has block 1.""" Utils.Print("Starting cluster bootstrap.") biosNode = Node(biosHost, biosPort) if not biosNode.checkPulse(): Utils.Print("ERROR: Bios node doesn't appear to be running...") return False producerKeys = Cluster.parseClusterKeys(totalNodes) # should have totalNodes node plus bios node if producerKeys is None or len(producerKeys) < (totalNodes + 1): Utils.Print( "ERROR: Failed to parse private keys from cluster config files." ) return False walletMgr = WalletMgr(True) walletMgr.killall() walletMgr.cleanup() if not walletMgr.launch(): Utils.Print("ERROR: Failed to launch bootstrap wallet.") return False biosNode.setWalletEndpointArgs(walletMgr.walletEndpointArgs) try: ignWallet = walletMgr.create("ignition") if ignWallet is None: Utils.Print("ERROR: Failed to create ignition wallet.") return False eosioName = "eosio" eosioKeys = producerKeys[eosioName] eosioAccount = Account(eosioName) eosioAccount.ownerPrivateKey = eosioKeys["private"] eosioAccount.ownerPublicKey = eosioKeys["public"] eosioAccount.activePrivateKey = eosioKeys["private"] eosioAccount.activePublicKey = eosioKeys["public"] if not walletMgr.importKey(eosioAccount, ignWallet): Utils.Print( "ERROR: Failed to import %s account keys into ignition wallet." % (eosioName)) return False contract = "eosio.bios" contractDir = "contracts/%s" % (contract) wastFile = "contracts/%s/%s.wast" % (contract, contract) abiFile = "contracts/%s/%s.abi" % (contract, contract) Utils.Print("Publish %s contract" % (contract)) trans = biosNode.publishContract(eosioAccount.name, contractDir, wastFile, abiFile, waitForTransBlock=True) if trans is None: Utils.Print("ERROR: Failed to publish contract %s." % (contract)) return False Node.validateTransaction(trans) Utils.Print("Creating accounts: %s " % ", ".join(producerKeys.keys())) producerKeys.pop(eosioName) accounts = [] for name, keys in producerKeys.items(): initx = None initx = Account(name) initx.ownerPrivateKey = keys["private"] initx.ownerPublicKey = keys["public"] initx.activePrivateKey = keys["private"] initx.activePublicKey = keys["public"] trans = biosNode.createAccount(initx, eosioAccount, 0) if trans is None: Utils.Print("ERROR: Failed to create account %s" % (name)) return False Node.validateTransaction(trans) accounts.append(initx) transId = Node.getTransId(trans) biosNode.waitForTransIdOnNode(transId) Utils.Print("Validating system accounts within bootstrap") biosNode.validateAccounts(accounts) if not onlyBios: if prodCount == -1: setProdsFile = "setprods.json" if Utils.Debug: Utils.Print("Reading in setprods file %s." % (setProdsFile)) with open(setProdsFile, "r") as f: setProdsStr = f.read() Utils.Print("Setting producers.") opts = "--permission eosio@active" myTrans = biosNode.pushMessage("eosio", "setprods", setProdsStr, opts) if myTrans is None or not myTrans[0]: Utils.Print("ERROR: Failed to set producers.") return False else: counts = dict.fromkeys( range(totalNodes), 0) # initialize node prods count to 0 setProdsStr = '{"schedule": [' firstTime = True prodNames = [] for name, keys in producerKeys.items(): if counts[keys["node"]] >= prodCount: continue if firstTime: firstTime = False else: setProdsStr += ',' setProdsStr += ' { "producer_name": "%s", "block_signing_key": "%s" }' % ( keys["name"], keys["public"]) prodNames.append(keys["name"]) counts[keys["node"]] += 1 setProdsStr += ' ] }' if Utils.Debug: Utils.Print("setprods: %s" % (setProdsStr)) Utils.Print("Setting producers: %s." % (", ".join(prodNames))) opts = "--permission eosio@active" # pylint: disable=redefined-variable-type trans = biosNode.pushMessage("eosio", "setprods", setProdsStr, opts) if trans is None or not trans[0]: Utils.Print("ERROR: Failed to set producer %s." % (keys["name"])) return False trans = trans[1] transId = Node.getTransId(trans) if not biosNode.waitForTransIdOnNode(transId): return False # wait for block production handover (essentially a block produced by anyone but eosio). lam = lambda: biosNode.getInfo()["head_block_producer" ] != "eosio" ret = Utils.waitForBool(lam) if not ret: Utils.Print("ERROR: Block production handover failed.") return False eosioTokenAccount = copy.deepcopy(eosioAccount) eosioTokenAccount.name = "eosio.token" trans = biosNode.createAccount(eosioTokenAccount, eosioAccount, 0) if trans is None: Utils.Print("ERROR: Failed to create account %s" % (eosioTokenAccount.name)) return False Node.validateTransaction(trans) transId = Node.getTransId(trans) biosNode.waitForTransIdOnNode(transId) contract = "eosio.token" contractDir = "contracts/%s" % (contract) wastFile = "contracts/%s/%s.wast" % (contract, contract) abiFile = "contracts/%s/%s.abi" % (contract, contract) Utils.Print("Publish %s contract" % (contract)) trans = biosNode.publishContract(eosioTokenAccount.name, contractDir, wastFile, abiFile, waitForTransBlock=True) if trans is None: Utils.Print("ERROR: Failed to publish contract %s." % (contract)) return False # Create currency0000, followed by issue currency0000 contract = eosioTokenAccount.name Utils.Print("push create action to %s contract" % (contract)) action = "create" data = "{\"issuer\":\"%s\",\"maximum_supply\":\"1000000000.0000 %s\",\"can_freeze\":\"0\",\"can_recall\":\"0\",\"can_whitelist\":\"0\"}" % ( eosioTokenAccount.name, CORE_SYMBOL) opts = "--permission %s@active" % (contract) trans = biosNode.pushMessage(contract, action, data, opts) if trans is None or not trans[0]: Utils.Print( "ERROR: Failed to push create action to eosio contract.") return False Node.validateTransaction(trans[1]) transId = Node.getTransId(trans[1]) biosNode.waitForTransIdOnNode(transId) contract = eosioTokenAccount.name Utils.Print("push issue action to %s contract" % (contract)) action = "issue" data = "{\"to\":\"%s\",\"quantity\":\"1000000000.0000 %s\",\"memo\":\"initial issue\"}" % ( eosioAccount.name, CORE_SYMBOL) opts = "--permission %s@active" % (contract) trans = biosNode.pushMessage(contract, action, data, opts) if trans is None or not trans[0]: Utils.Print( "ERROR: Failed to push issue action to eosio contract.") return False Node.validateTransaction(trans[1]) Utils.Print( "Wait for issue action transaction to become finalized.") transId = Node.getTransId(trans[1]) biosNode.waitForTransIdOnNode(transId) expectedAmount = "1000000000.0000 {0}".format(CORE_SYMBOL) Utils.Print("Verify eosio issue, Expected: %s" % (expectedAmount)) actualAmount = biosNode.getAccountEosBalanceStr(eosioAccount.name) if expectedAmount != actualAmount: Utils.Print( "ERROR: Issue verification failed. Excepted %s, actual: %s" % (expectedAmount, actualAmount)) return False contract = "eosio.system" contractDir = "contracts/%s" % (contract) wastFile = "contracts/%s/%s.wast" % (contract, contract) abiFile = "contracts/%s/%s.abi" % (contract, contract) Utils.Print("Publish %s contract" % (contract)) trans = biosNode.publishContract(eosioAccount.name, contractDir, wastFile, abiFile, waitForTransBlock=True) if trans is None: Utils.Print("ERROR: Failed to publish contract %s." % (contract)) return False Node.validateTransaction(trans) initialFunds = "1000000.0000 {0}".format(CORE_SYMBOL) Utils.Print("Transfer initial fund %s to individual accounts." % (initialFunds)) trans = None contract = eosioTokenAccount.name action = "transfer" for name, keys in producerKeys.items(): data = "{\"from\":\"%s\",\"to\":\"%s\",\"quantity\":\"%s\",\"memo\":\"%s\"}" % ( eosioAccount.name, name, initialFunds, "init transfer") opts = "--permission %s@active" % (eosioAccount.name) trans = biosNode.pushMessage(contract, action, data, opts) if trans is None or not trans[0]: Utils.Print( "ERROR: Failed to transfer funds from %s to %s." % (eosioTokenAccount.name, name)) return False Node.validateTransaction(trans[1]) Utils.Print( "Wait for last transfer transaction to become finalized.") transId = Node.getTransId(trans[1]) if not biosNode.waitForTransIdOnNode(transId): return False Utils.Print("Cluster bootstrap done.") finally: if not dontKill: walletMgr.killall() walletMgr.cleanup() return True