示例#1
0
    def __init__(self):
        self.input_parser = InputParser()
        self.start_height = Blockchain.Default().Height
        self.start_dt = datetime.datetime.utcnow()

        self.token_style = style_from_dict({
            Token.Command: preferences.token_style['Command'],
            Token.Neo: preferences.token_style['Neo'],
            Token.Default: preferences.token_style['Default'],
            Token.Number: preferences.token_style['Number'],
        })
示例#2
0
class PromptInterface:
    go_on = True

    _walletdb_loop = None

    Wallet = None

    _known_things = []

    commands = ['quit',
                'help',
                'block {index/hash} (tx)',
                'header {index/hash}',
                'tx {hash}',
                'asset {assetId}',
                'asset search {query}',
                'contract {contract hash}',
                'contract search {query}',
                'notifications {block_number or address}',
                'mem',
                'nodes',
                'state',
                'config debug {on/off}',
                'config sc-events {on/off}',
                'config maxpeers {num_peers}',
                'build {path/to/file.py} (test {params} {returntype} {needs_storage} {needs_dynamic_invoke} {test_params})',
                'load_run {path/to/file.avm} (test {params} {returntype} {needs_storage} {needs_dynamic_invoke} {test_params})',
                'import wif {wif}',
                'import nep2 {nep2_encrypted_key}',
                'import contract {path/to/file.avm} {params} {returntype} {needs_storage} {needs_dynamic_invoke}',
                'import contract_addr {contract_hash} {pubkey}',
                'import multisig_addr {pubkey in wallet} {minimum # of signatures required} {signing pubkey 1} {signing pubkey 2}...',
                'import watch_addr {address}',
                'import token {token_contract_hash}',
                'export wif {address}',
                'export nep2 {address}',
                'open wallet {path}',
                'create wallet {path}',
                'wallet {verbose}',
                'wallet claim',
                'wallet migrate',
                'wallet rebuild {start block}',
                'wallet delete_addr {addr}',
                'wallet delete_token {token_contract_hash}',
                'wallet alias {addr} {title}',
                'wallet tkn_send {token symbol} {address_from} {address to} {amount} ',
                'wallet tkn_send_from {token symbol} {address_from} {address to} {amount}',
                'wallet tkn_approve {token symbol} {address_from} {address to} {amount}',
                'wallet tkn_allowance {token symbol} {address_from} {address to}',
                'wallet tkn_mint {token symbol} {mint_to_addr} (--attach-neo={amount}, --attach-gas={amount})',
                'wallet tkn_register {addr} ({addr}...) (--from-addr={addr})',
                'wallet unspent',
                'wallet close',
                'withdraw_request {asset_name} {contract_hash} {to_addr} {amount}',
                'withdraw holds # lists all current holds',
                'withdraw completed # lists completed holds eligible for cleanup',
                'withdraw cancel # cancels current holds',
                'withdraw cleanup # cleans up completed holds',
                'withdraw # withdraws the first hold availabe',
                'withdraw all # withdraw all holds available',
                'send {assetId or name} {address} {amount} (--from-addr={addr})',
                'sign {transaction in JSON format}',
                'testinvoke {contract hash} {params} (--attach-neo={amount}, --attach-gas={amount}) (--from-addr={addr})',
                'debugstorage {on/off/reset}'
                ]

    history = PromptFileHistory(FILENAME_PROMPT_HISTORY)

    token_style = None
    start_height = None
    start_dt = None

    def __init__(self):
        self.input_parser = InputParser()
        self.start_height = Blockchain.Default().Height
        self.start_dt = datetime.datetime.utcnow()

        self.token_style = style_from_dict({
            Token.Command: preferences.token_style['Command'],
            Token.Neo: preferences.token_style['Neo'],
            Token.Default: preferences.token_style['Default'],
            Token.Number: preferences.token_style['Number'],
        })

    def get_bottom_toolbar(self, cli=None):
        out = []
        try:
            out = [(Token.Command, '[%s] Progress: ' % settings.net_name),
                   (Token.Number, str(Blockchain.Default().Height + 1)),
                   (Token.Neo, '/'),
                   (Token.Number, str(Blockchain.Default().HeaderHeight + 1))]
        except Exception as e:
            pass

        return out

    def get_completer(self):

        standard_completions = ['block', 'tx', 'header', 'mem', 'neo', 'gas',
                                'help', 'state', 'nodes', 'exit', 'quit',
                                'config', 'import', 'export', 'open',
                                'wallet', 'contract', 'asset', 'wif',
                                'watch_addr', 'contract_addr', 'testinvoke', 'tkn_send',
                                'tkn_mint', 'tkn_send_from', 'tkn_approve', 'tkn_allowance',
                                'tkn_register', 'build', 'notifications', ]

        if self.Wallet:
            for addr in self.Wallet.Addresses:
                if addr not in self._known_things:
                    self._known_things.append(addr)
            for alias in self.Wallet.NamedAddr:
                if alias.Title not in self._known_things:
                    self._known_things.append(alias.Title)
            for tkn in self.Wallet.GetTokens().values():
                if tkn.symbol not in self._known_things:
                    self._known_things.append(tkn.symbol)

        all_completions = standard_completions + self._known_things

        completer = WordCompleter(all_completions)

        return completer

    def quit(self):
        print('Shutting down. This may take a bit...')
        self.go_on = False
        self.do_close_wallet()
        reactor.stop()

    def help(self):
        tokens = []
        for c in self.commands:
            tokens.append((Token.Command, "%s\n" % c))
        print_tokens(tokens, self.token_style)

    def do_open(self, arguments):
        if self.Wallet:
            self.do_close_wallet()

        item = get_arg(arguments)

        if item and item == 'wallet':

            path = get_arg(arguments, 1)

            if path:

                if not os.path.exists(path):
                    print("Wallet file not found")
                    return

                passwd = prompt("[password]> ", is_password=True)
                password_key = to_aes_key(passwd)

                try:
                    self.Wallet = UserWallet.Open(path, password_key)

                    self.start_wallet_loop()
                    print("Opened wallet at %s" % path)
                except Exception as e:
                    print("Could not open wallet: %s" % e)

            else:
                print("Please specify a path")
        else:
            print("Please specify something to open")

    def do_create(self, arguments):
        item = get_arg(arguments)

        if item and item == 'wallet':

            path = get_arg(arguments, 1)

            if path:

                if os.path.exists(path):
                    print("File already exists")
                    return

                passwd1 = prompt("[password]> ", is_password=True)
                passwd2 = prompt("[password again]> ", is_password=True)

                if passwd1 != passwd2 or len(passwd1) < 10:
                    print("Please provide matching passwords that are at least 10 characters long")
                    return

                password_key = to_aes_key(passwd1)

                try:
                    self.Wallet = UserWallet.Create(path=path,
                                                    password=password_key)
                    contract = self.Wallet.GetDefaultContract()
                    key = self.Wallet.GetKey(contract.PublicKeyHash)
                    print("Wallet %s" % json.dumps(self.Wallet.ToJson(), indent=4))
                    print("Pubkey %s" % key.PublicKey.encode_point(True))
                except Exception as e:
                    print("Exception creating wallet: %s" % e)
                    self.Wallet = None
                    if os.path.isfile(path):
                        try:
                            os.remove(path)
                        except Exception as e:
                            print("Could not remove {}: {}".format(path, e))
                    return

                if self.Wallet:
                    self.start_wallet_loop()

            else:
                print("Please specify a path")

    def start_wallet_loop(self):
        self._walletdb_loop = task.LoopingCall(self.Wallet.ProcessBlocks)
        self._walletdb_loop.start(1)

    def stop_wallet_loop(self):
        self._walletdb_loop.stop()
        self._walletdb_loop = None

    def do_close_wallet(self):
        if self.Wallet:
            path = self.Wallet._path
            self.stop_wallet_loop()
            self.Wallet.Close()
            self.Wallet = None
            print("Closed wallet %s" % path)

    def do_import(self, arguments):
        item = get_arg(arguments)

        if not item:
            print("Please specify something to import")
            return

        if item == 'wif':
            if not self.Wallet:
                print("Please open a wallet before importing WIF")
                return

            wif = get_arg(arguments, 1)
            if not wif:
                print("Please supply a valid WIF key")
                return

            try:
                prikey = KeyPair.PrivateKeyFromWIF(wif)
                key = self.Wallet.CreateKey(prikey)
                print("Imported key: %s" % wif)
                print("Pubkey: %s\n" % key.PublicKey.encode_point(True).hex())
                print("Wallet: %s" % json.dumps(self.Wallet.ToJson(), indent=4))
            except ValueError as e:
                print(str(e))
            except Exception as e:
                print(str(e))

            return

        elif item == 'nep2':
            if not self.Wallet:
                print("Please open a wallet before importing a NEP2 key")
                return

            nep2_key = get_arg(arguments, 1)
            if not nep2_key:
                print("Please supply a valid NEP2 encrypted private key")
                return

            nep2_passwd = prompt("[key password]> ", is_password=True)

            try:
                prikey = KeyPair.PrivateKeyFromNEP2(nep2_key, nep2_passwd)
                key = self.Wallet.CreateKey(prikey)
                print("Imported NEP2 key: %s" % nep2_key)
                print("Pubkey: %s\n" % key.PublicKey.encode_point(True).hex())
                print("Wallet: %s" % json.dumps(self.Wallet.ToJson(), indent=4))
            except ValueError as e:
                print(str(e))
            except Exception as e:
                print(str(e))

            return

        elif item == 'contract':
            return self.load_smart_contract(arguments)

        elif item == 'contract_addr':
            return ImportContractAddr(self.Wallet, arguments[1:])

        elif item == 'watch_addr':
            return ImportWatchAddr(self.Wallet, get_arg(arguments, 1))

        elif item == 'multisig_addr':
            return ImportMultiSigContractAddr(self.Wallet, arguments[1:])

        elif item == 'token':
            return ImportToken(self.Wallet, get_arg(arguments, 1))

        else:
            print("Import of '%s' not implemented" % item)

    def do_build(self, arguments):
        Blockchain.Default().Pause()
        BuildAndRun(arguments, self.Wallet)
        Blockchain.Default().Resume()

    def do_load_n_run(self, arguments):
        LoadAndRun(arguments, self.Wallet)

    def do_export(self, arguments):
        item = get_arg(arguments)

        if item == 'wif':
            if not self.Wallet:
                return print("Please open a wallet")

            address = get_arg(arguments, 1)
            if not address:
                return print("Please specify an address")

            passwd = prompt("[wallet password]> ", is_password=True)
            if not self.Wallet.ValidatePassword(passwd):
                return print("Incorrect password")

            keys = self.Wallet.GetKeys()
            for key in keys:
                if key.GetAddress() == address:
                    export = key.Export()
                    print("WIF key export: %s" % export)
            return

        elif item == 'nep2':
            if not self.Wallet:
                return print("Please open a wallet")

            address = get_arg(arguments, 1)
            if not address:
                return print("Please specify an address")

            passwd = prompt("[wallet password]> ", is_password=True)
            if not self.Wallet.ValidatePassword(passwd):
                return print("Incorrect password")

            nep2_passwd1 = prompt("[key password]> ", is_password=True)
            if len(nep2_passwd1) < 10:
                return print("Please provide a password with at least 10 characters")

            nep2_passwd2 = prompt("[key password again]> ", is_password=True)
            if nep2_passwd1 != nep2_passwd2:
                return print("Passwords do not match")

            keys = self.Wallet.GetKeys()
            for key in keys:
                export = key.ExportNEP2(nep2_passwd1)
                print("NEP2 key export: %s" % export)
            return

        print("Command export %s not found" % item)

    def make_withdraw_request(self, arguments):
        if not self.Wallet:
            print("Please open a wallet")
            return
        if len(arguments) == 4:
            RequestWithdrawFrom(self.Wallet, arguments[0], arguments[1], arguments[2], arguments[3])
        else:
            print("Incorrect arg length. Use 'withdraw_request {asset_id} {contract_hash} {to_addr} {amount}'")

    def do_withdraw(self, arguments):
        if not self.Wallet:
            print("Please open a wallet")
            return

        item = get_arg(arguments, 0)

        if item:

            if item == 'holds':
                PrintHolds(self.Wallet)
            elif item == 'delete_holds':
                index_to_delete = -1
                if get_arg(arguments, 1) and int(get_arg(arguments, 1)) > -1:
                    index_to_delete = int(get_arg(arguments, 1))
                DeleteHolds(self.Wallet, index_to_delete)
            elif item == 'cancel_holds':
                if len(arguments) > 1:
                    CancelWithdrawalHolds(self.Wallet, get_arg(arguments, 1))
                else:
                    print("Please specify contract hash to cancel holds for")
            elif item == 'completed':
                ShowCompletedHolds(self.Wallet)
            elif item == 'cleanup':
                CleanupCompletedHolds(self.Wallet)
            elif item == 'all':
                WithdrawAll(self.Wallet)
        else:
            WithdrawOne(self.Wallet)

    def do_notifications(self, arguments):
        if NotificationDB.instance() is None:
            print("No notification DB Configured")
            return

        item = get_arg(arguments, 0)
        events = []
        if len(item) == 34:
            addr = item
            events = NotificationDB.instance().get_by_addr(addr)
        else:
            try:
                block_height = int(item)
                if block_height < Blockchain.Default().Height:
                    events = NotificationDB.instance().get_by_block(block_height)
                else:
                    print("Block %s not found" % block_height)
                    return
            except Exception as e:
                print("Could not parse block height %s" % e)
                return

        if len(events):
            [print(json.dumps(e.ToJson(), indent=4)) for e in events]
        else:
            print("No events found for %s" % item)

    def show_wallet(self, arguments):
        if not self.Wallet:
            print("Please open a wallet")
            return

        item = get_arg(arguments)

        if not item:
            print("Wallet %s " % json.dumps(self.Wallet.ToJson(), indent=4))
            return

        if item in ['v', '--v', 'verbose']:
            print("Wallet %s " % json.dumps(self.Wallet.ToJson(verbose=True), indent=4))
            return
        elif item == 'migrate' and self.Wallet is not None:
            self.Wallet.Migrate()
            print("Migrated wallet")
        elif item == 'delete_addr':
            addr_to_delete = get_arg(arguments, 1)
            DeleteAddress(self, self.Wallet, addr_to_delete)
        elif item == 'delete_token':
            token_to_delete = get_arg(arguments, 1)
            DeleteToken(self.Wallet, token_to_delete)
        elif item == 'close':
            self.do_close_wallet()
        elif item == 'claim':
            ClaimGas(self.Wallet, True, arguments[1:])
        elif item == 'rebuild':
            self.stop_wallet_loop()
            try:
                self.Wallet.Rebuild()
            finally:
                self.start_wallet_loop()
            try:
                item2 = int(get_arg(arguments, 1))
                if item2 and item2 > 0:
                    print("Restarting at %s" % item2)
                    self.Wallet._current_height = item2
            except Exception as e:
                pass
        elif item == 'tkn_send':
            token_send(self.Wallet, arguments[1:])
        elif item == 'tkn_send_from':
            token_send_from(self.Wallet, arguments[1:])
        elif item == 'tkn_approve':
            token_approve_allowance(self.Wallet, arguments[1:])
        elif item == 'tkn_allowance':
            token_get_allowance(self.Wallet, arguments[1:], verbose=True)
        elif item == 'tkn_mint':
            token_mint(self.Wallet, arguments[1:])
        elif item == 'tkn_register':
            token_crowdsale_register(self.Wallet, arguments[1:])
        elif item == 'unspent':
            ShowUnspentCoins(self.Wallet, arguments[1:])
        elif item == 'alias':
            if len(arguments) == 3:
                AddAlias(self.Wallet, arguments[1], arguments[2])
            else:
                print("Please supply an address and title")
        else:
            print("Wallet: '{}' is an invalid parameter".format(item))

    def do_send(self, arguments):
        construct_and_send(self, self.Wallet, arguments)

    def do_sign(self, arguments):
        jsn = get_arg(arguments)
        parse_and_sign(self, self.Wallet, jsn)

    def show_state(self):
        height = Blockchain.Default().Height
        headers = Blockchain.Default().HeaderHeight

        diff = height - self.start_height
        now = datetime.datetime.utcnow()
        difftime = now - self.start_dt

        mins = difftime / datetime.timedelta(minutes=1)
        secs = mins * 60

        bpm = 0
        tps = 0
        if diff > 0 and mins > 0:
            bpm = diff / mins
            tps = Blockchain.Default().TXProcessed / secs

        out = "Progress: %s / %s\n" % (height, headers)
        out += "Block-cache length %s\n" % Blockchain.Default().BlockCacheCount
        out += "Blocks since program start %s\n" % diff
        out += "Time elapsed %s mins\n" % mins
        out += "Blocks per min %s \n" % bpm
        out += "TPS: %s \n" % tps
        tokens = [(Token.Number, out)]
        print_tokens(tokens, self.token_style)

    def show_nodes(self):
        if len(NodeLeader.Instance().Peers) > 0:
            out = "Total Connected: %s " % len(NodeLeader.Instance().Peers)
            for peer in NodeLeader.Instance().Peers:
                out += "Peer %s - IO: %s\n" % (peer.Name(), peer.IOStats())
            print_tokens([(Token.Number, out)], self.token_style)
        else:
            print("Not connected yet\n")

    def show_block(self, args):
        item = get_arg(args)
        txarg = get_arg(args, 1)
        if item is not None:
            block = Blockchain.Default().GetBlock(item)

            if block is not None:

                bjson = json.dumps(block.ToJson(), indent=4)
                tokens = [(Token.Number, bjson)]
                print_tokens(tokens, self.token_style)
                print('\n')
                if txarg and 'tx' in txarg:

                    for tx in block.FullTransactions:
                        print(json.dumps(tx.ToJson(), indent=4))

            else:
                print("Could not locate block %s" % item)
        else:
            print("please specify a block")

    def show_header(self, args):
        item = get_arg(args)
        if item is not None:
            header = Blockchain.Default().GetHeaderBy(item)
            if header is not None:
                print(json.dumps(header.ToJson(), indent=4))
            else:
                print("Could not locate header %s\n" % item)
        else:
            print("Please specify a header")

    def show_tx(self, args):
        if len(args):
            try:
                txid = UInt256.ParseString(get_arg(args))
                tx, height = Blockchain.Default().GetTransaction(txid)
                if height > -1:
                    jsn = tx.ToJson()
                    jsn['height'] = height
                    jsn['unspents'] = [uns.ToJson(tx.outputs.index(uns)) for uns in
                                       Blockchain.Default().GetAllUnspent(txid)]
                    tokens = [(Token.Command, json.dumps(jsn, indent=4))]
                    print_tokens(tokens, self.token_style)
                    print('\n')
            except Exception as e:
                print("Could not find transaction from args: %s (%s)" % (e, args))
        else:
            print("Please specify a TX hash")

    def show_account_state(self, args):
        item = get_arg(args)

        if item is not None:
            account = Blockchain.Default().GetAccountState(item, print_all_accounts=True)

            if account is not None:
                bjson = json.dumps(account.ToJson(), indent=4)
                tokens = [(Token.Number, bjson)]
                print_tokens(tokens, self.token_style)
                print('\n')
            else:
                print("Account %s not found" % item)
        else:
            print("Please specify an account address")

    def show_asset_state(self, args):
        item = get_arg(args)

        if item is not None:

            if item == 'search':
                query = get_arg(args, 1)
                results = Blockchain.Default().SearchAssetState(query)
                print("Found %s results for %s" % (len(results), query))
                for asset in results:
                    bjson = json.dumps(asset.ToJson(), indent=4)
                    tokens = [(Token.Number, bjson)]
                    print_tokens(tokens, self.token_style)
                    print('\n')

                return

            asset = Blockchain.Default().GetAssetState(item)

            if asset is not None:
                bjson = json.dumps(asset.ToJson(), indent=4)
                tokens = [(Token.Number, bjson)]
                print_tokens(tokens, self.token_style)
                print('\n')
            else:
                print("Asset %s not found" % item)
        else:
            print("Please specify an asset hash")

    def show_contract_state(self, args):
        item = get_arg(args)

        if item is not None:

            if item.lower() == 'all':
                contracts = Blockchain.Default().ShowAllContracts()
                print("Contracts: %s" % contracts)
            elif item.lower() == 'search':
                query = get_arg(args, 1)
                if query:

                    contracts = Blockchain.Default().SearchContracts(query=query)
                    print("Found %s results for %s" % (len(contracts), query))
                    for contract in contracts:
                        bjson = json.dumps(contract.ToJson(), indent=4)
                        tokens = [(Token.Number, bjson)]
                        print_tokens(tokens, self.token_style)
                        print('\n')
                else:
                    print("Please specify a search query")
            else:
                contract = Blockchain.Default().GetContract(item)

                if contract is not None:
                    contract.DetermineIsNEP5()
                    jsn = contract.ToJson()
                    bjson = json.dumps(jsn, indent=4)
                    tokens = [(Token.Number, bjson)]
                    print_tokens(tokens, self.token_style)
                    print('\n')
        else:
            print("Please specify a contract")

    def test_invoke_contract(self, args):
        if not self.Wallet:
            print("Please open a wallet")
            return

        args, from_addr = get_from_addr(args)

        if args and len(args) > 0:
            tx, fee, results, num_ops = TestInvokeContract(self.Wallet, args, from_addr=from_addr)

            if tx is not None and results is not None:
                print(
                    "\n-------------------------------------------------------------------------------------------------------------------------------------")
                print("Test invoke successful")
                print("Total operations: %s" % num_ops)
                print("Results %s" % [str(item) for item in results])
                print("Invoke TX GAS cost: %s" % (tx.Gas.value / Fixed8.D))
                print("Invoke TX fee: %s" % (fee.value / Fixed8.D))
                print(
                    "-------------------------------------------------------------------------------------------------------------------------------------\n")
                print("Enter your password to continue and invoke on the network\n")

                passwd = prompt("[password]> ", is_password=True)
                if not self.Wallet.ValidatePassword(passwd):
                    return print("Incorrect password")

                result = InvokeContract(self.Wallet, tx, fee, from_addr=from_addr)

                return
            else:
                print("Error testing contract invoke")
                return

        print("Please specify a contract to invoke")

    def load_smart_contract(self, args):
        if not self.Wallet:
            print("Please open a wallet")
            return

        args, from_addr = get_from_addr(args)

        function_code = LoadContract(args[1:])

        if function_code:

            contract_script = GatherContractDetails(function_code, self)

            if contract_script is not None:

                tx, fee, results, num_ops = test_invoke(contract_script, self.Wallet, [], from_addr=from_addr)

                if tx is not None and results is not None:
                    print(
                        "\n-------------------------------------------------------------------------------------------------------------------------------------")
                    print("Test deploy invoke successful")
                    print("Total operations executed: %s " % num_ops)
                    print("Results:")
                    print([item.GetInterface() for item in results])
                    print("Deploy Invoke TX GAS cost: %s " % (tx.Gas.value / Fixed8.D))
                    print("Deploy Invoke TX Fee: %s " % (fee.value / Fixed8.D))
                    print(
                        "-------------------------------------------------------------------------------------------------------------------------------------\n")
                    print("Enter your password to continue and deploy this contract")

                    passwd = prompt("[password]> ", is_password=True)
                    if not self.Wallet.ValidatePassword(passwd):
                        return print("Incorrect password")

                    result = InvokeContract(self.Wallet, tx, Fixed8.Zero(), from_addr=from_addr)

                    return
                else:
                    print("Test invoke failed")
                    print("TX is %s, results are %s" % (tx, results))
                    return

    def show_mem(self):
        process = psutil.Process(os.getpid())
        total = process.memory_info().rss
        totalmb = total / (1024 * 1024)
        out = "Total: %s MB\n" % totalmb
        out += "Total buffers: %s\n" % StreamManager.TotalBuffers()
        print_tokens([(Token.Number, out)], self.token_style)

    def handle_debug_storage(self, args):
        what = get_arg(args)

        if what == 'on':
            settings.USE_DEBUG_STORAGE = True
            print("Debug storage on")
        elif what == 'off':
            settings.USE_DEBUG_STORAGE = False
            print("Debug Storage off")
        elif what == 'reset':
            DebugStorage.instance().reset()
            print("Reset debug storage")
        else:
            print("Please specify on|off|reset")

    def configure(self, args):
        what = get_arg(args)

        if what == 'debug':
            c1 = get_arg(args, 1).lower()
            if c1 is not None:
                if c1 == 'on' or c1 == '1':
                    print("Debug logging is now enabled")
                    settings.set_loglevel(logging.DEBUG)
                if c1 == 'off' or c1 == '0':
                    print("Debug logging is now disabled")
                    settings.set_loglevel(logging.INFO)

            else:
                print("Cannot configure log. Please specify on|off")

        elif what == 'sc-events':
            c1 = get_arg(args, 1).lower()
            if c1 is not None:
                if c1 == 'on' or c1 == '1':
                    print("Smart contract event logging is now enabled")
                    settings.set_log_smart_contract_events(True)
                if c1 == 'off' or c1 == '0':
                    print("Smart contract event logging is now disabled")
                    settings.set_log_smart_contract_events(False)

            else:
                print("Cannot configure log. Please specify on|off")

        elif what == 'sc-debug-notify':
            c1 = get_arg(args, 1).lower()
            if c1 is not None:
                if c1 == 'on' or c1 == '1':
                    print("Smart contract emit Notify events on execution failure is now enabled")
                    settings.set_emit_notify_events_on_sc_execution_error(True)
                if c1 == 'off' or c1 == '0':
                    print("Smart contract emit Notify events on execution failure is now disabled")
                    settings.set_emit_notify_events_on_sc_execution_error(False)

            else:
                print("Cannot configure log. Please specify on|off")

        elif what == 'vm-log':
            c1 = get_arg(args, 1).lower()
            if c1 is not None:
                if c1 == 'on' or c1 == '1':
                    print("VM instruction execution logging is now enabled")
                    settings.set_log_vm_instruction(True)
                if c1 == 'off' or c1 == '0':
                    print("VM instruction execution logging is now disabled")
                    settings.set_log_vm_instruction(False)

            else:
                print("Cannot configure VM instruction logging. Please specify on|off")

        elif what == 'maxpeers':
            try:
                c1 = int(get_arg(args, 1).lower())
                num_peers = int(c1)
                if num_peers > 0:
                    old_max_peers = settings.CONNECTED_PEER_MAX
                    settings.set_max_peers(num_peers)
                    NodeLeader.Instance().OnUpdatedMaxPeers(old_max_peers, num_peers)
                    print("set max peers to %s " % num_peers)
                else:
                    print("Please specify integer greater than zero")
            except Exception as e:
                print("Cannot configure max peers. Please specify an integer greater than 0")

        else:
            print(
                "Cannot configure %s try 'config sc-events on|off', 'config debug on|off', 'config sc-debug-notify on|off' or 'config vm-log on|off'" % what)

    def run(self):
        dbloop = task.LoopingCall(Blockchain.Default().PersistBlocks)
        dbloop.start(.1)

