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.EnuClientPath) 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.EnuClientPath) 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 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 bootstrap(totalNodes, prodCount, biosHost, biosPort, dontKill=False, onlyBios=False): """Create 'prodCount' init accounts and deposits 10000000000 SYS 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 None 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 None walletMgr=WalletMgr(True) walletMgr.killall() walletMgr.cleanup() if not walletMgr.launch(): Utils.Print("ERROR: Failed to launch bootstrap wallet.") return None biosNode.setWalletEndpointArgs(walletMgr.walletEndpointArgs) try: ignWallet=walletMgr.create("ignition") 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 None contract="eosio.bios" contractDir="contracts/%s" % (contract) wasmFile="%s.wasm" % (contract) abiFile="%s.abi" % (contract) Utils.Print("Publish %s contract" % (contract)) trans=biosNode.publishContract(eosioAccount.name, contractDir, wasmFile, abiFile, waitForTransBlock=True) if trans is None: Utils.Print("ERROR: Failed to publish contract %s." % (contract)) return None 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 None Node.validateTransaction(trans) accounts.append(initx) transId=Node.getTransId(trans) if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return None 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 None 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 None trans=trans[1] transId=Node.getTransId(trans) if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return None # wait for block production handover (essentially a block produced by anyone but eosio). lam = lambda: biosNode.getInfo(exitOnError=True)["head_block_producer"] != "eosio" ret=Utils.waitForBool(lam) if not ret: Utils.Print("ERROR: Block production handover failed.") return None 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 None eosioRamAccount=copy.deepcopy(eosioAccount) eosioRamAccount.name="eosio.ram" trans=biosNode.createAccount(eosioRamAccount, eosioAccount, 0) if trans is None: Utils.Print("ERROR: Failed to create account %s" % (eosioRamAccount.name)) return None eosioRamfeeAccount=copy.deepcopy(eosioAccount) eosioRamfeeAccount.name="eosio.ramfee" trans=biosNode.createAccount(eosioRamfeeAccount, eosioAccount, 0) if trans is None: Utils.Print("ERROR: Failed to create account %s" % (eosioRamfeeAccount.name)) return None eosioStakeAccount=copy.deepcopy(eosioAccount) eosioStakeAccount.name="eosio.stake" trans=biosNode.createAccount(eosioStakeAccount, eosioAccount, 0) if trans is None: Utils.Print("ERROR: Failed to create account %s" % (eosioStakeAccount.name)) return None Node.validateTransaction(trans) transId=Node.getTransId(trans) if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return None contract="eosio.token" contractDir="contracts/%s" % (contract) wasmFile="%s.wasm" % (contract) abiFile="%s.abi" % (contract) Utils.Print("Publish %s contract" % (contract)) trans=biosNode.publishContract(eosioTokenAccount.name, contractDir, wasmFile, abiFile, waitForTransBlock=True) if trans is None: Utils.Print("ERROR: Failed to publish contract %s." % (contract)) return None # 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 None Node.validateTransaction(trans[1]) transId=Node.getTransId(trans[1]) if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return None 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 None Node.validateTransaction(trans[1]) Utils.Print("Wait for issue action transaction to become finalized.") transId=Node.getTransId(trans[1]) # biosNode.waitForTransInBlock(transId) # guesstimating block finalization timeout. Two production rounds of 12 blocks per node, plus 60 seconds buffer timeout = .5 * 12 * 2 * len(producerKeys) + 60 if not biosNode.waitForTransFinalization(transId, timeout=timeout): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a finalized block on server port %d." % (transId, biosNode.port)) return None 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 None contract="eosio.system" contractDir="contracts/%s" % (contract) wasmFile="%s.wasm" % (contract) abiFile="%s.abi" % (contract) Utils.Print("Publish %s contract" % (contract)) trans=biosNode.publishContract(eosioAccount.name, contractDir, wasmFile, abiFile, waitForTransBlock=True) if trans is None: Utils.Print("ERROR: Failed to publish contract %s." % (contract)) return None 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 None Node.validateTransaction(trans[1]) Utils.Print("Wait for last transfer transaction to become finalized.") transId=Node.getTransId(trans[1]) if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return None Utils.Print("Cluster bootstrap done.") finally: if not dontKill: walletMgr.killall() walletMgr.cleanup() return biosNode
def bootstrap(totalNodes, prodCount, biosHost, biosPort, dontKill=False, onlyBios=False): """Create 'prodCount' init accounts and deposits 10000000000 SYS 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) if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return False 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.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) 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 eosioRamAccount=copy.deepcopy(eosioAccount) eosioRamAccount.name="eosio.ram" trans=biosNode.createAccount(eosioRamAccount, eosioAccount, 0) if trans is None: Utils.Print("ERROR: Failed to create account %s" % (eosioRamAccount.name)) return False eosioRamfeeAccount=copy.deepcopy(eosioAccount) eosioRamfeeAccount.name="eosio.ramfee" trans=biosNode.createAccount(eosioRamfeeAccount, eosioAccount, 0) if trans is None: Utils.Print("ERROR: Failed to create account %s" % (eosioRamfeeAccount.name)) return False eosioStakeAccount=copy.deepcopy(eosioAccount) eosioStakeAccount.name="eosio.stake" trans=biosNode.createAccount(eosioStakeAccount, eosioAccount, 0) if trans is None: Utils.Print("ERROR: Failed to create account %s" % (eosioStakeAccount.name)) return False Node.validateTransaction(trans) transId=Node.getTransId(trans) if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return False 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]) if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return False 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.waitForTransInBlock(transId) # guesstimating block finalization timeout. Two production rounds of 12 blocks per node, plus 60 seconds buffer timeout = .5 * 12 * 2 * len(producerKeys) + 60 if not biosNode.waitForTransFinalization(transId, timeout=timeout): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a finalized block on server port %d." % (transId, biosNode.port)) return False 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.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return False Utils.Print("Cluster bootstrap done.") finally: if not dontKill: walletMgr.killall() walletMgr.cleanup() return True