Esempio n. 1
0
def api_consensus_height(height):
    data = {}
    data['height'] = height
    data['consensus_hash'] = client.get_consensus_at(height)
    resp = Response(response=json.dumps(data),
    status=200, \
    mimetype="application/json")
    return (resp)
Esempio n. 2
0
def dontUseServer(blockstored_server):
    """
        Return false if server fails any tests
    """

    from registrar.config import CONSENSUS_SERVERS
    from basicrpc import Proxy

    servers_to_check = CONSENSUS_SERVERS
    servers_to_check.append(blockstored_server)

    consensus_hashes = []
    # initialize to a very large number
    last_block_everyone = 2000000000

    for server in servers_to_check:

        bs_client = Proxy(server, BLOCKSTORED_PORT)

        last_block_seen = bs_client.getinfo()[0]['bitcoind_blocks']
        try:
            last_block_processed = bs_client.getinfo()[0]['last_block']
        except:
            last_block_processed = bs_client.getinfo()[0]['blocks']

        if (last_block_seen - last_block_processed) > 10:
            log.debug("Server %s, seems to be lagging: (%s, %s)"
                      % (server, last_block_seen, last_block_processed))

            return True

        if last_block_processed < last_block_everyone:
            last_block_everyone = last_block_processed

    for server in servers_to_check:

        bs_client = Proxy(server, BLOCKSTORED_PORT)
        consensus_hash = bs_client.get_consensus_at(last_block_everyone)[0]
        print consensus_hash
        consensus_hashes.append(consensus_hash)

    check_hash = consensus_hashes[0]

    for stored_hash in consensus_hashes:

        if check_hash != stored_hash:
            log.debug('Mismatch in consensus hashes from %s' % servers_to_check)
            return True

    # can use server, if all tests pass
    return False
Esempio n. 3
0
            def pg_api_consensus(request):
                request.setHeader('Content-Type', 'application/json')
                responsebody = {}

                if 'height' in request.args:
                    height = int(request.args['height'][0])
                else:
                    height = yield client.getinfo()['last_block']

                responsebody['height'] = height

                responsebody['consensus'] = yield client.get_consensus_at(
                    height)

                if 'traceback' in responsebody:
                    del responsebody['traceback']

                returnValue(json.dumps(responsebody))