#        Blockchain.Default().PersistBlocks()

        tokens = [(Token.Neo, 'NEO'), (Token.Default, ' cli. Type '),
                  (Token.Command, '\'help\' '), (Token.Default, 'to get started')]

        print_tokens(tokens, self.token_style)
        print('\n')

        while self.go_on:

            try:
                result = prompt("neo> ",
                                completer=self.get_completer(),
                                history=self.history,
                                get_bottom_toolbar_tokens=self.get_bottom_toolbar,
                                style=self.token_style,
                                refresh_interval=3
                                )
            except EOFError:
                # Control-D pressed: quit
                return self.quit()
            except KeyboardInterrupt:
                # Control-C pressed: do nothing
                continue

            try:
                command, arguments = self.input_parser.parse_input(result)

                if command is not None and len(command) > 0:
                    command = command.lower()

                    if command == 'quit' or command == 'exit':
                        self.quit()
                    elif command == 'help':
                        self.help()
                    elif command == 'create':
                        self.do_create(arguments)
                    elif command == 'open':
                        self.do_open(arguments)
                    elif command == 'build':
                        self.do_build(arguments)
                    elif command == 'load_run':
                        self.do_load_n_run(arguments)
                    elif command == 'import':
                        self.do_import(arguments)
                    elif command == 'export':
                        self.do_export(arguments)
                    elif command == 'wallet':
                        self.show_wallet(arguments)
                    elif command == 'send':
                        self.do_send(arguments)
                    elif command == 'sign':
                        self.do_sign(arguments)
                    elif command == 'block':
                        self.show_block(arguments)
                    elif command == 'tx':
                        self.show_tx(arguments)
                    elif command == 'header':
                        self.show_header(arguments)
                    elif command == 'account':
                        self.show_account_state(arguments)
                    elif command == 'asset':
                        self.show_asset_state(arguments)
                    elif command == 'contract':
                        self.show_contract_state(arguments)
                    elif command == 'testinvoke':
                        self.test_invoke_contract(arguments)
                    elif command == 'withdraw_request':
                        self.make_withdraw_request(arguments)
                    elif command == 'withdraw':
                        self.do_withdraw(arguments)
                    elif command == 'notifications':
                        self.do_notifications(arguments)
                    elif command == 'mem':
                        self.show_mem()
                    elif command == 'nodes' or command == 'node':
                        self.show_nodes()
                    elif command == 'state':
                        self.show_state()
                    elif command == 'debugstorage':
                        self.handle_debug_storage(arguments)
                    elif command == 'config':
                        self.configure(arguments)
                    elif command is None:
                        print("Please specify a command")
                    else:
                        print("Command %s not found" % command)

            except Exception as e:

                print("Could not execute command: %s" % e)
                traceback.print_stack()
                traceback.print_exc()
示例#3
0
 def __init__(self, engine):
     self.engine = engine
     self.parser = InputParser()
     self.debug_map = engine._debug_map
     self.index = engine.CurrentContext.InstructionPointer
示例#4
0
class PromptInterface:
    prompt_completer = None
    history = None

    go_on = True

    _walletdb_loop = None

    Wallet = None

    _known_things = []

    commands = [
        'quit', 'help', 'block {index/hash} (tx)', 'header {index/hash}',
        'tx {hash}', 'asset {assetId}', 'asset search {query}',
        'contract {contract hash}', 'contract search {query}',
        'notifications {block_number or address}', 'mem', 'nodes', 'state',
        'config debug {on/off}', 'config sc-events {on/off}',
        'config maxpeers {num_peers}',
        'config node-requests {reqsize} {queuesize}',
        'config node-requests {slow/normal/fast}',
        'build {path/to/file.py} (test {params} {returntype} {needs_storage} {needs_dynamic_invoke} [{test_params} or --i]) --no-parse-addr (parse address strings to script hash bytearray)',
        'load_run {path/to/file.avm} (test {params} {returntype} {needs_storage} {needs_dynamic_invoke} [{test_params} or --i]) --no-parse-addr (parse address strings to script hash bytearray)',
        'import wif {wif}', 'import nep2 {nep2_encrypted_key}',
        'import contract {path/to/file.avm} {params} {returntype} {needs_storage} {needs_dynamic_invoke}',
        'import contract_addr {contract_hash} {pubkey}',
        'import multisig_addr {pubkey in wallet} {minimum # of signatures required} {signing pubkey 1} {signing pubkey 2}...',
        'import watch_addr {address}', 'import token {token_contract_hash}',
        'export wif {address}', 'export nep2 {address}', 'open wallet {path}',
        'create wallet {path}', 'wallet {verbose}',
        'wallet claim (max_coins_to_claim)', 'wallet migrate',
        'wallet rebuild {start block}', 'wallet delete_addr {addr}',
        'wallet delete_token {token_contract_hash}',
        'wallet alias {addr} {title}',
        'wallet tkn_send {token symbol} {address_from} {address to} {amount} ',
        'wallet tkn_send_from {token symbol} {address_from} {address to} {amount}',
        'wallet tkn_approve {token symbol} {address_from} {address to} {amount}',
        'wallet tkn_allowance {token symbol} {address_from} {address to}',
        'wallet tkn_mint {token symbol} {mint_to_addr} (--attach-neo={amount}, --attach-gas={amount})',
        'wallet tkn_register {addr} ({addr}...) (--from-addr={addr})',
        'wallet tkn_history {token symbol}', 'wallet unspent (neo/gas)',
        'wallet split {addr} {asset} {unspent index} {divide into number of vins}'
        'wallet close',
        'withdraw_request {asset_name} {contract_hash} {to_addr} {amount}',
        'withdraw holds # lists all current holds',
        'withdraw completed # lists completed holds eligible for cleanup',
        'withdraw cancel # cancels current holds',
        'withdraw cleanup # cleans up completed holds',
        'withdraw # withdraws the first hold availabe',
        'withdraw all # withdraw all holds available',
        'send {assetId or name} {address} {amount} (--from-addr={addr})',
        'sign {transaction in JSON format}',
        'testinvoke {contract hash} [{params} or --i] (--attach-neo={amount}, --attach-gas={amount}) (--from-addr={addr}) --no-parse-addr (parse address strings to script hash bytearray)',
        'debugstorage {on/off/reset}'
    ]

    token_style = None
    start_height = None
    start_dt = None

    def __init__(self, history_filename=None):
        if history_filename:
            PromptInterface.history = PromptFileHistory(history_filename)

        self.input_parser = InputParser()
        self.start_height = Blockchain.Default().Height
        self.start_dt = datetime.datetime.utcnow()

        self.token_style = Style.from_dict({
            "command":
            preferences.token_style['Command'],
            "neo":
            preferences.token_style['Neo'],
            "default":
            preferences.token_style['Default'],
            "number":
            preferences.token_style['Number'],
        })

    def get_bottom_toolbar(self, cli=None):
        out = []
        try:
            # Note: not sure if prompt-toolkit still supports foreground colors, couldn't get it to work
            # out = [("class:command", '[%s] Progress: ' % settings.net_name),
            #        ("class:number", str(Blockchain.Default().Height + 1)),
            #        ("class:neo", '/'),
            #        ("class:number", str(Blockchain.Default().HeaderHeight + 1))]
            return "[%s] Progress: %s/%s" % (
                settings.net_name, str(Blockchain.Default().Height + 1),
                str(Blockchain.Default().HeaderHeight + 1))
        except Exception as e:
            pass

        return out

    def get_completer(self):

        standard_completions = [
            'block', 'tx', 'header', 'mem', 'neo', 'gas', 'help', 'state',
            'nodes', 'exit', 'quit', 'config', 'import', 'export', 'open',
            'wallet', 'contract', 'asset', 'wif', 'watch_addr',
            'contract_addr', 'testinvoke', 'tkn_send', 'tkn_mint',
            'tkn_send_from', 'tkn_approve', 'tkn_allowance', 'tkn_register',
            'build', 'notifications', 'tkn_history'
        ]

        if self.Wallet:
            for addr in self.Wallet.Addresses:
                if addr not in self._known_things:
                    self._known_things.append(addr)
            for alias in self.Wallet.NamedAddr:
                if alias.Title not in self._known_things:
                    self._known_things.append(alias.Title)
            for tkn in self.Wallet.GetTokens().values():
                if tkn.symbol not in self._known_things:
                    self._known_things.append(tkn.symbol)

        all_completions = standard_completions + self._known_things

        PromptInterface.prompt_completer = WordCompleter(all_completions)

        return PromptInterface.prompt_completer

    def quit(self):
        print('Shutting down. This may take a bit...')
        self.go_on = False
        self.do_close_wallet()
        reactor.stop()

    def help(self):
        tokens = []
        for c in self.commands:
            tokens.append(("class:command", "%s\n" % c))
        print_formatted_text(FormattedText(tokens), style=self.token_style)

    def do_open(self, arguments):
        if self.Wallet:
            self.do_close_wallet()

        item = get_arg(arguments)

        if item and item == 'wallet':

            path = get_arg(arguments, 1)

            if path:

                if not os.path.exists(path):
                    print("Wallet file not found")
                    return

                passwd = prompt("[password]> ", is_password=True)
                password_key = to_aes_key(passwd)

                try:
                    self.Wallet = UserWallet.Open(path, password_key)

                    self.start_wallet_loop()
                    print("Opened wallet at %s" % path)
                except Exception as e:
                    print("Could not open wallet: %s" % e)

            else:
                print("Please specify a path")
        else:
            print("Please specify something to open")

    def do_create(self, arguments):
        item = get_arg(arguments)

        if item and item == 'wallet':

            path = get_arg(arguments, 1)

            if path:

                if os.path.exists(path):
                    print("File already exists")
                    return

                passwd1 = prompt("[password]> ", is_password=True)
                passwd2 = prompt("[password again]> ", is_password=True)

                if passwd1 != passwd2 or len(passwd1) < 10:
                    print(
                        "Please provide matching passwords that are at least 10 characters long"
                    )
                    return

                password_key = to_aes_key(passwd1)

                try:
                    self.Wallet = UserWallet.Create(path=path,
                                                    password=password_key)
                    contract = self.Wallet.GetDefaultContract()
                    key = self.Wallet.GetKey(contract.PublicKeyHash)
                    print("Wallet %s" %
                          json.dumps(self.Wallet.ToJson(), indent=4))
                    print("Pubkey %s" % key.PublicKey.encode_point(True))
                except Exception as e:
                    print("Exception creating wallet: %s" % e)
                    self.Wallet = None
                    if os.path.isfile(path):
                        try:
                            os.remove(path)
                        except Exception as e:
                            print("Could not remove {}: {}".format(path, e))
                    return

                if self.Wallet:
                    self.start_wallet_loop()

            else:
                print("Please specify a path")

    def start_wallet_loop(self):
        self._walletdb_loop = task.LoopingCall(self.Wallet.ProcessBlocks)
        print("1111111111111111111111111111")
        print(self._walletdb_loop)
        print("1111111111111111111111111111")
        self._walletdb_loop.start(1)

    def stop_wallet_loop(self):
        self._walletdb_loop.stop()
        self._walletdb_loop = None

    def do_close_wallet(self):
        if self.Wallet:
            path = self.Wallet._path
            self.stop_wallet_loop()
            self.Wallet.Close()
            self.Wallet = None
            print("Closed wallet %s" % path)

    def do_import(self, arguments):
        item = get_arg(arguments)

        if not item:
            print("Please specify something to import")
            return

        if item == 'wif':
            if not self.Wallet:
                print("Please open a wallet before importing WIF")
                return

            wif = get_arg(arguments, 1)
            if not wif:
                print("Please supply a valid WIF key")
                return

            try:
                prikey = KeyPair.PrivateKeyFromWIF(wif)
                key = self.Wallet.CreateKey(prikey)
                print("Imported key: %s" % wif)
                print("Pubkey: %s\n" % key.PublicKey.encode_point(True).hex())
                print("Wallet: %s" %
                      json.dumps(self.Wallet.ToJson(), indent=4))
            except ValueError as e:
                print(str(e))
            except Exception as e:
                print(str(e))

            return

        elif item == 'nep2':
            if not self.Wallet:
                print("Please open a wallet before importing a NEP2 key")
                return

            nep2_key = get_arg(arguments, 1)
            if not nep2_key:
                print("Please supply a valid NEP2 encrypted private key")
                return

            nep2_passwd = prompt("[key password]> ", is_password=True)

            try:
                prikey = KeyPair.PrivateKeyFromNEP2(nep2_key, nep2_passwd)
                key = self.Wallet.CreateKey(prikey)
                print("Imported NEP2 key: %s" % nep2_key)
                print("Pubkey: %s\n" % key.PublicKey.encode_point(True).hex())
                print("Wallet: %s" %
                      json.dumps(self.Wallet.ToJson(), indent=4))
            except ValueError as e:
                print(str(e))
            except Exception as e:
                print(str(e))

            return

        elif item == 'contract':
            return self.load_smart_contract(arguments)

        elif item == 'contract_addr':
            return ImportContractAddr(self.Wallet, arguments[1:])

        elif item == 'watch_addr':
            return ImportWatchAddr(self.Wallet, get_arg(arguments, 1))

        elif item == 'multisig_addr':
            return ImportMultiSigContractAddr(self.Wallet, arguments[1:])

        elif item == 'token':
            return ImportToken(self.Wallet, get_arg(arguments, 1))

        else:
            print("Import of '%s' not implemented" % item)

    def do_build(self, arguments):
        print(arguments)
        print('4.2 ----4 -> Starting core process %s' % self.Wallet)
        print('4.3 ----4 -> Completed Blockchain deafault pause')
        Blockchain.Default().Pause()
        BuildAndRun(arguments, self.Wallet)
        Blockchain.Default().Resume()

    def do_load_n_run(self, arguments):
        LoadAndRun(arguments, self.Wallet)

    def do_export(self, arguments):
        item = get_arg(arguments)

        if item == 'wif':
            if not self.Wallet:
                return print("Please open a wallet")

            address = get_arg(arguments, 1)
            if not address:
                return print("Please specify an address")

            passwd = prompt("[wallet password]> ", is_password=True)
            if not self.Wallet.ValidatePassword(passwd):
                return print("Incorrect password")

            keys = self.Wallet.GetKeys()
            for key in keys:
                if key.GetAddress() == address:
                    export = key.Export()
                    print("WIF key export: %s" % export)
            return

        elif item == 'nep2':
            if not self.Wallet:
                return print("Please open a wallet")

            address = get_arg(arguments, 1)
            if not address:
                return print("Please specify an address")

            passwd = prompt("[wallet password]> ", is_password=True)
            if not self.Wallet.ValidatePassword(passwd):
                return print("Incorrect password")

            nep2_passwd1 = prompt("[key password]> ", is_password=True)
            if len(nep2_passwd1) < 10:
                return print(
                    "Please provide a password with at least 10 characters")

            nep2_passwd2 = prompt("[key password again]> ", is_password=True)
            if nep2_passwd1 != nep2_passwd2:
                return print("Passwords do not match")

            keys = self.Wallet.GetKeys()
            for key in keys:
                export = key.ExportNEP2(nep2_passwd1)
                print("NEP2 key export: %s" % export)
            return

        print("Command export %s not found" % item)

    def make_withdraw_request(self, arguments):
        if not self.Wallet:
            print("Please open a wallet")
            return
        if len(arguments) == 4:
            RequestWithdrawFrom(self.Wallet, arguments[0], arguments[1],
                                arguments[2], arguments[3])
        else:
            print(
                "Incorrect arg length. Use 'withdraw_request {asset_id} {contract_hash} {to_addr} {amount}'"
            )

    def do_withdraw(self, arguments):
        if not self.Wallet:
            print("Please open a wallet")
            return

        item = get_arg(arguments, 0)

        if item:

            if item == 'holds':
                PrintHolds(self.Wallet)
            elif item == 'delete_holds':
                index_to_delete = -1
                if get_arg(arguments, 1) and int(get_arg(arguments, 1)) > -1:
                    index_to_delete = int(get_arg(arguments, 1))
                DeleteHolds(self.Wallet, index_to_delete)
            elif item == 'cancel_holds':
                if len(arguments) > 1:
                    CancelWithdrawalHolds(self.Wallet, get_arg(arguments, 1))
                else:
                    print("Please specify contract hash to cancel holds for")
            elif item == 'completed':
                ShowCompletedHolds(self.Wallet)
            elif item == 'cleanup':
                CleanupCompletedHolds(self.Wallet)
            elif item == 'all':
                WithdrawAll(self.Wallet)
        else:
            WithdrawOne(self.Wallet)

    def do_notifications(self, arguments):
        if NotificationDB.instance() is None:
            print("No notification DB Configured")
            return

        item = get_arg(arguments, 0)
        events = []
        if len(item) == 34:
            addr = item
            events = NotificationDB.instance().get_by_addr(addr)
        else:
            try:
                block_height = int(item)
                if block_height < Blockchain.Default().Height:
                    events = NotificationDB.instance().get_by_block(
                        block_height)
                else:
                    print("Block %s not found" % block_height)
                    return
            except Exception as e:
                print("Could not parse block height %s" % e)
                return

        if len(events):
            [print(json.dumps(e.ToJson(), indent=4)) for e in events]
        else:
            print("No events found for %s" % item)

    def show_wallet(self, arguments):
        if not self.Wallet:
            print("Please open a wallet")
            return

        item = get_arg(arguments)

        if not item:
            print("Wallet %s " % json.dumps(self.Wallet.ToJson(), indent=4))
            return

        if item in ['v', '--v', 'verbose']:
            print("Wallet %s " %
                  json.dumps(self.Wallet.ToJson(verbose=True), indent=4))
            return
        elif item == 'migrate' and self.Wallet is not None:
            self.Wallet.Migrate()
            print("Migrated wallet")
        elif item == 'delete_addr':
            addr_to_delete = get_arg(arguments, 1)
            DeleteAddress(self, self.Wallet, addr_to_delete)
        elif item == 'delete_token':
            token_to_delete = get_arg(arguments, 1)
            DeleteToken(self.Wallet, token_to_delete)
        elif item == 'close':
            self.do_close_wallet()
        elif item == 'claim':
            ClaimGas(self.Wallet, True, arguments[1:])
        elif item == 'rebuild':
            self.stop_wallet_loop()
            try:
                self.Wallet.Rebuild()
            finally:
                self.start_wallet_loop()
            try:
                item2 = int(get_arg(arguments, 1))
                if item2 and item2 > 0:
                    print("Restarting at %s" % item2)
                    self.Wallet._current_height = item2
            except Exception as e:
                pass
        elif item == 'tkn_send':
            token_send(self.Wallet, arguments[1:])
        elif item == 'tkn_send_from':
            token_send_from(self.Wallet, arguments[1:])
        elif item == 'tkn_approve':
            token_approve_allowance(self.Wallet, arguments[1:])
        elif item == 'tkn_allowance':
            token_get_allowance(self.Wallet, arguments[1:], verbose=True)
        elif item == 'tkn_mint':
            token_mint(self.Wallet, arguments[1:])
        elif item == 'tkn_register':
            token_crowdsale_register(self.Wallet, arguments[1:])
        elif item == 'tkn_history':
            notification_db = NotificationDB.instance()
            token_history(self.Wallet, notification_db, arguments[1:])
        elif item == 'unspent':
            ShowUnspentCoins(self.Wallet, arguments[1:])
        elif item == 'split':
            SplitUnspentCoin(self.Wallet, arguments[1:])
        elif item == 'alias':
            if len(arguments) == 3:
                AddAlias(self.Wallet, arguments[1], arguments[2])
            else:
                print("Please supply an address and title")
        else:
            print("Wallet: '{}' is an invalid parameter".format(item))

    def do_send(self, arguments):
        construct_and_send(self, self.Wallet, arguments)

    def do_sign(self, arguments):
        jsn = get_arg(arguments)
        parse_and_sign(self, self.Wallet, jsn)

    def show_state(self):
        height = Blockchain.Default().Height
        headers = Blockchain.Default().HeaderHeight

        diff = height - self.start_height
        now = datetime.datetime.utcnow()
        difftime = now - self.start_dt

        mins = difftime / datetime.timedelta(minutes=1)
        secs = mins * 60

        bpm = 0
        tps = 0
        if diff > 0 and mins > 0:
            bpm = diff / mins
            tps = Blockchain.Default().TXProcessed / secs

        out = "Progress: %s / %s\n" % (height, headers)
        out += "Block-cache length %s\n" % Blockchain.Default().BlockCacheCount
        out += "Blocks since program start %s\n" % diff
        out += "Time elapsed %s mins\n" % mins
        out += "Blocks per min %s \n" % bpm
        out += "TPS: %s \n" % tps
        tokens = [("class:number", out)]
        print_formatted_text(FormattedText(tokens), style=self.token_style)

    def show_nodes(self):
        if len(NodeLeader.Instance().Peers) > 0:
            out = "Total Connected: %s\n" % len(NodeLeader.Instance().Peers)
            for peer in NodeLeader.Instance().Peers:
                out += "Peer %s - IO: %s\n" % (peer.Name(), peer.IOStats())
            print_formatted_text(FormattedText([("class:number", out)]),
                                 style=self.token_style)
        else:
            print("Not connected yet\n")

    def show_block(self, args):
        item = get_arg(args)
        txarg = get_arg(args, 1)
        if item is not None:
            block = Blockchain.Default().GetBlock(item)

            if block is not None:

                bjson = json.dumps(block.ToJson(), indent=4)
                tokens = [("class:number", bjson)]
                print_formatted_text(FormattedText(tokens),
                                     style=self.token_style)
                print('\n')
                if txarg and 'tx' in txarg:

                    for tx in block.FullTransactions:
                        print(json.dumps(tx.ToJson(), indent=4))

            else:
                print("Could not locate block %s" % item)
        else:
            print("please specify a block")

    def show_header(self, args):
        item = get_arg(args)
        if item is not None:
            header = Blockchain.Default().GetHeaderBy(item)
            if header is not None:
                print(json.dumps(header.ToJson(), indent=4))
            else:
                print("Could not locate header %s\n" % item)
        else:
            print("Please specify a header")

    def show_tx(self, args):
        if len(args):
            try:
                txid = UInt256.ParseString(get_arg(args))
                tx, height = Blockchain.Default().GetTransaction(txid)
                if height > -1:
                    jsn = tx.ToJson()
                    jsn['height'] = height
                    jsn['unspents'] = [
                        uns.ToJson(tx.outputs.index(uns))
                        for uns in Blockchain.Default().GetAllUnspent(txid)
                    ]
                    tokens = [("class:command", json.dumps(jsn, indent=4))]
                    print_formatted_text(FormattedText(tokens),
                                         style=self.token_style)
                    print('\n')
            except Exception as e:
                print("Could not find transaction from args: %s (%s)" %
                      (e, args))
        else:
            print("Please specify a TX hash")

    def show_account_state(self, args):
        item = get_arg(args)

        if item is not None:
            account = Blockchain.Default().GetAccountState(
                item, print_all_accounts=True)

            if account is not None:
                bjson = json.dumps(account.ToJson(), indent=4)
                tokens = [("class:number", bjson)]
                print_formatted_text(FormattedText(tokens),
                                     style=self.token_style)
                print('\n')
            else:
                print("Account %s not found" % item)
        else:
            print("Please specify an account address")

    def show_asset_state(self, args):
        item = get_arg(args)

        if item is not None:

            if item == 'search':
                query = get_arg(args, 1)
                results = Blockchain.Default().SearchAssetState(query)
                print("Found %s results for %s" % (len(results), query))
                for asset in results:
                    bjson = json.dumps(asset.ToJson(), indent=4)
                    tokens = [("class:number", bjson)]
                    print_formatted_text(FormattedText(tokens),
                                         style=self.token_style)
                    print('\n')

                return

            asset = Blockchain.Default().GetAssetState(item)

            if asset is not None:
                bjson = json.dumps(asset.ToJson(), indent=4)
                tokens = [("class:number", bjson)]
                print_formatted_text(FormattedText(tokens),
                                     style=self.token_style)
                print('\n')
            else:
                print("Asset %s not found" % item)
        else:
            print("Please specify an asset hash")

    def show_contract_state(self, args):
        item = get_arg(args)

        if item is not None:

            if item.lower() == 'all':
                contracts = Blockchain.Default().ShowAllContracts()
                print("Contracts: %s" % contracts)
            elif item.lower() == 'search':
                query = get_arg(args, 1)
                if query:

                    contracts = Blockchain.Default().SearchContracts(
                        query=query)
                    print("Found %s results for %s" % (len(contracts), query))
                    for contract in contracts:
                        bjson = json.dumps(contract.ToJson(), indent=4)
                        tokens = [("class:number", bjson)]
                        print_formatted_text(FormattedText(tokens),
                                             style=self.token_style)
                        print('\n')
                else:
                    print("Please specify a search query")
            else:
                contract = Blockchain.Default().GetContract(item)

                if contract is not None:
                    contract.DetermineIsNEP5()
                    jsn = contract.ToJson()
                    bjson = json.dumps(jsn, indent=4)
                    tokens = [("class:number", bjson)]
                    print_formatted_text(FormattedText(tokens),
                                         style=self.token_style)
                    print('\n')
        else:
            print("Please specify a contract")

    def test_invoke_contract(self, args):
        if not self.Wallet:
            print("Please open a wallet")
            return
        args, from_addr = get_from_addr(args)
        args, invoke_attrs = get_tx_attr_from_args(args)
        args, owners = get_owners_from_params(args)
        if args and len(args) > 0:
            tx, fee, results, num_ops = TestInvokeContract(
                self.Wallet,
                args,
                from_addr=from_addr,
                invoke_attrs=invoke_attrs,
                owners=owners)

            if tx is not None and results is not None:

                parameterized_results = [
                    ContractParameter.ToParameter(item) for item in results
                ]

                print(
                    "\n-------------------------------------------------------------------------------------------------------------------------------------"
                )
                print("Test invoke successful")
                print("Total operations: %s" % num_ops)
                print("Results %s" %
                      [item.ToJson() for item in parameterized_results])
                print("Invoke TX GAS cost: %s" % (tx.Gas.value / Fixed8.D))
                print("Invoke TX fee: %s" % (fee.value / Fixed8.D))
                print(
                    "-------------------------------------------------------------------------------------------------------------------------------------\n"
                )
                print(
                    "Enter your password to continue and invoke on the network\n"
                )

                tx.Attributes = invoke_attrs

                passwd = prompt("[password]> ", is_password=True)
                if not self.Wallet.ValidatePassword(passwd):
                    return print("Incorrect password")

                InvokeContract(self.Wallet,
                               tx,
                               fee,
                               from_addr=from_addr,
                               owners=owners)
                return
            else:
                print("Error testing contract invoke")
                return

        print("Please specify a contract to invoke")

    def load_smart_contract(self, args):
        if not self.Wallet:
            print("Please open a wallet")
            return

        args, from_addr = get_from_addr(args)
        print("-------------------------------------->")
        print(args)
        print("<<<<<<<<<<<<-------------------------------------->")
        print(from_addr)
        print("<<<<<<<<<<<<----------------------+++++---------------->")
        function_code = LoadContract(args[1:])

        if function_code:

            contract_script = GatherContractDetails(function_code)

            if contract_script is not None:

                tx, fee, results, num_ops = test_invoke(contract_script,
                                                        self.Wallet, [],
                                                        from_addr=from_addr)

                if tx is not None and results is not None:
                    print(
                        "\n-------------------------------------------------------------------------------------------------------------------------------------"
                    )
                    print("Test deploy invoke successful")
                    print("Total operations executed: %s " % num_ops)
                    print("Results:")
                    print([item.GetInterface() for item in results])
                    print("Deploy Invoke TX GAS cost: %s " %
                          (tx.Gas.value / Fixed8.D))
                    print("Deploy Invoke TX Fee: %s " % (fee.value / Fixed8.D))
                    print(
                        "-------------------------------------------------------------------------------------------------------------------------------------\n"
                    )
                    print(
                        "Enter your password to continue and deploy this contract"
                    )

                    passwd = prompt("[password]> ", is_password=True)
                    if not self.Wallet.ValidatePassword(passwd):
                        return print("Incorrect password")

                    result = InvokeContract(self.Wallet,
                                            tx,
                                            Fixed8.Zero(),
                                            from_addr=from_addr)

                    return
                else:
                    print("Test invoke failed")
                    print("TX is %s, results are %s" % (tx, results))
                    return

    def show_mem(self):
        process = psutil.Process(os.getpid())
        total = process.memory_info().rss
        totalmb = total / (1024 * 1024)
        out = "Total: %s MB\n" % totalmb
        out += "Total buffers: %s\n" % StreamManager.TotalBuffers()
        print_formatted_text(FormattedText([("class:number", out)]),
                             style=self.token_style)

    def handle_debug_storage(self, args):
        what = get_arg(args)

        if what == 'on':
            settings.USE_DEBUG_STORAGE = True
            print("Debug storage on")
        elif what == 'off':
            settings.USE_DEBUG_STORAGE = False
            print("Debug Storage off")
        elif what == 'reset':
            DebugStorage.instance().reset()
            print("Reset debug storage")
        else:
            print("Please specify on|off|reset")

    def configure(self, args):
        what = get_arg(args)

        if what == 'debug':
            c1 = get_arg(args, 1).lower()
            if c1 is not None:
                if c1 == 'on' or c1 == '1':
                    print("Debug logging is now enabled")
                    settings.set_loglevel(logging.DEBUG)
                if c1 == 'off' or c1 == '0':
                    print("Debug logging is now disabled")
                    settings.set_loglevel(logging.INFO)

            else:
                print("Cannot configure log. Please specify on|off")

        elif what == 'sc-events':
            c1 = get_arg(args, 1).lower()
            if c1 is not None:
                if c1 == 'on' or c1 == '1':
                    print("Smart contract event logging is now enabled")
                    settings.set_log_smart_contract_events(True)
                if c1 == 'off' or c1 == '0':
                    print("Smart contract event logging is now disabled")
                    settings.set_log_smart_contract_events(False)

            else:
                print("Cannot configure log. Please specify on|off")

        elif what == 'sc-debug-notify':
            c1 = get_arg(args, 1).lower()
            if c1 is not None:
                if c1 == 'on' or c1 == '1':
                    print(
                        "Smart contract emit Notify events on execution failure is now enabled"
                    )
                    settings.set_emit_notify_events_on_sc_execution_error(True)
                if c1 == 'off' or c1 == '0':
                    print(
                        "Smart contract emit Notify events on execution failure is now disabled"
                    )
                    settings.set_emit_notify_events_on_sc_execution_error(
                        False)

            else:
                print("Cannot configure log. Please specify on|off")

        elif what == 'vm-log':
            c1 = get_arg(args, 1).lower()
            if c1 is not None:
                if c1 == 'on' or c1 == '1':
                    print("VM instruction execution logging is now enabled")
                    settings.set_log_vm_instruction(True)
                if c1 == 'off' or c1 == '0':
                    print("VM instruction execution logging is now disabled")
                    settings.set_log_vm_instruction(False)

            else:
                print(
                    "Cannot configure VM instruction logging. Please specify on|off"
                )

        elif what == 'node-requests':
            if len(args) == 3:
                NodeLeader.Instance().setBlockReqSizeAndMax(
                    int(args[1]), int(args[2]))
            elif len(args) == 2:
                NodeLeader.Instance().setBlockReqSizeByName(args[1])
        else:
            print(
                "Cannot configure %s try 'config sc-events on|off', 'config debug on|off', 'config sc-debug-notify on|off' or 'config vm-log on|off'"
                % what)

    def run(self):
        dbloop = task.LoopingCall(Blockchain.Default().PersistBlocks)
        dbloop.start(.1)

        tokens = [("class:neo", 'NEO'), ("class:default", ' cli. Type '),
                  ("class:command", '\'help\' '),
                  ("class:default", 'to get started')]

        print_formatted_text(FormattedText(tokens), style=self.token_style)
        print('\n')

        while self.go_on:

            session = PromptSession(
                "neo> ",
                completer=self.get_completer(),
                history=self.history,
                bottom_toolbar=self.get_bottom_toolbar,
                style=self.token_style,
                refresh_interval=3,
            )

            try:
                result = session.prompt()
            except EOFError:
                # Control-D pressed: quit
                return self.quit()
            except KeyboardInterrupt:
                # Control-C pressed: do nothing
                continue

            try:
                command, arguments = self.input_parser.parse_input(result)

                if command is not None and len(command) > 0:
                    command = command.lower()

                    if command == 'quit' or command == 'exit':
                        self.quit()
                    elif command == 'help':
                        self.help()
                    elif command == 'create':
                        self.do_create(arguments)
                    elif command == 'open':
                        self.do_open(arguments)
                    elif command == 'build':
                        self.do_build(arguments)
                    elif command == 'load_run':
                        self.do_load_n_run(arguments)
                    elif command == 'import':
                        self.do_import(arguments)
                    elif command == 'export':
                        self.do_export(arguments)
                    elif command == 'wallet':
                        self.show_wallet(arguments)
                    elif command == 'send':
                        self.do_send(arguments)
                    elif command == 'sign':
                        self.do_sign(arguments)
                    elif command == 'block':
                        self.show_block(arguments)
                    elif command == 'tx':
                        self.show_tx(arguments)
                    elif command == 'header':
                        self.show_header(arguments)
                    elif command == 'account':
                        self.show_account_state(arguments)
                    elif command == 'asset':
                        self.show_asset_state(arguments)
                    elif command == 'contract':
                        self.show_contract_state(arguments)
                    elif command == 'testinvoke':
                        self.test_invoke_contract(arguments)
                    elif command == 'withdraw_request':
                        self.make_withdraw_request(arguments)
                    elif command == 'withdraw':
                        self.do_withdraw(arguments)
                    elif command == 'notifications':
                        self.do_notifications(arguments)
                    elif command == 'mem':
                        self.show_mem()
                    elif command == 'nodes' or command == 'node':
                        self.show_nodes()
                    elif command == 'state':
                        self.show_state()
                    elif command == 'debugstorage':
                        self.handle_debug_storage(arguments)
                    elif command == 'config':
                        self.configure(arguments)
                    elif command == 'pause':
                        Blockchain.Default().Pause()
                    elif command == 'resume':
                        Blockchain.Default().Resume()

                    elif command is None:
                        print("Please specify a command")
                    else:
                        print("Command %s not found" % command)

            except Exception as e:

                print("Could not execute command: %s" % e)
                traceback.print_stack()
                traceback.print_exc()