def run_cli():
    """ run cli
    """

    conf = config.get_config()
    if conf is None:
        log.error("Failed to load config")
        sys.exit(1)

    parser = argparse.ArgumentParser(
      description='Blockstore Cli version {}'.format(config.VERSION))

    parser.add_argument(
      '--blockstored-server',
      help="""the hostname/IP of server (default: {})""".format(config.BLOCKSTORED_SERVER))

    parser.add_argument(
      '--blockstored-port', type=int,
      help="""the server port to connect to (default: {})""".format(config.BLOCKSTORED_PORT))

    parser.add_argument(
      '--txid', type=str,
      help="tx hash of a partially-failed storage operation")

    subparsers = parser.add_subparsers(
      dest='action',
      help='the action to be taken')

    # ------------------------------------
    # start commands

    subparser = subparsers.add_parser(
      'delete_immutable',
      help='<name> <hash> <privatekey> | Delete immutable data from the storage providers.')
    subparser.add_argument(
      'name', type=str,
      help='the name of the user')
    subparser.add_argument(
      'hash', type=str,
      help='the hash of the data')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the user')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'delete_mutable',
      help='<name> <data_id> <privatekey> | Delete mutable data from the storage providers.')
    subparser.add_argument(
      'name', type=str,
      help='the name of the user')
    subparser.add_argument(
      'data_id', type=str,
      help='the unchanging identifier for this data')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the user')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_all_names',
      help='[offset] [count] | get all names that exist')
    subparser.add_argument(
      'offset', nargs='?',
      help='The offset into the list at which to start reading')
    subparser.add_argument(
      'count', nargs='?',
      help='The maximum number of names to return')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_consensus_at',
      help='<block ID> | get the consensus hash at a particular block')
    subparser.add_argument(
      'block_id', type=int,
      help='The block ID.')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_immutable',
      help='<name> <hash> | get immutable data from storage')
    subparser.add_argument(
      'name', type=str,
      help='the name of the user')
    subparser.add_argument(
      'hash', type=str,
      help='the hash of the data')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_mutable',
      help='<name> <data_id> | get mutable data from storage')
    subparser.add_argument(
      'name', type=str,
      help='the name associated with the data')
    subparser.add_argument(
      'data_id', type=str,
      help='the unchanging identifier for this data')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_name_cost',
      help="<name> | get the cost of a name")
    subparser.add_argument(
      'name', type=str,
      help="The fully-qualified name to check")

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_names_in_namespace',
      help='<namespace ID> [offset] [count] | get all names in a particular namespace')
    subparser.add_argument(
      'namespace_id', type=str,
      help='The namespace to search')
    subparser.add_argument(
      'offset', nargs='?',
      help='The offset into the list at which to start reading')
    subparser.add_argument(
      'count', nargs='?',
      help='The maximum number of names to return')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_names_owned_by_address',
      help='<address> | get all names owned by an address')
    subparser.add_argument(
      'address', type=str,
      help='The address to query')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_namespace_cost',
      help="<namespace_id> | get the cost of a namespace")
    subparser.add_argument(
      'namespace_id', type=str,
      help="The namespace ID to check")

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_name_record',
      help='<name> | get the off-blockchain record for a given name')
    subparser.add_argument(
      'name', type=str,
      help='the name to look up')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'getinfo',
      help='get basic info from the blockstored server')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_name_blockchain_record',
      help='<name> | get the blockchain-hosted information for a particular name')
    subparser.add_argument(
      'name', type=str,
      help='the name to query')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_namespace_blockchain_record',
      help='<namespace_id> | get the blockchain-hosted information for a particular namespace')
    subparser.add_argument(
      'namespace_id', type=str,
      help='the namespace to look up')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'lookup',
      help='<name> | get name record for a particular name')
    subparser.add_argument(
      'name', type=str,
      help='the name to look up')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'lookup_snv',
      help='<name> <block_id> <consensus_hash> | Look up a name as it existed at a particular block, using SNV protocol')
    subparser.add_argument(
      'name', type=str,
      help='the name to look up')
    subparser.add_argument(
      'block_id', type=int,
      help='the block ID in the desired point in the past')
    subparser.add_argument(
      'consensus_hash', type=str,
      help='the trusted consensus hash at the given block')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'get_nameops_at',
      help='<block_id> | Look up all name operations that occurred at a block')
    subparser.add_argument(
      'block_id', type=int,
      help='the block ID in the desired point in the past')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'name_import',
      help='import a name into a revealed namespace')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to import')
    subparser.add_argument(
      'address', type=str,
      help='the new owner\'s Bitcoin address')
    subparser.add_argument(
      'hash', type=str,
      help='hash of the storage index to associate with the name')
    subparser.add_argument(
      'privatekey', type=str,
      help='the private key of the namespace revealer\'s address')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'namespace_preorder',
      help='preorder a namespace and claim the name')
    subparser.add_argument(
      'namespace_id', type=str,
      help='the human-readable namespace identifier')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the namespace creator')
    subparser.add_argument(
      'address', type=str, nargs='?',
      help='[OPTIONAL] the address of private key that will import names into this namespace (should be different from the private key given here).  \
      If not given, a new private key will be generated.  The private key must be used to sign name_import requests, and the address must be submitted on namespace_reveal')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'namespace_reveal',
      help='define a namespace\'s parameters once preorder succeeds')
    subparser.add_argument(
      'namespace_id', type=str,
      help='the human-readable namespace identifier')
    subparser.add_argument(
      'addr', type=str,
      help='the address that will import names into the namespace, and open it for registration')
    subparser.add_argument(
      'lifetime', type=int,
      help='the number of blocks for which a name will be valid (any value less than zero means "forever")')
    subparser.add_argument(
      'coeff', type=int,
      help='constant cost multipler for names (in range [0, 256))')
    subparser.add_argument(
      'base', type=int,
      help='base cost for names (in range [0, 256))')
    subparser.add_argument(
      'bucket_exponents', type=str,
      help='per-name-length cost exponents (CSV string of 16 values in range [0, 16))')
    subparser.add_argument(
      'nonalpha_discount', type=int,
      help='non-alpha discount multipler (in range [0, 16))')
    subparser.add_argument(
      'no_vowel_discount', type=int,
      help='no-vowel discount multipler (in range [0, 16))')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the namespace creator (from namespace_preorder)')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'namespace_ready',
      help='open namespace for registrations')
    subparser.add_argument(
      'namespace_id', type=str,
      help='the human-readable namespace identifier')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the namespace creator')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'ping',
      help='check if the blockstored server is up')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'preorder',
      help='<name> <privatekey> | preorder a name')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to preorder')
    subparser.add_argument(
      'privatekey', type=str,
      help='the private key of the Bitcoin account to pay for the name')
    subparser.add_argument(
      'address', type=str, nargs='?',
      help='[OPTIONAL] the address that will own the name (should be different from the address of the private key given here). \
      If not given, a new private key will be generated, and its address must be submitted upon register.')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'preorder_tx',
      help='<name> <privatekey> [address] | create an unsigned serialized transaction that will preorder a name.')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to preorder')
    subparser.add_argument(
      'privatekey', type=str,
      help='the private key of the Bitcoin account to pay for the name and register it')
    subparser.add_argument(
      'address', type=str, nargs='?',
      help='[OPTIONAL] the address that will own the name (should be different from the address of the private key given here). \
      If not given, a new private key will be generated, and its address must be submitted upon register.')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'preorder_subsidized',
      help='<name> <public_key> <address> <subsidy_key> | create an "anyone-can-pay" transaction to preorder a name, subsidized with a separate key.  The client must sign the <public_key>\'s address input separately to complete the transaction.')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to preorder')
    subparser.add_argument(
      'public_key', type=str,
      help='the client\'s public key, whose private counterpart will sign the subsidized transaction.')
    subparser.add_argument(
      'address', type=str,
      help='The address that will own the name (should be different from the address of the public key given here). \
      If not given, a new private key will be generated, and its address must be submitted upon register.')
    subparser.add_argument(
      'subsidy_key', type=str,
      help='the private key of the Bitcoin account to pay for the name')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'put_immutable',
      help='store immutable data into storage')
    subparser.add_argument(
      'name', type=str,
      help='the name that owns this data')
    subparser.add_argument(
      'data', type=str,
      help='the data to store')
    subparser.add_argument(
      'privatekey', type=str,
      help='the private key associated with the name')

    # ------------------------------------
    put_mutable_parser = subparsers.add_parser(
      'put_mutable',
      help='<name> <data_id> <data> <privatekey> [<nonce>] | Store mutable data into the storage providers, creating it if it does not exist.')
    put_mutable_parser.add_argument(
      'name', type=str,
      help='the name that owns this data')
    put_mutable_parser.add_argument(
      'data_id', type=str,
      help='the unchanging identifier for this data')
    put_mutable_parser.add_argument(
      'data', type=str,
      help='the data to store')
    put_mutable_parser.add_argument(
      'privatekey', type=str,
      help='the private key assocated with the name')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'register',
      help='<name> <privatekey> <addr> | register/claim a name')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to register/claim')
    subparser.add_argument(
      'privatekey', type=str,
      help='the private key used to preorder the name')
    subparser.add_argument(
      'addr', type=str,
      help='the address that will own the name (given in the preorder)')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'register_tx',
      help='<name> <privatekey> <addr> | Generate an unsigned transaction to register/claim a name')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to register/claim')
    subparser.add_argument(
      'privatekey', type=str,
      help='the private key used to preorder the name')
    subparser.add_argument(
      'addr', type=str,
      help='the address that will own the name (given in the preorder)')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'register_subsidized',
      help='<name> <public_key> <addr> <subsidy_key> | create an "anyone-can-pay" transaction to register/claim a name, subsidized by a separate key.  The client must sign the <public_key>\'s address inputs before broadcasting it.')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to register/claim')
    subparser.add_argument(
      'public_key', type=str,
      help='the private key used to preorder the name')
    subparser.add_argument(
      'addr', type=str,
      help='the address that will own the name (given in the preorder)')
    subparser.add_argument(
      'subsidy_key', type=str,
      help='the private key used to pay for this transaction')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'renew',
      help='<name> <privatekey> | renew a name')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to renew')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the owner Bitcoin address')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'renew_tx',
      help='<name> <privatekey> | create an unsigned transaction to renew a name')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to renew')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the owner Bitcoin address')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'renew_subsidized',
      help='<name> <public_key> <subsidy_key> | create an "anyone-can-pay" transaction to renew a name, subsidized by a separate key.  The client must sign the <public_key>\'s address inputs before broadcasting it.')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to renew')
    subparser.add_argument(
      'public_key', type=str,
      help='the public key of the owner')
    subparser.add_argument(
      'subsidy_key', type=str,
      help='the key to subsidize the transaction')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'revoke',
      help='<name> <privatekey> | revoke a name and its data')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to revoke')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the owner Bitcoin address')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'revoke_tx',
      help='<name> <privatekey> | generate an unsigned transaction to revoke a name and its data')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to revoke')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the owner Bitcoin address')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'revoke_subsidized',
      help='<name> <public_key> <subsidy_key> | create an "anyone-can-pay" transaction to revoke a name and its data, subsidized by a separate key.  The client must sign the <public_key>\'s address inputs before broadcasting it.')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to revoke')
    subparser.add_argument(
      'public_key', type=str,
      help='the public key of the owner Bitcoin address')
    subparser.add_argument(
      'subsidy_key', type=str,
      help='the key to subsidize the transaction')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'transfer',
      help='<name> <address> <keepdata> <privatekey> | transfer a name')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to register/claim')
    subparser.add_argument(
      'address', type=str,
      help='the new owner Bitcoin address')
    subparser.add_argument(
      'keepdata', type=str,
      help='whether or not the storage index should remain associated with the name [true|false]')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the owner Bitcoin address')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'transfer_tx',
      help='<name> <address> <keepdata> <privatekey> | create an unsigned transaction that will transfer a name')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to register/claim')
    subparser.add_argument(
      'address', type=str,
      help='the new owner Bitcoin address')
    subparser.add_argument(
      'keepdata', type=str,
      help='whether or not the storage index should remain associated with the name [true|false]')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the owner Bitcoin address')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'transfer_subsidized',
      help='<name> <address> <keepdata> <public_key> <subsidy_key> | create an "anyone-can-pay" transaction that will transfer a name, subsidized by a separate key.  The client must sign the <public_key>\s address inputs before broadcasting it.')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to register/claim')
    subparser.add_argument(
      'address', type=str,
      help='the new owner Bitcoin address')
    subparser.add_argument(
      'keepdata', type=str,
      help='whether or not the storage index should remain associated with the name [true|false]')
    subparser.add_argument(
      'public_key', type=str,
      help='the public key of the owner Bitcoin address')
    subparser.add_argument(
      'subsidy_key', type=str,
      help='the key to subsidize the transaction.')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'update',
      help='<name> <record_json> <private_key> [txid] | update and store a name record')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to update')
    subparser.add_argument(
      'record_json', type=str,
      help='the JSON-encoded user record to associate with the name')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the owner Bitcoin address')
    subparser.add_argument(
      'txid', type=str, nargs='?',
      help='[OPTIONAL] the transaction ID of the previously-attempted, partially-successful update')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'update_tx',
      help='<name> <record_json> <private_key> [txid] | generate an unsigned transaction to update and store a name record')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to update')
    subparser.add_argument(
      'record_json', type=str,
      help='the JSON-encoded user record to associate with the name')
    subparser.add_argument(
      'privatekey', type=str,
      help='the privatekey of the owner Bitcoin address')
    subparser.add_argument(
      'txid', type=str, nargs='?',
      help='[OPTIONAL] the transaction ID of the previously-attempted, partially-successful update')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'update_subsidized',
      help='<name> <record_json> <public_key> <subsidy_key> [txid] | generate an "anyone-can-pay" transaction to update and store a name record, subsidized by a separate key.  The client will need to sign the <public_key>\'s address inputs before broadcasting it.')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to update')
    subparser.add_argument(
      'record_json', type=str,
      help='the JSON-encoded user record to associate with the name')
    subparser.add_argument(
      'public_key', type=str,
      help='the public key of the owner Bitcoin address')
    subparser.add_argument(
      'subsidy_key', type=str,
      help='the key to subsidize the transaction')
    subparser.add_argument(
      'txid', type=str, nargs='?',
      help='[OPTIONAL] the transaction ID of the previously-attempted, partially-successful update')


    # Print default help message, if no argument is given
    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args, unknown_args = parser.parse_known_args()
    result = {}

    blockstore_server = args.blockstored_server
    blockstore_port = args.blockstored_port

    if blockstore_server is None:
        blockstore_server = config.BLOCKSTORED_SERVER

    if blockstore_port is None:
        blockstore_port = config.BLOCKSTORED_PORT

    proxy = client.session(conf=conf, server_host=blockstore_server, server_port=blockstore_port )

    if args.action == 'getinfo':
        result = client.getinfo()

    elif args.action == 'ping':
        result = client.ping()

    elif args.action == 'preorder':

        register_addr = None
        if args.address is not None:
            register_addr = str(args.address)

        result = client.preorder(str(args.name), str(args.privatekey), register_addr=register_addr )

    elif args.action == 'preorder_tx':

        register_addr = None
        if args.address is not None:
            register_addr = str(args.address)

        result = client.preorder(str(args.name), str(args.privatekey), register_addr=register_addr, tx_only=True )

    elif args.action == 'preorder_subsidized':

        result = client.preorder_subsidized( str(args.name), str(args.public_key), str(args.address), str(args.subsidy_key) )

    elif args.action == 'register':
        result = client.register(str(args.name), str(args.privatekey), str(args.addr))

    elif args.action == 'register_tx':
        result = client.register(str(args.name), str(args.privatekey), str(args.addr), tx_only=True )

    elif args.action == 'register_subsidized':
        result = client.register_subsidized(str(args.name), str(args.privatekey), str(args.addr), str(args.subsidy_key) )

    elif args.action == 'update':

        txid = None
        if args.txid is not None:
            txid = str(args.txid)

        result = client.update(str(args.name),
                               str(args.record_json),
                               str(args.privatekey),
                               txid=txid)


    elif args.action == 'update_tx':

        txid = None
        if args.txid is not None:
            txid = str(args.txid)

        result = client.update(str(args.name),
                               str(args.record_json),
                               str(args.privatekey),
                               txid=txid, tx_only=True)


    elif args.action == 'update_subsidized':

        txid = None
        if args.txid is not None:
            txid = str(args.txid)

        result = client.update_subsidized(str(args.name),
                                          str(args.record_json),
                                          str(args.public_key),
                                          str(args.subsidy_key),
                                          txid=txid)

    elif args.action == 'transfer':
        keepdata = False
        if args.keepdata.lower() not in ["true", "false"]:
            print >> sys.stderr, "Pass 'true' or 'false' for keepdata"
            sys.exit(1)

        if args.keepdata.lower() == "true":
            keepdata = True

        result = client.transfer(str(args.name),
                                 str(args.address),
                                 keepdata,
                                 str(args.privatekey))


    elif args.action == 'transfer_tx':
        keepdata = False
        if args.keepdata.lower() not in ["true", "false"]:
            print >> sys.stderr, "Pass 'true' or 'false' for keepdata"
            sys.exit(1)

        if args.keepdata.lower() == "true":
            keepdata = True

        result = client.transfer(str(args.name),
                                 str(args.address),
                                 keepdata,
                                 str(args.privatekey),
                                 tx_only=True)


    elif args.action == 'transfer_subsidized':
        keepdata = False
        if args.keepdata.lower() not in ["true", "false"]:
            print >> sys.stderr, "Pass 'true' or 'false' for keepdata"
            sys.exit(1)

        if args.keepdata.lower() == "true":
            keepdata = True

        result = client.transfer_subsidized(str(args.name),
                                            str(args.address),
                                            keepdata,
                                            str(args.public_key),
                                            str(args.subsidy_key))

    elif args.action == 'renew':
        result = client.renew(str(args.name), str(args.privatekey))

    elif args.action == 'renew_tx':
        result = client.renew(str(args.name), str(args.privatekey), tx_only=True)

    elif args.action == 'renew_subsidized':
        result = client.renew_subsidized(str(args.name), str(args.public_key), str(args.subsidy_key))

    elif args.action == 'revoke':
        result = client.revoke(str(args.name), str(args.privatekey))

    elif args.action == 'revoke_tx':
        result = client.revoke(str(args.name), str(args.privatekey), tx_only=True)

    elif args.action == 'revoke_subsidized':
        result = client.revoke_subsidized(str(args.name), str(args.public_key), str(args.subsidy_key))

    elif args.action == 'name_import':
        result = client.name_import(str(args.name), str(args.address), str(args.hash), str(args.privatekey))

    elif args.action == 'namespace_preorder':

        reveal_addr = None
        if args.address is not None:
            reveal_addr = str(args.address)

        result = client.namespace_preorder(str(args.namespace_id),
                                           str(args.privatekey),
                                           reveal_addr=reveal_addr)


    elif args.action == 'namespace_reveal':
        bucket_exponents = args.bucket_exponents.split(',')
        if len(bucket_exponents) != 16:
            raise Exception("bucket_exponents must be a 16-value CSV of integers")

        for i in xrange(0, len(bucket_exponents)):
            try:
                bucket_exponents[i] = int(bucket_exponents[i])
            except:
                raise Exception("bucket_exponents must contain integers in range [0, 16)")

        lifetime = int(args.lifetime)
        if lifetime < 0:
            lifetime = 0xffffffff       # means "infinite" to blockstore

        result = client.namespace_reveal(str(args.namespace_id),
                                         str(args.addr),
                                         lifetime,
                                         int(args.coeff),
                                         int(args.base),
                                         bucket_exponents,
                                         int(args.nonalpha_discount),
                                         int(args.no_vowel_discount),
                                         str(args.privatekey))

    elif args.action == 'namespace_ready':
        result = client.namespace_ready(str(args.namespace_id),
                                        str(args.privatekey))

    elif args.action == 'put_mutable':
        result = client.put_mutable(str(args.name),
                                    str(args.data_id),
                                    str(args.data),
                                    str(args.privatekey))

    elif args.action == 'put_immutable':
        result = client.put_immutable(str(args.name),
                                      str(args.data),
                                      str(args.privatekey),
                                      conf=conf)

    elif args.action == 'get_mutable':
        result = client.get_mutable(str(args.name), str(args.data_id), conf=conf)

    elif args.action == 'get_immutable':
        result = client.get_immutable(str(args.name), str(args.hash))

    elif args.action == 'delete_immutable':
        result = client.delete_immutable(str(args.name), str(args.hash), str(args.privatekey))

    elif args.action == 'delete_mutable':
        result = client.delete_mutable(str(args.name), str(args.data_id), str(args.privatekey))

    elif args.action == 'get_name_blockchain_record':
        result = client.get_name_blockchain_record(str(args.name))

    elif args.action == 'get_namespace_blockchain_record':
        result = client.get_namespace_blockchain_record(str(args.namespace_id))

    elif args.action == 'lookup':
        result = client.lookup(str(args.name))

    elif args.action == 'lookup_snv':
        result = client.lookup_snv(str(args.name), int(args.block_id), str(args.consensus_hash) )

    elif args.action == 'get_name_record':
        result = client.get_name_record( str(args.name) )

    elif args.action == 'get_name_cost':
        result = client.get_name_cost(str(args.name))

    elif args.action == 'get_names_owned_by_address':
        result = client.get_names_owned_by_address(str(args.address))

    elif args.action == 'get_namespace_cost':
        result = client.get_namespace_cost(str(args.namespace_id))

    elif args.action == 'get_all_names':
        offset = None
        count = None

        if args.offset is not None:
            offset = int(args.offset)

        if args.count is not None:
            count = int(args.count)

        result = client.get_all_names( offset, count )

    elif args.action == 'get_names_in_namespace':
        offset = None
        count = None

        if args.offset is not None:
            offset = int(args.offset)

        if args.count is not None:
            count = int(args.count)

        result = client.get_names_in_namespace( str(args.namespace_id), offset, count )

    elif args.action == 'get_consensus_at':
        result = client.get_consensus_at( int(args.block_id) )

    elif args.action == 'get_nameops_at':
        result = client.get_nameops_at( int(args.block_id) )

    print_result(result)
def run_cli():
    """ run cli
    """

    conf = config.get_config()

    if conf is None:
        log.error("Failed to load config")
        sys.exit(1)

    advanced_mode = conf['advanced_mode']

    parser = argparse.ArgumentParser(
      description='Blockstack cli version {}'.format(config.VERSION))

    subparsers = parser.add_subparsers(
      dest='action')

    # ------------------------------------
    # start commands

    subparser = subparsers.add_parser(
      'advanced',
      help='check advanced mode | turn --mode=off or --mode=on')

    subparser.add_argument(
      '--mode',
      action='store',
      help="can be 'on' or 'off'")

    # ------------------------------------
    if advanced_mode == "on":
      subparser = subparsers.add_parser(
        'delete_immutable',
        help='<name> <hash> <privatekey> | Delete immutable data from the storage providers.')
      subparser.add_argument(
        'name', type=str,
        help='the name of the user')
      subparser.add_argument(
        'hash', type=str,
        help='the hash of the data')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the user')

    # ------------------------------------
    if advanced_mode == "on":
      subparser = subparsers.add_parser(
        'delete_mutable',
        help='<name> <data_id> <privatekey> | Delete mutable data from the storage providers.')
      subparser.add_argument(
        'name', type=str,
        help='the name of the user')
      subparser.add_argument(
        'data_id', type=str,
        help='the unchanging identifier for this data')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the user')

    # ------------------------------------
    if advanced_mode == "on":
      subparser = subparsers.add_parser(
        'get_all_names',
        help='[offset] [count] | get all names that exist')
      subparser.add_argument(
        'offset', nargs='?',
        help='The offset into the list at which to start reading')
      subparser.add_argument(
        'count', nargs='?',
        help='The maximum number of names to return')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'consensus',
      help='<block number> | get consensus hash at given block')
    subparser.add_argument(
      'block_height', type=int, nargs='?',
      help='The block height.')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_immutable',
        help='<name> <hash> | get immutable data from storage')
      subparser.add_argument(
        'name', type=str,
        help='the name of the user')
      subparser.add_argument(
        'hash', type=str,
        help='the hash of the data')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_mutable',
        help='<name> <data_id> | get mutable data from storage')
      subparser.add_argument(
        'name', type=str,
        help='the name associated with the data')
      subparser.add_argument(
        'data_id', type=str,
        help='the unchanging identifier for this data')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'cost',
      help="<name> | get the cost of a name")
    subparser.add_argument(
      'name', type=str,
      help="The fully-qualified name to check")

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_names_in_namespace',
        help='<namespace ID> [offset] [count] | get all names in a particular namespace')
      subparser.add_argument(
        'namespace_id', type=str,
        help='The namespace to search')
      subparser.add_argument(
        'offset', nargs='?',
        help='The offset into the list at which to start reading')
      subparser.add_argument(
        'count', nargs='?',
        help='The maximum number of names to return')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_names_owned_by_address',
        help='<address> | get all names owned by an address')
      subparser.add_argument(
        'address', type=str,
        help='The address to query')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_namespace_cost',
        help="<namespace_id> | get the cost of a namespace")
      subparser.add_argument(
        'namespace_id', type=str,
        help="The namespace ID to check")

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_name_record',
        help='<name> | get the off-blockchain record for a given name')
      subparser.add_argument(
        'name', type=str,
        help='the name to look up')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_name_blockchain_record',
        help='<name> | get the blockchain-hosted information for a particular name')
      subparser.add_argument(
        'name', type=str,
        help='the name to query')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_namespace_blockchain_record',
        help='<namespace_id> | get the blockchain-hosted information for a particular namespace')
      subparser.add_argument(
        'namespace_id', type=str,
        help='the namespace to look up')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'lookup',
      help='<name> | get data record for a particular name')
    subparser.add_argument(
      'name', type=str,
      help='the name to look up')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'lookup_snv',
        help='<name> <block_id> <consensus_hash> | Look up a name as it existed at a particular block, using SNV protocol')
      subparser.add_argument(
        'name', type=str,
        help='the name to look up')
      subparser.add_argument(
        'block_id', type=int,
        help='the block ID in the desired point in the past')
      subparser.add_argument(
        'consensus_hash', type=str,
        help='the trusted consensus hash at the given block')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'get_nameops_at',
        help='<block_id> | Look up all name operations that occurred at a block')
      subparser.add_argument(
        'block_id', type=int,
        help='the block ID in the desired point in the past')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'name_import',
        help='import a name into a revealed namespace')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to import')
      subparser.add_argument(
        'address', type=str,
        help='the new owner\'s Bitcoin address')
      subparser.add_argument(
        'hash', type=str,
        help='hash of the storage index to associate with the name')
      subparser.add_argument(
        'privatekey', type=str,
        help='the private key of the namespace revealer\'s address')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'namespace_preorder',
        help='preorder a namespace and claim the name')
      subparser.add_argument(
        'namespace_id', type=str,
        help='the human-readable namespace identifier')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the namespace creator')
      subparser.add_argument(
        'address', type=str, nargs='?',
        help='[OPTIONAL] the address of private key that will import names into this namespace (should be different from the private key given here).  \
        If not given, a new private key will be generated.  The private key must be used to sign name_import requests, and the address must be submitted on namespace_reveal')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'namespace_reveal',
        help='define a namespace\'s parameters once preorder succeeds')
      subparser.add_argument(
        'namespace_id', type=str,
        help='the human-readable namespace identifier')
      subparser.add_argument(
        'addr', type=str,
        help='the address that will import names into the namespace, and open it for registration')
      subparser.add_argument(
        'lifetime', type=int,
        help='the number of blocks for which a name will be valid (any value less than zero means "forever")')
      subparser.add_argument(
        'coeff', type=int,
        help='constant cost multipler for names (in range [0, 256))')
      subparser.add_argument(
        'base', type=int,
        help='base cost for names (in range [0, 256))')
      subparser.add_argument(
        'bucket_exponents', type=str,
        help='per-name-length cost exponents (CSV string of 16 values in range [0, 16))')
      subparser.add_argument(
        'nonalpha_discount', type=int,
        help='non-alpha discount multipler (in range [0, 16))')
      subparser.add_argument(
        'no_vowel_discount', type=int,
        help='no-vowel discount multipler (in range [0, 16))')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the namespace creator (from namespace_preorder)')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'namespace_ready',
        help='open namespace for registrations')
      subparser.add_argument(
        'namespace_id', type=str,
        help='the human-readable namespace identifier')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the namespace creator')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'ping',
      help='check if the blockstack server is up')

    # ------------------------------------
    if advanced_mode == "on":
      subparser = subparsers.add_parser(
        'preorder',
        help='<name> <private_key> | preorder a name')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to preorder')
      subparser.add_argument(
        'privatekey', type=str,
        help='the private key of the Bitcoin account to pay for the name')
      subparser.add_argument(
        'address', type=str, nargs='?',
        help='[OPTIONAL] the address that will own the name (should be different from the address of the private key given here). \
        If not given, a new private key will be generated, and its address must be submitted upon register.')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'preorder_tx',
        help='<name> <privatekey> [address] | create an unsigned serialized transaction that will preorder a name.')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to preorder')
      subparser.add_argument(
        'privatekey', type=str,
        help='the private key of the Bitcoin account to pay for the name and register it')
      subparser.add_argument(
        'address', type=str, nargs='?',
        help='[OPTIONAL] the address that will own the name (should be different from the address of the private key given here). \
        If not given, a new private key will be generated, and its address must be submitted upon register.')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'preorder_subsidized',
        help='<name> <public_key> <address> <subsidy_key> | create an "anyone-can-pay" transaction to preorder a name, subsidized with a separate key.  The client must sign the <public_key>\'s address input separately to complete the transaction.')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to preorder')
      subparser.add_argument(
        'public_key', type=str,
        help='the client\'s public key, whose private counterpart will sign the subsidized transaction.')
      subparser.add_argument(
        'address', type=str,
        help='The address that will own the name (should be different from the address of the public key given here). \
        If not given, a new private key will be generated, and its address must be submitted upon register.')
      subparser.add_argument(
        'subsidy_key', type=str,
        help='the private key of the Bitcoin account to pay for the name')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'put_immutable',
        help='store immutable data into storage')
      subparser.add_argument(
        'name', type=str,
        help='the name that owns this data')
      subparser.add_argument(
        'data', type=str,
        help='the data to store')
      subparser.add_argument(
        'privatekey', type=str,
        help='the private key associated with the name')

    if advanced_mode == "on":
      # ------------------------------------
      put_mutable_parser = subparsers.add_parser(
        'put_mutable',
        help='<name> <data_id> <data> <privatekey> [<nonce>] | Store mutable data into the storage providers, creating it if it does not exist.')
      put_mutable_parser.add_argument(
        'name', type=str,
        help='the name that owns this data')
      put_mutable_parser.add_argument(
        'data_id', type=str,
        help='the unchanging identifier for this data')
      put_mutable_parser.add_argument(
        'data', type=str,
        help='the data to store')
      put_mutable_parser.add_argument(
        'privatekey', type=str,
        help='the private key assocated with the name')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'register',
      help='<name> <data> | register a name')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to register')
    subparser.add_argument(
      'data', type=str,
      help='the data record (in JSON format)')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'register_tx',
        help='<name> <privatekey> <addr> | Generate an unsigned transaction to register/claim a name')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to register/claim')
      subparser.add_argument(
        'privatekey', type=str,
        help='the private key used to preorder the name')
      subparser.add_argument(
        'addr', type=str,
        help='the address that will own the name (given in the preorder)')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'register_subsidized',
        help='<name> <public_key> <addr> <subsidy_key> | create an "anyone-can-pay" transaction to register/claim a name, subsidized by a separate key.  The client must sign the <public_key>\'s address inputs before broadcasting it.')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to register/claim')
      subparser.add_argument(
        'public_key', type=str,
        help='the private key used to preorder the name')
      subparser.add_argument(
        'addr', type=str,
        help='the address that will own the name (given in the preorder)')
      subparser.add_argument(
        'subsidy_key', type=str,
        help='the private key used to pay for this transaction')

    if advanced_mode == "on":
        # ------------------------------------
        subparser = subparsers.add_parser(
          'renew',
          help='<name> <privatekey> | renew a name')
        subparser.add_argument(
          'name', type=str,
          help='the name that you want to renew')
        subparser.add_argument(
          'privatekey', type=str,
          help='the privatekey of the owner Bitcoin address')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'renew_tx',
        help='<name> <privatekey> | create an unsigned transaction to renew a name')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to renew')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the owner Bitcoin address')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'renew_subsidized',
        help='<name> <public_key> <subsidy_key> | create an "anyone-can-pay" transaction to renew a name, subsidized by a separate key.  The client must sign the <public_key>\'s address inputs before broadcasting it.')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to renew')
      subparser.add_argument(
        'public_key', type=str,
        help='the public key of the owner')
      subparser.add_argument(
        'subsidy_key', type=str,
        help='the key to subsidize the transaction')

    if advanced_mode == "on":
        # ------------------------------------
        subparser = subparsers.add_parser(
          'revoke',
          help='<name> <privatekey> | revoke a name and its data')
        subparser.add_argument(
          'name', type=str,
          help='the name that you want to revoke')
        subparser.add_argument(
          'privatekey', type=str,
          help='the privatekey of the owner Bitcoin address')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'revoke_tx',
        help='<name> <privatekey> | generate an unsigned transaction to revoke a name and its data')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to revoke')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the owner Bitcoin address')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'revoke_subsidized',
        help='<name> <public_key> <subsidy_key> | create an "anyone-can-pay" transaction to revoke a name and its data, subsidized by a separate key.  The client must sign the <public_key>\'s address inputs before broadcasting it.')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to revoke')
      subparser.add_argument(
        'public_key', type=str,
        help='the public key of the owner Bitcoin address')
      subparser.add_argument(
        'subsidy_key', type=str,
        help='the key to subsidize the transaction')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'server',
      help='display server:port | change by --server=x --port=y')

    subparser.add_argument(
      '--server',
      action='store',
      help="""the hostname/IP of blockstack server (current: {})""".format(config.BLOCKSTORED_SERVER))

    subparser.add_argument(
      '--port',
      action='store',
      help="""the server port to connect to (current: {})""".format(config.BLOCKSTORED_PORT))

    # ------------------------------------
    subparser = subparsers.add_parser(
      'status',
      help='get basic information from the blockstack server')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'transfer',
      help='<name> <address> | transfer a name you own')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to transfer')
    subparser.add_argument(
      'address', type=str,
      help='the new owner Bitcoin address')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'transfer_tx',
        help='<name> <address> <keepdata> <privatekey> | create an unsigned transaction that will transfer a name')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to register/claim')
      subparser.add_argument(
        'address', type=str,
        help='the new owner Bitcoin address')
      subparser.add_argument(
        'keepdata', type=str,
        help='whether or not the storage index should remain associated with the name [true|false]')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the owner Bitcoin address')

    if advanced_mode == "on":
      # ------------------------------------
      subparser = subparsers.add_parser(
        'transfer_subsidized',
        help='<name> <address> <keepdata> <public_key> <subsidy_key> | create an "anyone-can-pay" transaction that will transfer a name, subsidized by a separate key.  The client must sign the <public_key>\s address inputs before broadcasting it.')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to register/claim')
      subparser.add_argument(
        'address', type=str,
        help='the new owner Bitcoin address')
      subparser.add_argument(
        'keepdata', type=str,
        help='whether or not the storage index should remain associated with the name [true|false]')
      subparser.add_argument(
        'public_key', type=str,
        help='the public key of the owner Bitcoin address')
      subparser.add_argument(
        'subsidy_key', type=str,
        help='the key to subsidize the transaction.')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'update',
      help='<name> <data> | update a name record')
    subparser.add_argument(
      'name', type=str,
      help='the name that you want to update')
    subparser.add_argument(
      'data', type=str,
      help='the new data record (in JSON format)')

    if advanced_mode == 'true':
      # ------------------------------------
      subparser = subparsers.add_parser(
        'update_tx',
        help='<name> <record_json> <private_key> [txid] | generate an unsigned transaction to update and store a name record')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to update')
      subparser.add_argument(
        'record_json', type=str,
        help='the JSON-encoded user record to associate with the name')
      subparser.add_argument(
        'privatekey', type=str,
        help='the privatekey of the owner Bitcoin address')
      subparser.add_argument(
        'txid', type=str, nargs='?',
        help='[OPTIONAL] the transaction ID of the previously-attempted, partially-successful update')

      # ------------------------------------
      subparser = subparsers.add_parser(
        'update_subsidized',
        help='<name> <record_json> <public_key> <subsidy_key> [txid] | generate an "anyone-can-pay" transaction to update and store a name record, subsidized by a separate key.  The client will need to sign the <public_key>\'s address inputs before broadcasting it.')
      subparser.add_argument(
        'name', type=str,
        help='the name that you want to update')
      subparser.add_argument(
        'record_json', type=str,
        help='the JSON-encoded user record to associate with the name')
      subparser.add_argument(
        'public_key', type=str,
        help='the public key of the owner Bitcoin address')
      subparser.add_argument(
        'subsidy_key', type=str,
        help='the key to subsidize the transaction')
      subparser.add_argument(
        'txid', type=str, nargs='?',
        help='[OPTIONAL] the transaction ID of the previously-attempted, partially-successful update')

    # ------------------------------------
    subparser = subparsers.add_parser(
      'wallet',
      help='display wallet information')


    # Print default help message, if no argument is given
    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args, unknown_args = parser.parse_known_args()
    result = {}

    conf = config.get_config()

    blockstore_server = conf['server']
    blockstore_port = conf['port']

    proxy = client.session(conf=conf, server_host=blockstore_server, server_port=blockstore_port)

    # start the two background processes (rpc daemon and monitor queue)
    start_background_daemons()

    if args.action == 'server':
        data = {}

        if args.server is not None and args.port is not None:
            config.update_config('blockstack-client', 'server', args.server)
            config.update_config('blockstack-client', 'port', args.port)
            data["message"] = "Updated server and port"
        elif args.server is not None:
            config.update_config('blockstack-client', 'server', args.server)
            data["message"] = "Updated server"
        elif args.port is not None:
            config.update_config('blockstack-client', 'port', args.port)
            data["message"] = "Updated port"

        # reload conf
        conf = config.get_config()

        data['server'] = conf['server']
        data['port'] = conf['port']
        result = data

    elif args.action == 'advanced':
        data = {}
        data["advanced_mode"] = advanced_mode

        if args.mode is not None:

            if args.mode != "on" and args.mode != "off":
                data['error'] = "Valid values are 'on' or 'off'"
            else:
                config.update_config('blockstack-client', 'advanced_mode', args.mode)
                data["message"] = "Updated advanced_mode"

        # reload conf
        conf = config.get_config()

        data['advanced_mode'] = conf['advanced_mode']

        result = data

    elif args.action == 'status':
        resp = client.getinfo()

        result = {}

        if 'error' in resp:
            result['error'] = resp['error']
        else:

            result['server'] = conf['server'] + ':' + str(conf['port'])
            result['server_version'] = resp['blockstore_version']
            result['cli_version'] = config.VERSION
            try:
              result['last_block_processed'] = resp['last_block']
            except:
              result['last_block_processed'] = resp['blocks']
            result['last_block_seen'] = resp['bitcoind_blocks']
            result['consensus_hash'] = resp['consensus']

            if advanced_mode == 'on':
                result['testset'] = resp['testset']

            proxy = get_local_proxy()

            if proxy is not False:

              current_state = json.loads(proxy.state())

              pending_queue = []
              preorder_queue = []
              register_queue = []
              update_queue = []
              transfer_queue = []

              for entry in current_state:

                  if 'type' in entry:
                      if entry['type'] == 'pending':
                          pending_queue.append(entry['fqu'])
                      elif entry['type'] == 'preorder':
                          preorder_queue.append(entry['fqu'])
                      elif entry['type'] == 'register':
                          register_queue.append(entry['fqu'])
                      elif entry['type'] == 'update':
                          update_queue.append(entry['fqu'])
                      elif entry['type'] == 'transfer':
                          transfer_queue.append(entry['fqu'])

              if len(pending_queue) != 0:
                  result['pending_queue'] = pending_queue

              if len(preorder_queue) != 0:
                  result['preorder_queue'] = preorder_queue

              if len(register_queue) != 0:
                  result['register_queue'] = register_queue

              if len(update_queue) != 0:
                  result['update_queue'] = update_queue

              if len(transfer_queue) != 0:
                  result['transfer_queue'] = transfer_queue

    # -----------------------------
    elif args.action == 'ping':
        result = client.ping()

    elif args.action == 'preorder':

        register_addr = None
        if args.address is not None:
            register_addr = str(args.address)

        result = client.preorder(str(args.name), str(args.privatekey), register_addr=register_addr )

    elif args.action == 'preorder_tx':

        register_addr = None
        if args.address is not None:
            register_addr = str(args.address)

        result = client.preorder(str(args.name), str(args.privatekey), register_addr=register_addr, tx_only=True )

    elif args.action == 'preorder_subsidized':

        result = client.preorder_subsidized( str(args.name), str(args.public_key), str(args.address), str(args.subsidy_key) )

    elif args.action == 'register':
        result = {}
        fqu = str(args.name)
        cost = client.get_name_cost(fqu)

        if 'error' in cost:
            result['error'] = "This namespace doesn't exist, try using namespaces like .id"

        data = client.get_name_blockchain_record(fqu)

        if 'value_hash' in data:
            result['error'] = "%s is already registered" % fqu

        user_data = str(args.data)
        try:
            user_data = json.loads(user_data)
        except:
            result['error'] = "data is not in JSON format"

        proxy = get_local_proxy()
        result = proxy.register(fqu, user_data)

    elif args.action == 'register_tx':
        result = client.register(str(args.name), str(args.privatekey), str(args.addr), tx_only=True )

    elif args.action == 'register_subsidized':
        result = client.register_subsidized(str(args.name), str(args.privatekey), str(args.addr), str(args.subsidy_key) )

    elif args.action == 'update':

        txid = None
        if args.txid is not None:
            txid = str(args.txid)

        result = client.update(str(args.name),
                               str(args.record_json),
                               str(args.privatekey),
                               txid=txid)

    elif args.action == 'update_tx':

        txid = None
        if args.txid is not None:
            txid = str(args.txid)

        result = client.update(str(args.name),
                               str(args.record_json),
                               str(args.privatekey),
                               txid=txid, tx_only=True)

    elif args.action == 'update_subsidized':

        txid = None
        if args.txid is not None:
            txid = str(args.txid)

        result = client.update_subsidized(str(args.name),
                                          str(args.record_json),
                                          str(args.public_key),
                                          str(args.subsidy_key),
                                          txid=txid)

    elif args.action == 'transfer':
        keepdata = False
        if args.keepdata.lower() not in ["on", "false"]:
            print >> sys.stderr, "Pass 'true' or 'false' for keepdata"
            sys.exit(1)

        if args.keepdata.lower() == "on":
            keepdata = True

        result = client.transfer(str(args.name),
                                 str(args.address),
                                 keepdata,
                                 str(args.privatekey))

    elif args.action == 'transfer_tx':
        keepdata = False
        if args.keepdata.lower() not in ["on", "false"]:
            print >> sys.stderr, "Pass 'true' or 'false' for keepdata"
            sys.exit(1)

        if args.keepdata.lower() == "on":
            keepdata = True

        result = client.transfer(str(args.name),
                                 str(args.address),
                                 keepdata,
                                 str(args.privatekey),
                                 tx_only=True)

    elif args.action == 'transfer_subsidized':
        keepdata = False
        if args.keepdata.lower() not in ["on", "false"]:
            print >> sys.stderr, "Pass 'true' or 'false' for keepdata"
            sys.exit(1)

        if args.keepdata.lower() == "on":
            keepdata = True

        result = client.transfer_subsidized(str(args.name),
                                            str(args.address),
                                            keepdata,
                                            str(args.public_key),
                                            str(args.subsidy_key))

    elif args.action == 'renew':
        result = client.renew(str(args.name), str(args.privatekey))

    elif args.action == 'renew_tx':
        result = client.renew(str(args.name), str(args.privatekey), tx_only=True)

    elif args.action == 'renew_subsidized':
        result = client.renew_subsidized(str(args.name), str(args.public_key), str(args.subsidy_key))

    elif args.action == 'revoke':
        result = client.revoke(str(args.name), str(args.privatekey))

    elif args.action == 'revoke_tx':
        result = client.revoke(str(args.name), str(args.privatekey), tx_only=True)

    elif args.action == 'revoke_subsidized':
        result = client.revoke_subsidized(str(args.name), str(args.public_key), str(args.subsidy_key))

    elif args.action == 'name_import':
        result = client.name_import(str(args.name), str(args.address), str(args.hash), str(args.privatekey))

    elif args.action == 'namespace_preorder':

        reveal_addr = None
        if args.address is not None:
            reveal_addr = str(args.address)

        result = client.namespace_preorder(str(args.namespace_id),
                                           str(args.privatekey),
                                           reveal_addr=reveal_addr)

    elif args.action == 'namespace_reveal':
        bucket_exponents = args.bucket_exponents.split(',')
        if len(bucket_exponents) != 16:
            raise Exception("bucket_exponents must be a 16-value CSV of integers")

        for i in xrange(0, len(bucket_exponents)):
            try:
                bucket_exponents[i] = int(bucket_exponents[i])
            except:
                raise Exception("bucket_exponents must contain integers in range [0, 16)")

        lifetime = int(args.lifetime)
        if lifetime < 0:
            lifetime = 0xffffffff       # means "infinite" to blockstore

        result = client.namespace_reveal(str(args.namespace_id),
                                         str(args.addr),
                                         lifetime,
                                         int(args.coeff),
                                         int(args.base),
                                         bucket_exponents,
                                         int(args.nonalpha_discount),
                                         int(args.no_vowel_discount),
                                         str(args.privatekey))

    elif args.action == 'namespace_ready':
        result = client.namespace_ready(str(args.namespace_id),
                                        str(args.privatekey))

    elif args.action == 'put_mutable':
        result = client.put_mutable(str(args.name),
                                    str(args.data_id),
                                    str(args.data),
                                    str(args.privatekey))

    elif args.action == 'put_immutable':
        result = client.put_immutable(str(args.name),
                                      str(args.data),
                                      str(args.privatekey),
                                      conf=conf)

    elif args.action == 'get_mutable':
        result = client.get_mutable(str(args.name), str(args.data_id), conf=conf)

    elif args.action == 'get_immutable':
        result = client.get_immutable(str(args.name), str(args.hash))

    elif args.action == 'delete_immutable':
        result = client.delete_immutable(str(args.name), str(args.hash), str(args.privatekey))

    elif args.action == 'delete_mutable':
        result = client.delete_mutable(str(args.name), str(args.data_id), str(args.privatekey))

    elif args.action == 'get_name_blockchain_record':
        result = client.get_name_blockchain_record(str(args.name))

    elif args.action == 'get_namespace_blockchain_record':
        result = client.get_namespace_blockchain_record(str(args.namespace_id))

    elif args.action == 'lookup':
        data = {}
        data['blockchain_record'] = client.get_name_blockchain_record(str(args.name))

        try:
            data_id = data['blockchain_record']['value_hash']
            data['data_record'] = json.loads(client.get_immutable(str(args.name), data_id)['data'])
        except:
            data['data_record'] = None

        result = data

    elif args.action == 'lookup_snv':
        result = client.lookup_snv(str(args.name), int(args.block_id), str(args.consensus_hash) )

    elif args.action == 'get_name_record':
        result = client.get_name_record( str(args.name) )

    elif args.action == 'cost':
        result = client.get_name_cost(str(args.name))

    elif args.action == 'get_names_owned_by_address':
        result = client.get_names_owned_by_address(str(args.address))

    elif args.action == 'get_namespace_cost':
        result = client.get_namespace_cost(str(args.namespace_id))

    elif args.action == 'get_all_names':
        offset = None
        count = None

        if args.offset is not None:
            offset = int(args.offset)

        if args.count is not None:
            count = int(args.count)

        result = client.get_all_names( offset, count )

    elif args.action == 'get_names_in_namespace':
        offset = None
        count = None

        if args.offset is not None:
            offset = int(args.offset)

        if args.count is not None:
            count = int(args.count)

        result = client.get_names_in_namespace( str(args.namespace_id), offset, count )

    elif args.action == 'consensus':

        if args.block_height is None:
            # by default get last indexed block
            args.block_height = client.getinfo()['last_block']

        resp = client.get_consensus_at( int(args.block_height) )

        data = {}
        data['consensus'] = resp
        data['block_height'] = args.block_height

        result = data

    elif args.action == 'get_nameops_at':
        result = client.get_nameops_at( int(args.block_id) )

    elif args.action == 'wallet':

        if not os.path.exists(WALLET_PATH):
            result = initialize_wallet()
        else:
            unlock_wallet(display_enabled=True)

    print_result(result)