示例#5
0
class VMDebugger():

    engine = None
    parser = None

    debug_map = None
    debug_context = None
    index = None

    continue_debug = False

    def __init__(self, engine):
        self.engine = engine
        self.parser = InputParser()
        self.debug_map = engine._debug_map
        self.index = engine.CurrentContext.InstructionPointer

    def end(self):
        self.continue_debug = False

    def start(self):

        self.continue_debug = True
        #        pprint.pprint(self.debug_map)

        dbg_title = self.debug_map['avm']['name']
        print("\n")
        print("======= debug engine enter =======")

        ctx = self.get_context()
        ctx.print()

        while self.continue_debug:
            try:
                result = prompt("[%s debug]> " % dbg_title)
            except EOFError:
                # Control-D pressed: quit
                self.continue_debug = False
            except KeyboardInterrupt:
                # Control-C pressed: do nothing
                self.continue_debug = False

            command, arguments = self.parser.parse_input(result)

            if command is not None and len(command) > 0:
                command = command.lower()

                if command in ['quit', 'exit', 'cont']:
                    self.continue_debug = False

                elif command == 'estack':
                    if len(self.engine.EvaluationStack.Items):
                        for item in self.engine.EvaluationStack.Items:
                            print(ContractParameter.ToParameter(item).ToJson())
                    else:
                        print("Evaluation stack empty")

                elif command == 'istack':
                    print("Invocation Stack:")
                    for item in self.engine.InvocationStack.Items:
                        pprint.pprint(item)
                        print(vars(item))

                elif command == 'astack':
                    if len(self.engine.AltStack.Items):
                        for item in self.engine.AltStack.Items:
                            print(ContractParameter.ToParameter(item).ToJson())
                    else:
                        print("Alt Stack Empty")

                elif command == 'ctx':
                    ctx.print()

                elif command == 'file':
                    ctx.print_file()

                elif command == 'ops':
                    ctx.print_method_ops()

                elif command == 'pdb':
                    pdb.set_trace()

                elif command == 'help':
                    print(
                        "Use one of [estack, istack, astack, exit, quit, ctx, file, ops, pdb, or any local variable]"
                    )

                elif command in ctx.method.scope:
                    try:
                        idx = ctx.method.scope[command]
                        value = self.engine.AltStack.Items[-1].GetArray()[idx]
                        param = ContractParameter.ToParameter(value)
                        print("\n")
                        print(
                            '%s = %s [%s]' %
                            (command, json.dumps(param.Value.ToJson(),
                                                 indent=4) if param.Type
                             == ContractParameterType.InteropInterface else
                             param.Value, param.Type))
                        print("\n")
                    except Exception as e:
                        logger.error("Could not lookup item %s: %s " %
                                     (command, e))
                else:
                    print("unknown command: %s " % command)

        print("======= debug engine exit =======")
        print("\n")

    def get_context(self):
        files = self.debug_map['files']
        for item in self.debug_map['map']:
            if item['start'] == self.index:
                ctx = DebugContext(item, files)
                return ctx