Example #1
0
 def __init__(self, config):
     super(CounterpartydAPI, self).__init__()
     clientapi.initialize(
         testnet=config.TESTNET,
         testcoin=False,
         counterparty_rpc_connect=config.COUNTERPARTY_RPC_CONNECT,
         counterparty_rpc_port=config.COUNTERPARTY_RPC_PORT,
         counterparty_rpc_user=config.COUNTERPARTY_RPC_USER,
         counterparty_rpc_password=config.COUNTERPARTY_RPC_PASSWORD,
         counterparty_rpc_ssl=config.COUNTERPARTY_RPC_SSL,
         counterparty_rpc_ssl_verify=config.COUNTERPARTY_RPC_SSL_VERIFY,
         wallet_name=config.WALLET_NAME,
         wallet_connect=config.WALLET_CONNECT,
         wallet_port=config.WALLET_PORT,
         wallet_user=config.WALLET_USER,
         wallet_password=config.WALLET_PASSWORD,
         wallet_ssl=config.WALLET_SSL,
         wallet_ssl_verify=config.WALLET_SSL_VERIFY,
         requests_timeout=config.REQUESTS_TIMEOUT)
     log.set_up(logger, verbose=config.VERBOSE, logfile=config.LOG_FILE)
def initialise_config(
        database_file=None,
        log_file=None,
        api_log_file=None,
        testnet=False,
        testcoin=False,
        backend_name=None,
        backend_connect=None,
        backend_port=None,
        backend_user=None,
        backend_password=None,
        backend_ssl=False,
        backend_ssl_no_verify=False,
        backend_poll_interval=None,
        rpc_host=None,
        rpc_port=None,
        rpc_user=None,
        rpc_password=None,
        rpc_no_allow_cors=False,
        force=False,
        verbose=False,
        console_logfilter=None,
        requests_timeout=config.DEFAULT_REQUESTS_TIMEOUT,
        rpc_batch_size=config.DEFAULT_RPC_BATCH_SIZE,
        check_asset_conservation=config.DEFAULT_CHECK_ASSET_CONSERVATION,
        backend_ssl_verify=None,
        rpc_allow_cors=None,
        p2sh_dust_return_pubkey=None,
        utxo_locks_max_addresses=config.DEFAULT_UTXO_LOCKS_MAX_ADDRESSES,
        utxo_locks_max_age=config.DEFAULT_UTXO_LOCKS_MAX_AGE,
        estimate_fee_per_kb=None):

    # Data directory
    data_dir = appdirs.user_data_dir(appauthor=config.XCP_NAME,
                                     appname=config.APP_NAME,
                                     roaming=True)
    if not os.path.isdir(data_dir):
        os.makedirs(data_dir, mode=0o755)

    # testnet
    if testnet:
        config.TESTNET = testnet
    else:
        config.TESTNET = False

    # testcoin
    if testcoin:
        config.TESTCOIN = testcoin
    else:
        config.TESTCOIN = False

    network = ''
    if config.TESTNET:
        network += '.testnet'
    if config.TESTCOIN:
        network += '.testcoin'

    # Database
    if database_file:
        config.DATABASE = database_file
    else:
        filename = '{}{}.db'.format(config.APP_NAME, network)
        config.DATABASE = os.path.join(data_dir, filename)

    # Log directory
    log_dir = appdirs.user_log_dir(appauthor=config.XCP_NAME,
                                   appname=config.APP_NAME)
    if not os.path.isdir(log_dir):
        os.makedirs(log_dir, mode=0o755)

    # Log
    if log_file is False:  # no file logging
        config.LOG = None
    elif not log_file:  # default location
        filename = 'server{}.log'.format(network)
        config.LOG = os.path.join(log_dir, filename)
    else:  # user-specified location
        config.LOG = log_file

    # Set up logging.
    log.set_up(log.ROOT_LOGGER,
               verbose=verbose,
               logfile=config.LOG,
               console_logfilter=console_logfilter)
    if config.LOG:
        logger.debug('Writing server log to file: `{}`'.format(config.LOG))

    if api_log_file is False:  # no file logging
        config.API_LOG = None
    elif not api_log_file:  # default location
        filename = 'server{}.access.log'.format(network)
        config.API_LOG = os.path.join(log_dir, filename)
    else:  # user-specified location
        config.API_LOG = api_log_file
    if config.API_LOG:
        logger.debug('Writing API accesses log to file: `{}`'.format(
            config.API_LOG))

    # Log unhandled errors.
    def handle_exception(exc_type, exc_value, exc_traceback):
        logger.error("Unhandled Exception",
                     exc_info=(exc_type, exc_value, exc_traceback))

    sys.excepthook = handle_exception

    ##############
    # THINGS WE CONNECT TO

    # Backend name
    if backend_name:
        config.BACKEND_NAME = backend_name
    else:
        config.BACKEND_NAME = 'addrindex'
    if config.BACKEND_NAME == 'jmcorgan':
        config.BACKEND_NAME = 'addrindex'

    # Backend RPC host (Bitcoin Core)
    if backend_connect:
        config.BACKEND_CONNECT = backend_connect
    else:
        config.BACKEND_CONNECT = 'localhost'

    # Backend Core RPC port (Bitcoin Core)
    if backend_port:
        config.BACKEND_PORT = backend_port
    else:
        if config.TESTNET:
            if config.BACKEND_NAME == 'btcd':
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_TESTNET_BTCD
            else:
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_TESTNET
        else:
            if config.BACKEND_NAME == 'btcd':
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_BTCD
            else:
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT

    try:
        config.BACKEND_PORT = int(config.BACKEND_PORT)
        if not (int(config.BACKEND_PORT) > 1
                and int(config.BACKEND_PORT) < 65535):
            raise ConfigurationError('invalid backend API port number')
    except:
        raise ConfigurationError(
            "Please specific a valid port number backend-port configuration parameter"
        )

    # Backend Core RPC user (Bitcoin Core)
    if backend_user:
        config.BACKEND_USER = backend_user
    else:
        config.BACKEND_USER = '******'

    # Backend Core RPC password (Bitcoin Core)
    if backend_password:
        config.BACKEND_PASSWORD = backend_password
    else:
        raise ConfigurationError(
            'backend RPC password not set. (Use configuration file or --backend-password=PASSWORD)'
        )

    # Backend Core RPC SSL
    if backend_ssl:
        config.BACKEND_SSL = backend_ssl
    else:
        config.BACKEND_SSL = False  # Default to off.

    # Backend Core RPC SSL Verify
    if backend_ssl_verify is not None:
        logger.warning(
            'The server parameter `backend_ssl_verify` is deprecated. Use `backend_ssl_no_verify` instead.'
        )
        config.BACKEND_SSL_NO_VERIFY = not backend_ssl_verify
    else:
        if backend_ssl_no_verify:
            config.BACKEND_SSL_NO_VERIFY = backend_ssl_no_verify
        else:
            config.BACKEND_SSL_NO_VERIFY = False  # Default to on (don't support self‐signed certificates)

    # Backend Poll Interval
    if backend_poll_interval:
        config.BACKEND_POLL_INTERVAL = backend_poll_interval
    else:
        config.BACKEND_POLL_INTERVAL = 0.5

    # Construct backend URL.
    config.BACKEND_URL = config.BACKEND_USER + ':' + config.BACKEND_PASSWORD + '@' + config.BACKEND_CONNECT + ':' + str(
        config.BACKEND_PORT)
    if config.BACKEND_SSL:
        config.BACKEND_URL = 'https://' + config.BACKEND_URL
    else:
        config.BACKEND_URL = 'http://' + config.BACKEND_URL

    ##############
    # THINGS WE SERVE

    # Server API RPC host
    if rpc_host:
        config.RPC_HOST = rpc_host
    else:
        config.RPC_HOST = 'localhost'

    # The web root directory for API calls, eg. localhost:14000/rpc/
    config.RPC_WEBROOT = '/rpc/'

    # Server API RPC port
    if rpc_port:
        config.RPC_PORT = rpc_port
    else:
        if config.TESTNET:
            if config.TESTCOIN:
                config.RPC_PORT = config.DEFAULT_RPC_PORT_TESTNET + 1
            else:
                config.RPC_PORT = config.DEFAULT_RPC_PORT_TESTNET
        else:
            if config.TESTCOIN:
                config.RPC_PORT = config.DEFAULT_RPC_PORT + 1
            else:
                config.RPC_PORT = config.DEFAULT_RPC_PORT
    try:
        config.RPC_PORT = int(config.RPC_PORT)
        if not (int(config.RPC_PORT) > 1 and int(config.RPC_PORT) < 65535):
            raise ConfigurationError('invalid server API port number')
    except:
        raise ConfigurationError(
            "Please specific a valid port number rpc-port configuration parameter"
        )

    # Server API RPC user
    if rpc_user:
        config.RPC_USER = rpc_user
    else:
        config.RPC_USER = '******'

    # Server API RPC password
    if rpc_password:
        config.RPC_PASSWORD = rpc_password
        config.RPC = 'http://' + urlencode(config.RPC_USER) + ':' + urlencode(
            config.RPC_PASSWORD) + '@' + config.RPC_HOST + ':' + str(
                config.RPC_PORT) + config.RPC_WEBROOT
    else:
        config.RPC = 'http://' + config.RPC_HOST + ':' + str(
            config.RPC_PORT) + config.RPC_WEBROOT

    # RPC CORS
    if rpc_allow_cors is not None:
        logger.warning(
            'The server parameter `rpc_allow_cors` is deprecated. Use `rpc_no_allow_cors` instead.'
        )
        config.RPC_NO_ALLOW_CORS = not rpc_allow_cors
    else:
        if rpc_no_allow_cors:
            config.RPC_NO_ALLOW_CORS = rpc_no_allow_cors
        else:
            config.RPC_NO_ALLOW_CORS = False

    config.RPC_BATCH_SIZE = rpc_batch_size

    ##############
    # OTHER SETTINGS

    # skip checks
    if force:
        config.FORCE = force
    else:
        config.FORCE = False

    # Encoding
    if config.TESTCOIN:
        config.PREFIX = b'XX'  # 2 bytes (possibly accidentally created)
    else:
        config.PREFIX = b'CNTRPRTY'  # 8 bytes

    # (more) Testnet
    if config.TESTNET:
        config.MAGIC_BYTES = config.MAGIC_BYTES_TESTNET
        if config.TESTCOIN:
            config.ADDRESSVERSION = config.ADDRESSVERSION_TESTNET
            config.P2SH_ADDRESSVERSION = config.P2SH_ADDRESSVERSION_TESTNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_TESTNET_TESTCOIN
            config.BURN_START = config.BURN_START_TESTNET_TESTCOIN
            config.BURN_END = config.BURN_END_TESTNET_TESTCOIN
            config.UNSPENDABLE = config.UNSPENDABLE_TESTNET
            config.P2SH_DUST_RETURN_PUBKEY = p2sh_dust_return_pubkey
        else:
            config.ADDRESSVERSION = config.ADDRESSVERSION_TESTNET
            config.P2SH_ADDRESSVERSION = config.P2SH_ADDRESSVERSION_TESTNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_TESTNET
            config.BURN_START = config.BURN_START_TESTNET
            config.BURN_END = config.BURN_END_TESTNET
            config.UNSPENDABLE = config.UNSPENDABLE_TESTNET
            config.P2SH_DUST_RETURN_PUBKEY = p2sh_dust_return_pubkey
    else:
        config.MAGIC_BYTES = config.MAGIC_BYTES_MAINNET
        if config.TESTCOIN:
            config.ADDRESSVERSION = config.ADDRESSVERSION_MAINNET
            config.P2SH_ADDRESSVERSION = config.P2SH_ADDRESSVERSION_MAINNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_MAINNET_TESTCOIN
            config.BURN_START = config.BURN_START_MAINNET_TESTCOIN
            config.BURN_END = config.BURN_END_MAINNET_TESTCOIN
            config.UNSPENDABLE = config.UNSPENDABLE_MAINNET
            config.P2SH_DUST_RETURN_PUBKEY = p2sh_dust_return_pubkey
        else:
            config.ADDRESSVERSION = config.ADDRESSVERSION_MAINNET
            config.P2SH_ADDRESSVERSION = config.P2SH_ADDRESSVERSION_MAINNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_MAINNET
            config.BURN_START = config.BURN_START_MAINNET
            config.BURN_END = config.BURN_END_MAINNET
            config.UNSPENDABLE = config.UNSPENDABLE_MAINNET
            config.P2SH_DUST_RETURN_PUBKEY = p2sh_dust_return_pubkey

    # Misc
    config.REQUESTS_TIMEOUT = requests_timeout
    config.CHECK_ASSET_CONSERVATION = check_asset_conservation
    config.UTXO_LOCKS_MAX_ADDRESSES = utxo_locks_max_addresses
    config.UTXO_LOCKS_MAX_AGE = utxo_locks_max_age
    transaction.UTXO_LOCKS = None  # reset the UTXO_LOCKS (for tests really)

    if estimate_fee_per_kb is not None:
        config.ESTIMATE_FEE_PER_KB = estimate_fee_per_kb

    logger.info('Running v{} of counterparty-lib.'.format(
        config.VERSION_STRING))
Example #3
0
def main():
    if os.name == 'nt':
        from counterpartylib.lib import util_windows
        #patch up cmd.exe's "challenged" (i.e. broken/non-existent) UTF-8 logging
        util_windows.fix_win32_unicode()

    # Post installation tasks
    generate_config_files()

    # Parse command-line arguments.
    parser = argparse.ArgumentParser(
        prog=APP_NAME,
        description='Counterparty CLI for counterparty-server',
        add_help=False)
    parser.add_argument('-h',
                        '--help',
                        dest='help',
                        action='store_true',
                        help='show this help message and exit')
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version="{} v{}; {} v{}".format(
                            APP_NAME, APP_VERSION, 'counterparty-lib',
                            config.VERSION_STRING))
    parser.add_argument('--config-file',
                        help='the location of the configuration file')

    parser = add_config_arguments(parser, CONFIG_ARGS, 'client.conf')

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

    parser_send = subparsers.add_parser(
        'send', help='create and broadcast a *send* message')
    parser_send.add_argument('--source',
                             required=True,
                             help='the source address')
    parser_send.add_argument('--destination',
                             required=True,
                             help='the destination address')
    parser_send.add_argument('--quantity',
                             required=True,
                             help='the quantity of ASSET to send')
    parser_send.add_argument(
        '--asset',
        required=True,
        help='the ASSET of which you would like to send QUANTITY')
    parser_send.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_order = subparsers.add_parser(
        'order', help='create and broadcast an *order* message')
    parser_order.add_argument('--source',
                              required=True,
                              help='the source address')
    parser_order.add_argument(
        '--get-quantity',
        required=True,
        help='the quantity of GET_ASSET that you would like to receive')
    parser_order.add_argument('--get-asset',
                              required=True,
                              help='the asset that you would like to buy')
    parser_order.add_argument(
        '--give-quantity',
        required=True,
        help='the quantity of GIVE_ASSET that you are willing to give')
    parser_order.add_argument('--give-asset',
                              required=True,
                              help='the asset that you would like to sell')
    parser_order.add_argument(
        '--expiration',
        type=int,
        required=True,
        help='the number of blocks for which the order should be valid')
    parser_order.add_argument(
        '--fee-fraction-required',
        default=config.DEFAULT_FEE_FRACTION_REQUIRED,
        help=
        'the miners’ fee required for an order to match this one, as a fraction of the {} to be bought'
        .format(config.BTC))
    parser_order_fees = parser_order.add_mutually_exclusive_group()
    parser_order_fees.add_argument(
        '--fee-fraction-provided',
        default=config.DEFAULT_FEE_FRACTION_PROVIDED,
        help='the miners’ fee provided, as a fraction of the {} to be sold'.
        format(config.BTC))
    parser_order_fees.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_btcpay = subparsers.add_parser(
        '{}pay'.format(config.BTC).lower(),
        help=
        'create and broadcast a *{}pay* message, to settle an Order Match for which you owe {}'
        .format(config.BTC, config.BTC))
    parser_btcpay.add_argument('--source',
                               required=True,
                               help='the source address')
    parser_btcpay.add_argument(
        '--order-match-id',
        required=True,
        help=
        'the concatenation of the hashes of the two transactions which compose the order match'
    )
    parser_btcpay.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_issuance = subparsers.add_parser(
        'issuance',
        help=
        'issue a new asset, issue more of an existing asset or transfer the ownership of an asset'
    )
    parser_issuance.add_argument('--source',
                                 required=True,
                                 help='the source address')
    parser_issuance.add_argument(
        '--transfer-destination',
        help='for transfer of ownership of asset issuance rights')
    parser_issuance.add_argument('--quantity',
                                 default=0,
                                 help='the quantity of ASSET to be issued')
    parser_issuance.add_argument(
        '--asset',
        required=True,
        help='the name of the asset to be issued (if it’s available)')
    parser_issuance.add_argument(
        '--divisible',
        action='store_true',
        help=
        'whether or not the asset is divisible (must agree with previous issuances)'
    )
    parser_issuance.add_argument(
        '--description',
        type=str,
        required=True,
        help=
        'a description of the asset (set to ‘LOCK’ to lock against further issuances with non‐zero quantitys)'
    )
    parser_issuance.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_broadcast = subparsers.add_parser(
        'broadcast',
        help='broadcast textual and numerical information to the network')
    parser_broadcast.add_argument('--source',
                                  required=True,
                                  help='the source address')
    parser_broadcast.add_argument(
        '--text',
        type=str,
        required=True,
        help='the textual part of the broadcast (set to ‘LOCK’ to lock feed)')
    parser_broadcast.add_argument('--value',
                                  type=float,
                                  default=-1,
                                  help='numerical value of the broadcast')
    parser_broadcast.add_argument(
        '--fee-fraction',
        default=0,
        help='the fraction of bets on this feed that go to its operator')
    parser_broadcast.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_bet = subparsers.add_parser(
        'bet', help='offer to make a bet on the value of a feed')
    parser_bet.add_argument('--source',
                            required=True,
                            help='the source address')
    parser_bet.add_argument(
        '--feed-address',
        required=True,
        help='the address which publishes the feed to bet on')
    parser_bet.add_argument('--bet-type',
                            choices=list(BET_TYPE_NAME.values()),
                            required=True,
                            help='choices: {}'.format(
                                list(BET_TYPE_NAME.values())))
    parser_bet.add_argument(
        '--deadline',
        required=True,
        help='the date and time at which the bet should be decided/settled')
    parser_bet.add_argument('--wager',
                            required=True,
                            help='the quantity of XCP to wager')
    parser_bet.add_argument(
        '--counterwager',
        required=True,
        help=
        'the minimum quantity of XCP to be wagered by the user to bet against you, if he were to accept the whole thing'
    )
    parser_bet.add_argument('--target-value',
                            default=0.0,
                            help='target value for Equal/NotEqual bet')
    parser_bet.add_argument('--leverage',
                            type=int,
                            default=5040,
                            help='leverage, as a fraction of 5040')
    parser_bet.add_argument(
        '--expiration',
        type=int,
        required=True,
        help='the number of blocks for which the bet should be valid')
    parser_bet.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_dividend = subparsers.add_parser(
        'dividend',
        help=
        'pay dividends to the holders of an asset (in proportion to their stake in it)'
    )
    parser_dividend.add_argument('--source',
                                 required=True,
                                 help='the source address')
    parser_dividend.add_argument(
        '--quantity-per-unit',
        required=True,
        help='the quantity of XCP to be paid per whole unit held of ASSET')
    parser_dividend.add_argument('--asset',
                                 required=True,
                                 help='the asset to which pay dividends')
    parser_dividend.add_argument('--dividend-asset',
                                 required=True,
                                 help='asset in which to pay the dividends')
    parser_dividend.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_burn = subparsers.add_parser(
        'burn',
        help='destroy {} to earn XCP, during an initial period of time')
    parser_burn.add_argument('--source',
                             required=True,
                             help='the source address')
    parser_burn.add_argument('--quantity',
                             required=True,
                             help='quantity of {} to be burned'.format(
                                 config.BTC))
    parser_burn.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_cancel = subparsers.add_parser(
        'cancel', help='cancel an open order or bet you created')
    parser_cancel.add_argument('--source',
                               required=True,
                               help='the source address')
    parser_cancel.add_argument('--offer-hash',
                               required=True,
                               help='the transaction hash of the order or bet')
    parser_cancel.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_rps = subparsers.add_parser(
        'rps', help='open a rock-paper-scissors like game')
    parser_rps.add_argument('--source',
                            required=True,
                            help='the source address')
    parser_rps.add_argument('--wager',
                            required=True,
                            help='the quantity of XCP to wager')
    parser_rps.add_argument('--move',
                            type=int,
                            required=True,
                            help='the selected move')
    parser_rps.add_argument(
        '--possible-moves',
        type=int,
        required=True,
        help='the number of possible moves (odd number greater or equal than 3)'
    )
    parser_rps.add_argument(
        '--expiration',
        type=int,
        required=True,
        help='the number of blocks for which the bet should be valid')
    parser_rps.add_argument('--fee',
                            help='the exact BTC fee to be paid to miners')

    parser_rpsresolve = subparsers.add_parser(
        'rpsresolve', help='resolve a rock-paper-scissors like game')
    parser_rpsresolve.add_argument('--source',
                                   required=True,
                                   help='the source address')
    parser_rpsresolve.add_argument(
        '--random',
        type=str,
        required=True,
        help='the random number used in the corresponding rps transaction')
    parser_rpsresolve.add_argument(
        '--move',
        type=int,
        required=True,
        help='the selected move in the corresponding rps transaction')
    parser_rpsresolve.add_argument(
        '--rps-match-id',
        required=True,
        help=
        'the concatenation of the hashes of the two transactions which compose the rps match'
    )
    parser_rpsresolve.add_argument(
        '--fee', help='the exact BTC fee to be paid to miners')

    parser_publish = subparsers.add_parser(
        'publish', help='publish contract code in the blockchain')
    parser_publish.add_argument('--source',
                                required=True,
                                help='the source address')
    parser_publish.add_argument('--gasprice',
                                required=True,
                                type=int,
                                help='the price of gas')
    parser_publish.add_argument(
        '--startgas',
        required=True,
        type=int,
        help=
        'the maximum quantity of {} to be used to pay for the execution (satoshis)'
        .format(config.XCP))
    parser_publish.add_argument(
        '--endowment',
        required=True,
        type=int,
        help='quantity of {} to be transfered to the contract (satoshis)'.
        format(config.XCP))
    parser_publish.add_argument(
        '--code-hex',
        required=True,
        type=str,
        help='the hex‐encoded contract (returned by `serpent compile`)')
    parser_publish.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_execute = subparsers.add_parser(
        'execute', help='execute contract code in the blockchain')
    parser_execute.add_argument('--source',
                                required=True,
                                help='the source address')
    parser_execute.add_argument(
        '--contract-id',
        required=True,
        help='the contract ID of the contract to be executed')
    parser_execute.add_argument('--gasprice',
                                required=True,
                                type=int,
                                help='the price of gas')
    parser_execute.add_argument(
        '--startgas',
        required=True,
        type=int,
        help=
        'the maximum quantity of {} to be used to pay for the execution (satoshis)'
        .format(config.XCP))
    parser_execute.add_argument(
        '--value',
        required=True,
        type=int,
        help='quantity of {} to be transfered to the contract (satoshis)'.
        format(config.XCP))
    parser_execute.add_argument(
        '--payload-hex',
        required=True,
        type=str,
        help=
        'data to be provided to the contract (returned by `serpent encode_datalist`)'
    )
    parser_execute.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_destroy = subparsers.add_parser(
        'destroy', help='destroy a quantity of a Counterparty asset')
    parser_destroy.add_argument('--source',
                                required=True,
                                help='the source address')
    parser_destroy.add_argument(
        '--asset',
        required=True,
        help='the ASSET of which you would like to destroy QUANTITY')
    parser_destroy.add_argument('--quantity',
                                required=True,
                                help='the quantity of ASSET to destroy')
    parser_destroy.add_argument('--tag', default='', help='tag')
    parser_destroy.add_argument(
        '--fee',
        help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_address = subparsers.add_parser(
        'balances',
        help='display the balances of a {} address'.format(config.XCP_NAME))
    parser_address.add_argument('address',
                                help='the address you are interested in')

    parser_asset = subparsers.add_parser(
        'asset',
        help='display the basic properties of a {} asset'.format(
            config.XCP_NAME))
    parser_asset.add_argument('asset', help='the asset you are interested in')

    parser_wallet = subparsers.add_parser(
        'wallet',
        help=
        'list the addresses in your backend wallet along with their balances in all {} assets'
        .format(config.XCP_NAME))

    parser_pending = subparsers.add_parser(
        'pending',
        help='list pending order matches awaiting {}payment from you'.format(
            config.BTC))

    parser_getrows = subparsers.add_parser(
        'getrows', help='get rows from a Counterparty table')
    parser_getrows.add_argument('--table', required=True, help='table name')
    parser_getrows.add_argument('--filter',
                                nargs=3,
                                action='append',
                                help='filters to get specific rows')
    parser_getrows.add_argument('--filter-op',
                                choices=['AND', 'OR'],
                                help='operator uses to combine filters',
                                default='AND')
    parser_getrows.add_argument('--order-by',
                                help='field used to order results')
    parser_getrows.add_argument('--order-dir',
                                choices=['ASC', 'DESC'],
                                help='direction used to order results')
    parser_getrows.add_argument(
        '--start-block',
        help='return only rows with block_index greater than start-block')
    parser_getrows.add_argument(
        '--end-block',
        help='return only rows with block_index lower than end-block')
    parser_getrows.add_argument(
        '--status', help='return only rows with the specified status')
    parser_getrows.add_argument('--limit',
                                help='number of rows to return',
                                default=100)
    parser_getrows.add_argument('--offset',
                                help='number of rows to skip',
                                default=0)

    parser_getrunninginfo = subparsers.add_parser(
        'getinfo', help='get the current state of the server')

    args = parser.parse_args()

    # Logging
    log.set_up(logger, verbose=args.verbose)
    logger.propagate = False

    logger.info('Running v{} of {}.'.format(APP_VERSION, APP_NAME))

    # Help message
    if args.help:
        parser.print_help()
        sys.exit()

    # Configuration
    clientapi.initialize(
        testnet=args.testnet,
        testcoin=args.testcoin,
        counterparty_rpc_connect=args.counterparty_rpc_connect,
        counterparty_rpc_port=args.counterparty_rpc_port,
        counterparty_rpc_user=args.counterparty_rpc_user,
        counterparty_rpc_password=args.counterparty_rpc_password,
        counterparty_rpc_ssl=args.counterparty_rpc_ssl,
        counterparty_rpc_ssl_verify=args.counterparty_rpc_ssl_verify,
        wallet_name=args.wallet_name,
        wallet_connect=args.wallet_connect,
        wallet_port=args.wallet_port,
        wallet_user=args.wallet_user,
        wallet_password=args.wallet_password,
        wallet_ssl=args.wallet_ssl,
        wallet_ssl_verify=args.wallet_ssl_verify,
        requests_timeout=args.requests_timeout)

    # MESSAGE CREATION
    if args.action in list(messages.MESSAGE_PARAMS.keys()):
        unsigned_hex = messages.compose(args.action, args)
        logger.info('Transaction (unsigned): {}'.format(unsigned_hex))
        if not args.unsigned:
            if script.is_multisig(args.source):
                logger.info(
                    'Multi‐signature transactions are signed and broadcasted manually.'
                )

            elif input('Sign and broadcast? (y/N) ') == 'y':

                if wallet.is_mine(args.source):
                    if wallet.is_locked():
                        passphrase = getpass.getpass(
                            'Enter your wallet passhrase: ')
                        logger.info('Unlocking wallet for 60 (more) seconds.')
                        wallet.unlock(passphrase)
                    signed_tx_hex = wallet.sign_raw_transaction(unsigned_hex)
                else:
                    private_key_wif = input(
                        'Source address not in wallet. Please enter the private key in WIF format for {}:'
                        .format(args.source))
                    if not private_key_wif:
                        raise TransactionError('invalid private key')
                    signed_tx_hex = wallet.sign_raw_transaction(
                        unsigned_hex, private_key_wif=private_key_wif)

                logger.info('Transaction (signed): {}'.format(signed_tx_hex))
                tx_hash = wallet.send_raw_transaction(signed_tx_hex)
                logger.info(
                    'Hash of transaction (broadcasted): {}'.format(tx_hash))

    # VIEWING
    elif args.action in [
            'balances', 'asset', 'wallet', 'pending', 'getinfo', 'getrows'
    ]:
        view = console.get_view(args.action, args)
        print_method = getattr(console, 'print_{}'.format(args.action), None)
        if args.json_output or print_method is None:
            util.json_print(view)
        else:
            print_method(view)

    else:
        parser.print_help()
def main():
    if os.name == 'nt':
        from counterpartylib.lib import util_windows
        #patch up cmd.exe's "challenged" (i.e. broken/non-existent) UTF-8 logging
        util_windows.fix_win32_unicode()

    # Post installation tasks
    generate_config_files()

    # Parse command-line arguments.
    parser = argparse.ArgumentParser(prog=APP_NAME, description='Server for the {} protocol'.format(config.XCP_NAME), add_help=False)
    parser.add_argument('-h', '--help', dest='help', action='store_true', help='show this help message and exit')
    parser.add_argument('-V', '--version', action='version', version="{} v{}; {} v{}".format(APP_NAME, APP_VERSION, 'counterparty-lib', config.VERSION_STRING))
    parser.add_argument('--config-file', help='the path to the configuration file')

    parser = add_config_arguments(parser, CONFIG_ARGS, 'server.conf')

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

    parser_server = subparsers.add_parser('start', help='run the server')

    parser_reparse = subparsers.add_parser('reparse', help='reparse all transactions in the database')
   
    parser_rollback = subparsers.add_parser('rollback', help='rollback database')
    parser_rollback.add_argument('block_index', type=int, help='the index of the last known good block')
    
    parser_kickstart = subparsers.add_parser('kickstart', help='rapidly build database by reading from Bitcoin Core blockchain')
    parser_kickstart.add_argument('--bitcoind-dir', help='Bitcoin Core data directory')

    parser_bootstrap = subparsers.add_parser('bootstrap', help='bootstrap database with hosted snapshot')

    args = parser.parse_args()

    log.set_up(logger, verbose=args.verbose)
    
    logger.info('Running v{} of {}.'.format(APP_VERSION, APP_NAME))

    # Help message
    if args.help:
        parser.print_help()
        sys.exit()

    # Bootstrapping
    if args.action == 'bootstrap':
        bootstrap(testnet=args.testnet)
        sys.exit()

    # Configuration
    if args.action in ['reparse', 'rollback', 'kickstart', 'start']:
        try:
            db = server.initialise(database_file=args.database_file,
                                log_file=args.log_file, api_log_file=args.api_log_file,
                                testnet=args.testnet, testcoin=args.testcoin,
                                backend_name=args.backend_name,
                                backend_connect=args.backend_connect,
                                backend_port=args.backend_port,
                                backend_user=args.backend_user,
                                backend_password=args.backend_password,
                                backend_ssl=args.backend_ssl,
                                backend_ssl_no_verify=args.backend_ssl_no_verify,
                                backend_poll_interval=args.backend_poll_interval,
                                rpc_host=args.rpc_host, rpc_port=args.rpc_port, rpc_user=args.rpc_user,
                                rpc_password=args.rpc_password, rpc_no_allow_cors=args.rpc_no_allow_cors,
                                requests_timeout=args.requests_timeout,
                                rpc_batch_size=args.rpc_batch_size,
                                check_asset_conservation=not args.no_check_asset_conservation,
                                force=args.force, verbose=args.verbose)
                                #,broadcast_tx_mainnet=args.broadcast_tx_mainnet)
        except TypeError as e:
            if 'unexpected keyword argument' in str(e):
                raise VersionError('Unsupported Server Parameter. CLI/Library Version Incompatibility.')
            else:
                raise e

    # PARSING
    if args.action == 'reparse':
        server.reparse(db)

    elif args.action == 'rollback':
        server.reparse(db, block_index=args.block_index)

    elif args.action == 'kickstart':
        server.kickstart(db, bitcoind_dir=args.bitcoind_dir)

    elif args.action == 'start':
        server.start_all(db)

    else:
        parser.print_help()
Example #5
0
def main():
    if os.name == 'nt':
        from counterpartylib.lib import util_windows
        #patch up cmd.exe's "challenged" (i.e. broken/non-existent) UTF-8 logging
        util_windows.fix_win32_unicode()

    # Post installation tasks
    generate_config_files()

    # Parse command-line arguments.
    parser = argparse.ArgumentParser(prog=APP_NAME, description='Counterparty CLI for counterparty-server', add_help=False)
    parser.add_argument('-h', '--help', dest='help', action='store_true', help='show this help message and exit')
    parser.add_argument('-V', '--version', action='version', version="{} v{}; {} v{}".format(APP_NAME, APP_VERSION, 'counterparty-lib', config.VERSION_STRING))
    parser.add_argument('--config-file', help='the location of the configuration file')

    parser = add_config_arguments(parser, CONFIG_ARGS, 'client.conf')

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

    parser_send = subparsers.add_parser('send', help='create and broadcast a *send* message')
    parser_send.add_argument('--source', required=True, help='the source address')
    parser_send.add_argument('--destination', required=True, help='the destination address')
    parser_send.add_argument('--quantity', required=True, help='the quantity of ASSET to send')
    parser_send.add_argument('--asset', required=True, help='the ASSET of which you would like to send QUANTITY')
    parser_send.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_order = subparsers.add_parser('order', help='create and broadcast an *order* message')
    parser_order.add_argument('--source', required=True, help='the source address')
    parser_order.add_argument('--get-quantity', required=True, help='the quantity of GET_ASSET that you would like to receive')
    parser_order.add_argument('--get-asset', required=True, help='the asset that you would like to buy')
    parser_order.add_argument('--give-quantity', required=True, help='the quantity of GIVE_ASSET that you are willing to give')
    parser_order.add_argument('--give-asset', required=True, help='the asset that you would like to sell')
    parser_order.add_argument('--expiration', type=int, required=True, help='the number of blocks for which the order should be valid')
    parser_order.add_argument('--fee-fraction-required', default=config.DEFAULT_FEE_FRACTION_REQUIRED, help='the miners’ fee required for an order to match this one, as a fraction of the {} to be bought'.format(config.BTC))
    parser_order_fees = parser_order.add_mutually_exclusive_group()
    parser_order_fees.add_argument('--fee-fraction-provided', default=config.DEFAULT_FEE_FRACTION_PROVIDED, help='the miners’ fee provided, as a fraction of the {} to be sold'.format(config.BTC))
    parser_order_fees.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_btcpay = subparsers.add_parser('{}pay'.format(config.BTC).lower(), help='create and broadcast a *{}pay* message, to settle an Order Match for which you owe {}'.format(config.BTC, config.BTC))
    parser_btcpay.add_argument('--source', required=True, help='the source address')
    parser_btcpay.add_argument('--order-match-id', required=True, help='the concatenation of the hashes of the two transactions which compose the order match')
    parser_btcpay.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_issuance = subparsers.add_parser('issuance', help='issue a new asset, issue more of an existing asset or transfer the ownership of an asset')
    parser_issuance.add_argument('--source', required=True, help='the source address')
    parser_issuance.add_argument('--transfer-destination', help='for transfer of ownership of asset issuance rights')
    parser_issuance.add_argument('--quantity', default=0, help='the quantity of ASSET to be issued')
    parser_issuance.add_argument('--asset', required=True, help='the name of the asset to be issued (if it’s available)')
    parser_issuance.add_argument('--divisible', action='store_true', help='whether or not the asset is divisible (must agree with previous issuances)')
    parser_issuance.add_argument('--description', type=str, required=True, help='a description of the asset (set to ‘LOCK’ to lock against further issuances with non‐zero quantitys)')
    parser_issuance.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_broadcast = subparsers.add_parser('broadcast', help='broadcast textual and numerical information to the network')
    parser_broadcast.add_argument('--source', required=True, help='the source address')
    parser_broadcast.add_argument('--text', type=str, required=True, help='the textual part of the broadcast (set to ‘LOCK’ to lock feed)')
    parser_broadcast.add_argument('--value', type=float, default=-1, help='numerical value of the broadcast')
    parser_broadcast.add_argument('--fee-fraction', default=0, help='the fraction of bets on this feed that go to its operator')
    parser_broadcast.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_bet = subparsers.add_parser('bet', help='offer to make a bet on the value of a feed')
    parser_bet.add_argument('--source', required=True, help='the source address')
    parser_bet.add_argument('--feed-address', required=True, help='the address which publishes the feed to bet on')
    parser_bet.add_argument('--bet-type', choices=list(BET_TYPE_NAME.values()), required=True, help='choices: {}'.format(list(BET_TYPE_NAME.values())))
    parser_bet.add_argument('--deadline', required=True, help='the date and time at which the bet should be decided/settled')
    parser_bet.add_argument('--wager', required=True, help='the quantity of XCP to wager')
    parser_bet.add_argument('--counterwager', required=True, help='the minimum quantity of XCP to be wagered by the user to bet against you, if he were to accept the whole thing')
    parser_bet.add_argument('--target-value', default=0.0, help='target value for Equal/NotEqual bet')
    parser_bet.add_argument('--leverage', type=int, default=5040, help='leverage, as a fraction of 5040')
    parser_bet.add_argument('--expiration', type=int, required=True, help='the number of blocks for which the bet should be valid')
    parser_bet.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_dividend = subparsers.add_parser('dividend', help='pay dividends to the holders of an asset (in proportion to their stake in it)')
    parser_dividend.add_argument('--source', required=True, help='the source address')
    parser_dividend.add_argument('--quantity-per-unit', required=True, help='the quantity of XCP to be paid per whole unit held of ASSET')
    parser_dividend.add_argument('--asset', required=True, help='the asset to which pay dividends')
    parser_dividend.add_argument('--dividend-asset', required=True, help='asset in which to pay the dividends')
    parser_dividend.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_burn = subparsers.add_parser('burn', help='destroy {} to earn XCP, during an initial period of time')
    parser_burn.add_argument('--source', required=True, help='the source address')
    parser_burn.add_argument('--quantity', required=True, help='quantity of {} to be burned'.format(config.BTC))
    parser_burn.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_cancel = subparsers.add_parser('cancel', help='cancel an open order or bet you created')
    parser_cancel.add_argument('--source', required=True, help='the source address')
    parser_cancel.add_argument('--offer-hash', required=True, help='the transaction hash of the order or bet')
    parser_cancel.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_rps = subparsers.add_parser('rps', help='open a rock-paper-scissors like game')
    parser_rps.add_argument('--source', required=True, help='the source address')
    parser_rps.add_argument('--wager', required=True, help='the quantity of XCP to wager')
    parser_rps.add_argument('--move', type=int, required=True, help='the selected move')
    parser_rps.add_argument('--possible-moves', type=int, required=True, help='the number of possible moves (odd number greater or equal than 3)')
    parser_rps.add_argument('--expiration', type=int, required=True, help='the number of blocks for which the bet should be valid')
    parser_rps.add_argument('--fee', help='the exact BTC fee to be paid to miners')

    parser_rpsresolve = subparsers.add_parser('rpsresolve', help='resolve a rock-paper-scissors like game')
    parser_rpsresolve.add_argument('--source', required=True, help='the source address')
    parser_rpsresolve.add_argument('--random', type=str, required=True, help='the random number used in the corresponding rps transaction')
    parser_rpsresolve.add_argument('--move', type=int, required=True, help='the selected move in the corresponding rps transaction')
    parser_rpsresolve.add_argument('--rps-match-id', required=True, help='the concatenation of the hashes of the two transactions which compose the rps match')
    parser_rpsresolve.add_argument('--fee', help='the exact BTC fee to be paid to miners')

    parser_publish = subparsers.add_parser('publish', help='publish contract code in the blockchain')
    parser_publish.add_argument('--source', required=True, help='the source address')
    parser_publish.add_argument('--gasprice', required=True, type=int, help='the price of gas')
    parser_publish.add_argument('--startgas', required=True, type=int, help='the maximum quantity of {} to be used to pay for the execution (satoshis)'.format(config.XCP))
    parser_publish.add_argument('--endowment', required=True, type=int, help='quantity of {} to be transfered to the contract (satoshis)'.format(config.XCP))
    parser_publish.add_argument('--code-hex', required=True, type=str, help='the hex‐encoded contract (returned by `serpent compile`)')
    parser_publish.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_execute = subparsers.add_parser('execute', help='execute contract code in the blockchain')
    parser_execute.add_argument('--source', required=True, help='the source address')
    parser_execute.add_argument('--contract-id', required=True, help='the contract ID of the contract to be executed')
    parser_execute.add_argument('--gasprice', required=True, type=int, help='the price of gas')
    parser_execute.add_argument('--startgas', required=True, type=int, help='the maximum quantity of {} to be used to pay for the execution (satoshis)'.format(config.XCP))
    parser_execute.add_argument('--value', required=True, type=int, help='quantity of {} to be transfered to the contract (satoshis)'.format(config.XCP))
    parser_execute.add_argument('--payload-hex', required=True, type=str, help='data to be provided to the contract (returned by `serpent encode_datalist`)')
    parser_execute.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_destroy = subparsers.add_parser('destroy', help='destroy a quantity of a Counterparty asset')
    parser_destroy.add_argument('--source', required=True, help='the source address')
    parser_destroy.add_argument('--asset', required=True, help='the ASSET of which you would like to destroy QUANTITY')
    parser_destroy.add_argument('--quantity', required=True, help='the quantity of ASSET to destroy')
    parser_destroy.add_argument('--tag', default='', help='tag')
    parser_destroy.add_argument('--fee', help='the exact {} fee to be paid to miners'.format(config.BTC))

    parser_address = subparsers.add_parser('balances', help='display the balances of a {} address'.format(config.XCP_NAME))
    parser_address.add_argument('address', help='the address you are interested in')

    parser_asset = subparsers.add_parser('asset', help='display the basic properties of a {} asset'.format(config.XCP_NAME))
    parser_asset.add_argument('asset', help='the asset you are interested in')

    parser_wallet = subparsers.add_parser('wallet', help='list the addresses in your backend wallet along with their balances in all {} assets'.format(config.XCP_NAME))

    parser_pending = subparsers.add_parser('pending', help='list pending order matches awaiting {}payment from you'.format(config.BTC))

    parser_getrows = subparsers.add_parser('getrows', help='get rows from a Counterparty table')
    parser_getrows.add_argument('--table', required=True, help='table name')
    parser_getrows.add_argument('--filter', nargs=3, action='append', help='filters to get specific rows')
    parser_getrows.add_argument('--filter-op', choices=['AND', 'OR'], help='operator uses to combine filters', default='AND')
    parser_getrows.add_argument('--order-by', help='field used to order results')
    parser_getrows.add_argument('--order-dir', choices=['ASC', 'DESC'], help='direction used to order results')
    parser_getrows.add_argument('--start-block', help='return only rows with block_index greater than start-block')
    parser_getrows.add_argument('--end-block', help='return only rows with block_index lower than end-block')
    parser_getrows.add_argument('--status', help='return only rows with the specified status')
    parser_getrows.add_argument('--limit', help='number of rows to return', default=100)
    parser_getrows.add_argument('--offset', help='number of rows to skip', default=0)

    parser_getrunninginfo = subparsers.add_parser('getinfo', help='get the current state of the server')

    args = parser.parse_args()

    # Logging
    log.set_up(logger, verbose=args.verbose)
    logger.propagate = False

    logger.info('Running v{} of {}.'.format(APP_VERSION, APP_NAME))

    # Help message
    if args.help:
        parser.print_help()
        sys.exit()

    # Configuration
    clientapi.initialize(testnet=args.testnet, testcoin=args.testcoin,
                        counterparty_rpc_connect=args.counterparty_rpc_connect, counterparty_rpc_port=args.counterparty_rpc_port,
                        counterparty_rpc_user=args.counterparty_rpc_user, counterparty_rpc_password=args.counterparty_rpc_password,
                        counterparty_rpc_ssl=args.counterparty_rpc_ssl, counterparty_rpc_ssl_verify=args.counterparty_rpc_ssl_verify,
                        wallet_name=args.wallet_name, wallet_connect=args.wallet_connect, wallet_port=args.wallet_port, 
                        wallet_user=args.wallet_user, wallet_password=args.wallet_password,
                        wallet_ssl=args.wallet_ssl, wallet_ssl_verify=args.wallet_ssl_verify,
                        requests_timeout=args.requests_timeout)

    # MESSAGE CREATION
    if args.action in list(messages.MESSAGE_PARAMS.keys()):
        unsigned_hex = messages.compose(args.action, args)
        logger.info('Transaction (unsigned): {}'.format(unsigned_hex))
        if not args.unsigned:
            if script.is_multisig(args.source):
                logger.info('Multi‐signature transactions are signed and broadcasted manually.')
            
            elif input('Sign and broadcast? (y/N) ') == 'y':

                if wallet.is_mine(args.source):
                    if wallet.is_locked():
                        passphrase = getpass.getpass('Enter your wallet passhrase: ')
                        logger.info('Unlocking wallet for 60 (more) seconds.')
                        wallet.unlock(passphrase)
                    signed_tx_hex = wallet.sign_raw_transaction(unsigned_hex)
                else:
                    private_key_wif = input('Source address not in wallet. Please enter the private key in WIF format for {}:'.format(args.source))
                    if not private_key_wif:
                        raise TransactionError('invalid private key')
                    signed_tx_hex = wallet.sign_raw_transaction(unsigned_hex, private_key_wif=private_key_wif)

                logger.info('Transaction (signed): {}'.format(signed_tx_hex))
                tx_hash = wallet.send_raw_transaction(signed_tx_hex)
                logger.info('Hash of transaction (broadcasted): {}'.format(tx_hash))


    # VIEWING
    elif args.action in ['balances', 'asset', 'wallet', 'pending', 'getinfo', 'getrows']:
        view = console.get_view(args.action, args)
        print_method = getattr(console, 'print_{}'.format(args.action), None)
        if args.json_output or print_method is None:
            util.json_print(view)
        else:
            print_method(view)

    else:
        parser.print_help()
Example #6
0
def setup_logging():
    print(
        "")  # for --verbose output this makes sure the logs start on a newline
    log.set_up(log.ROOT_LOGGER,
               verbose=True,
               console_logfilter=os.environ.get('COUNTERPARTY_LOGGING', None))
Example #7
0
def main():
    if os.name == 'nt':
        from counterpartylib.lib import util_windows
        #patch up cmd.exe's "challenged" (i.e. broken/non-existent) UTF-8 logging
        util_windows.fix_win32_unicode()

    # Post installation tasks
    generate_config_files()

    # Parse command-line arguments.
    parser = argparse.ArgumentParser(
        prog=APP_NAME,
        description='Server for the {} protocol'.format(config.XCP_NAME),
        add_help=False)
    parser.add_argument('-h',
                        '--help',
                        dest='help',
                        action='store_true',
                        help='show this help message and exit')
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version="{} v{}; {} v{}".format(
                            APP_NAME, APP_VERSION, 'counterparty-lib',
                            config.VERSION_STRING))
    parser.add_argument('--config-file',
                        help='the path to the configuration file')

    add_config_arguments(parser, CONFIG_ARGS, 'server.conf')

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

    parser_server = subparsers.add_parser('start', help='run the server')

    parser_reparse = subparsers.add_parser(
        'reparse', help='reparse all transactions in the database')

    parser_rollback = subparsers.add_parser('rollback',
                                            help='rollback database')
    parser_rollback.add_argument('block_index',
                                 type=int,
                                 help='the index of the last known good block')

    parser_kickstart = subparsers.add_parser(
        'kickstart',
        help='rapidly build database by reading from Bitcoin Core blockchain')
    parser_kickstart.add_argument('--bitcoind-dir',
                                  help='Bitcoin Core data directory')

    parser_bootstrap = subparsers.add_parser(
        'bootstrap', help='bootstrap database with hosted snapshot')
    parser_bootstrap.add_argument('-q',
                                  '--quiet',
                                  dest='quiet',
                                  action='store_true',
                                  help='suppress progress bar')

    args = parser.parse_args()

    log.set_up(log.ROOT_LOGGER,
               verbose=args.verbose,
               console_logfilter=os.environ.get('COUNTERPARTY_LOGGING', None))

    logger.info('Running v{} of {}.'.format(APP_VERSION, APP_NAME))

    # Help message
    if args.help:
        parser.print_help()
        sys.exit()

    # Bootstrapping
    if args.action == 'bootstrap':
        bootstrap(testnet=args.testnet, quiet=args.quiet)
        sys.exit()

    def init_with_catch(fn, init_args):
        try:
            return fn(**init_args)
        except TypeError as e:
            if 'unexpected keyword argument' in str(e):
                raise VersionError(
                    'Unsupported Server Parameter. CLI/Library Version Incompatibility.'
                )
            else:
                raise e

    # Configuration
    COMMANDS_WITH_DB = ['reparse', 'rollback', 'kickstart', 'start']
    COMMANDS_WITH_CONFIG = ['debug_config']
    if args.action in COMMANDS_WITH_DB or args.action in COMMANDS_WITH_CONFIG:
        init_args = dict(
            database_file=args.database_file,
            log_file=args.log_file,
            api_log_file=args.api_log_file,
            testnet=args.testnet,
            testcoin=args.testcoin,
            backend_name=args.backend_name,
            backend_connect=args.backend_connect,
            backend_port=args.backend_port,
            backend_user=args.backend_user,
            backend_password=args.backend_password,
            backend_ssl=args.backend_ssl,
            backend_ssl_no_verify=args.backend_ssl_no_verify,
            backend_poll_interval=args.backend_poll_interval,
            rpc_host=args.rpc_host,
            rpc_port=args.rpc_port,
            rpc_user=args.rpc_user,
            rpc_password=args.rpc_password,
            rpc_no_allow_cors=args.rpc_no_allow_cors,
            requests_timeout=args.requests_timeout,
            rpc_batch_size=args.rpc_batch_size,
            check_asset_conservation=not args.no_check_asset_conservation,
            force=args.force,
            verbose=args.verbose,
            console_logfilter=os.environ.get('COUNTERPARTY_LOGGING', None),
            p2sh_dust_return_pubkey=args.p2sh_dust_return_pubkey,
            utxo_locks_max_addresses=args.utxo_locks_max_addresses,
            utxo_locks_max_age=args.utxo_locks_max_age)
        #,broadcast_tx_mainnet=args.broadcast_tx_mainnet)

    if args.action in COMMANDS_WITH_DB:
        db = init_with_catch(server.initialise, init_args)

    elif args.action in COMMANDS_WITH_CONFIG:
        init_with_catch(server.initialise_config, init_args)

    # PARSING
    if args.action == 'reparse':
        server.reparse(db)

    elif args.action == 'rollback':
        server.reparse(db, block_index=args.block_index)

    elif args.action == 'kickstart':
        server.kickstart(db, bitcoind_dir=args.bitcoind_dir)

    elif args.action == 'start':
        server.start_all(db)

    elif args.action == 'debug_config':
        server.debug_config()

    else:
        parser.print_help()
Example #8
0
    def initialize(self, openDialog=False):
        configdir = appdirs.user_config_dir(appauthor=config.XCP_NAME,
                                            appname=config.APP_NAME,
                                            roaming=True)
        configfile = os.path.join(configdir, 'client.conf')
        config_exists = os.path.exists(configfile)

        if not config_exists:
            generate_config_file(configfile, client.CONFIG_ARGS)

        # Parse command-line arguments.
        parser = argparse.ArgumentParser(
            prog=APP_NAME,
            description=tr('Counterparty CLI for counterparty-server'),
            add_help=False,
            conflict_handler='resolve')
        parser.add_argument('-h',
                            '--help',
                            dest='help',
                            action='store_true',
                            help=tr('show this help message and exit'))
        parser.add_argument('-V',
                            '--version',
                            action='version',
                            version="{} v{}".format(APP_NAME, APP_VERSION))
        parser.add_argument(
            '--config-file',
            help=tr(
                'the location of the counterparty-client configuration file'))

        self.args = parser.parse_known_args()[0]

        if not config_exists or openDialog:
            is_splash_visible = False
            if self.splash:
                is_splash_visible = self.splash.isVisible()
                if is_splash_visible:
                    self.splash.hide()
            configfile = getattr(self.args, 'config_file', None) or configfile
            configUI = ConfigDialog(configfile, newconfig=not config_exists)
            result = configUI.exec()
            if is_splash_visible:
                self.splash.show()

        if openDialog and result == 0:
            return False

        parser = add_config_arguments(parser,
                                      CONFIG_ARGS,
                                      'client.conf',
                                      config_file_arg_name='config_file')

        self.args = parser.parse_args()

        dargs = vars(self.args)
        for argName in dargs:
            print('{}: {}'.format(argName.upper(), dargs[argName]))
            setattr(self, argName.upper(), dargs[argName])

        # Help message
        if self.args.help:
            parser.print_help()
            sys.exit()

        # Logging
        logdir = appdirs.user_log_dir(appauthor=config.XCP_NAME,
                                      appname=config.APP_NAME)
        if not os.path.exists(logdir):
            os.makedirs(logdir, mode=0o755)
        self.LOG_FILE = os.path.join(logdir, 'counterpartygui.log')
        log.set_up(logger, verbose=self.args.verbose, logfile=self.LOG_FILE)

        return True
Example #9
0
def initialise_config(database_file=None, log_file=None, api_log_file=None,
                testnet=False, testcoin=False,
                backend_name=None, backend_connect=None, backend_port=None,
                backend_user=None, backend_password=None,
                backend_ssl=False, backend_ssl_no_verify=False,
                backend_poll_interval=None,
                rpc_host=None, rpc_port=None,
                rpc_user=None, rpc_password=None,
                rpc_no_allow_cors=False,
                force=False, verbose=False, console_logfilter=None,
                requests_timeout=config.DEFAULT_REQUESTS_TIMEOUT,
                rpc_batch_size=config.DEFAULT_RPC_BATCH_SIZE,
                check_asset_conservation=config.DEFAULT_CHECK_ASSET_CONSERVATION,
                backend_ssl_verify=None, rpc_allow_cors=None, p2sh_dust_return_pubkey=None,
                utxo_locks_max_addresses=config.DEFAULT_UTXO_LOCKS_MAX_ADDRESSES,
                utxo_locks_max_age=config.DEFAULT_UTXO_LOCKS_MAX_AGE,
                estimate_fee_per_kb=None):

    # Data directory
    data_dir = appdirs.user_data_dir(appauthor=config.XCP_NAME, appname=config.APP_NAME, roaming=True)
    if not os.path.isdir(data_dir):
        os.makedirs(data_dir, mode=0o755)

    # testnet
    if testnet:
        config.TESTNET = testnet
    else:
        config.TESTNET = False

    # testcoin
    if testcoin:
        config.TESTCOIN = testcoin
    else:
        config.TESTCOIN = False

    network = ''
    if config.TESTNET:
        network += '.testnet'
    if config.TESTCOIN:
        network += '.testcoin'

    # Database
    if database_file:
        config.DATABASE = database_file
    else:
        filename = '{}{}.db'.format(config.APP_NAME, network)
        config.DATABASE = os.path.join(data_dir, filename)

    # Log directory
    log_dir = appdirs.user_log_dir(appauthor=config.XCP_NAME, appname=config.APP_NAME)
    if not os.path.isdir(log_dir):
        os.makedirs(log_dir, mode=0o755)

    # Log
    if log_file is False:  # no file logging
        config.LOG = None
    elif not log_file:  # default location
        filename = 'server{}.log'.format(network)
        config.LOG = os.path.join(log_dir, filename)
    else:  # user-specified location
        config.LOG = log_file

    # Set up logging.
    log.set_up(log.ROOT_LOGGER, verbose=verbose, logfile=config.LOG, console_logfilter=console_logfilter)
    if config.LOG:
        logger.debug('Writing server log to file: `{}`'.format(config.LOG))

    if api_log_file is False:  # no file logging
        config.API_LOG = None
    elif not api_log_file:  # default location
        filename = 'server{}.access.log'.format(network)
        config.API_LOG = os.path.join(log_dir, filename)
    else:  # user-specified location
        config.API_LOG = api_log_file
    if config.API_LOG:
        logger.debug('Writing API accesses log to file: `{}`'.format(config.API_LOG))

    # Log unhandled errors.
    def handle_exception(exc_type, exc_value, exc_traceback):
        logger.error("Unhandled Exception", exc_info=(exc_type, exc_value, exc_traceback))
    sys.excepthook = handle_exception

    ##############
    # THINGS WE CONNECT TO

    # Backend name
    if backend_name:
        config.BACKEND_NAME = backend_name
    else:
        config.BACKEND_NAME = 'addrindex'
    if config.BACKEND_NAME == 'jmcorgan':
        config.BACKEND_NAME = 'addrindex'

    # Backend RPC host (Bitcoin Core)
    if backend_connect:
        config.BACKEND_CONNECT = backend_connect
    else:
        config.BACKEND_CONNECT = 'localhost'

    # Backend Core RPC port (Bitcoin Core)
    if backend_port:
        config.BACKEND_PORT = backend_port
    else:
        if config.TESTNET:
            if config.BACKEND_NAME == 'btcd':
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_TESTNET_BTCD
            else:
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_TESTNET
        else:
            if config.BACKEND_NAME == 'btcd':
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_BTCD
            else:
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT

    try:
        config.BACKEND_PORT = int(config.BACKEND_PORT)
        if not (int(config.BACKEND_PORT) > 1 and int(config.BACKEND_PORT) < 65535):
            raise ConfigurationError('invalid backend API port number')
    except:
        raise ConfigurationError("Please specific a valid port number backend-port configuration parameter")

    # Backend Core RPC user (Bitcoin Core)
    if backend_user:
        config.BACKEND_USER = backend_user
    else:
        config.BACKEND_USER = '******'

    # Backend Core RPC password (Bitcoin Core)
    if backend_password:
        config.BACKEND_PASSWORD = backend_password
    else:
        raise ConfigurationError('backend RPC password not set. (Use configuration file or --backend-password=PASSWORD)')

    # Backend Core RPC SSL
    if backend_ssl:
        config.BACKEND_SSL = backend_ssl
    else:
        config.BACKEND_SSL = False  # Default to off.

    # Backend Core RPC SSL Verify
    if backend_ssl_verify is not None:
        logger.warning('The server parameter `backend_ssl_verify` is deprecated. Use `backend_ssl_no_verify` instead.')
        config.BACKEND_SSL_NO_VERIFY = not backend_ssl_verify
    else:
        if backend_ssl_no_verify:
            config.BACKEND_SSL_NO_VERIFY = backend_ssl_no_verify
        else:
            config.BACKEND_SSL_NO_VERIFY = False # Default to on (don't support self‐signed certificates)

    # Backend Poll Interval
    if backend_poll_interval:
        config.BACKEND_POLL_INTERVAL = backend_poll_interval
    else:
        config.BACKEND_POLL_INTERVAL = 0.5

    # Construct backend URL.
    config.BACKEND_URL = config.BACKEND_USER + ':' + config.BACKEND_PASSWORD + '@' + config.BACKEND_CONNECT + ':' + str(config.BACKEND_PORT)
    if config.BACKEND_SSL:
        config.BACKEND_URL = 'https://' + config.BACKEND_URL
    else:
        config.BACKEND_URL = 'http://' + config.BACKEND_URL


    ##############
    # THINGS WE SERVE

    # Server API RPC host
    if rpc_host:
        config.RPC_HOST = rpc_host
    else:
        config.RPC_HOST = 'localhost'

    # The web root directory for API calls, eg. localhost:14000/rpc/
    config.RPC_WEBROOT = '/rpc/'

    # Server API RPC port
    if rpc_port:
        config.RPC_PORT = rpc_port
    else:
        if config.TESTNET:
            if config.TESTCOIN:
                config.RPC_PORT = config.DEFAULT_RPC_PORT_TESTNET + 1
            else:
                config.RPC_PORT = config.DEFAULT_RPC_PORT_TESTNET
        else:
            if config.TESTCOIN:
                config.RPC_PORT = config.DEFAULT_RPC_PORT + 1
            else:
                config.RPC_PORT = config.DEFAULT_RPC_PORT
    try:
        config.RPC_PORT = int(config.RPC_PORT)
        if not (int(config.RPC_PORT) > 1 and int(config.RPC_PORT) < 65535):
            raise ConfigurationError('invalid server API port number')
    except:
        raise ConfigurationError("Please specific a valid port number rpc-port configuration parameter")

    # Server API RPC user
    if rpc_user:
        config.RPC_USER = rpc_user
    else:
        config.RPC_USER = '******'

    # Server API RPC password
    if rpc_password:
        config.RPC_PASSWORD = rpc_password
        config.RPC = 'http://' + urlencode(config.RPC_USER) + ':' + urlencode(config.RPC_PASSWORD) + '@' + config.RPC_HOST + ':' + str(config.RPC_PORT) + config.RPC_WEBROOT
    else:
        config.RPC = 'http://' + config.RPC_HOST + ':' + str(config.RPC_PORT) + config.RPC_WEBROOT

    # RPC CORS
    if rpc_allow_cors is not None:
        logger.warning('The server parameter `rpc_allow_cors` is deprecated. Use `rpc_no_allow_cors` instead.')
        config.RPC_NO_ALLOW_CORS = not rpc_allow_cors
    else:
        if rpc_no_allow_cors:
            config.RPC_NO_ALLOW_CORS = rpc_no_allow_cors
        else:
            config.RPC_NO_ALLOW_CORS = False

    config.RPC_BATCH_SIZE = rpc_batch_size

    ##############
    # OTHER SETTINGS

    # skip checks
    if force:
        config.FORCE = force
    else:
        config.FORCE = False

    # Encoding
    if config.TESTCOIN:
        config.PREFIX = b'XX'                   # 2 bytes (possibly accidentally created)
    else:
        config.PREFIX = b'CNTRPRTY'             # 8 bytes

    # (more) Testnet
    if config.TESTNET:
        config.MAGIC_BYTES = config.MAGIC_BYTES_TESTNET
        if config.TESTCOIN:
            config.ADDRESSVERSION = config.ADDRESSVERSION_TESTNET
            config.P2SH_ADDRESSVERSION = config.P2SH_ADDRESSVERSION_TESTNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_TESTNET_TESTCOIN
            config.BURN_START = config.BURN_START_TESTNET_TESTCOIN
            config.BURN_END = config.BURN_END_TESTNET_TESTCOIN
            config.UNSPENDABLE = config.UNSPENDABLE_TESTNET
            config.P2SH_DUST_RETURN_PUBKEY = p2sh_dust_return_pubkey
        else:
            config.ADDRESSVERSION = config.ADDRESSVERSION_TESTNET
            config.P2SH_ADDRESSVERSION = config.P2SH_ADDRESSVERSION_TESTNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_TESTNET
            config.BURN_START = config.BURN_START_TESTNET
            config.BURN_END = config.BURN_END_TESTNET
            config.UNSPENDABLE = config.UNSPENDABLE_TESTNET
            config.P2SH_DUST_RETURN_PUBKEY = p2sh_dust_return_pubkey
    else:
        config.MAGIC_BYTES = config.MAGIC_BYTES_MAINNET
        if config.TESTCOIN:
            config.ADDRESSVERSION = config.ADDRESSVERSION_MAINNET
            config.P2SH_ADDRESSVERSION = config.P2SH_ADDRESSVERSION_MAINNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_MAINNET_TESTCOIN
            config.BURN_START = config.BURN_START_MAINNET_TESTCOIN
            config.BURN_END = config.BURN_END_MAINNET_TESTCOIN
            config.UNSPENDABLE = config.UNSPENDABLE_MAINNET
            config.P2SH_DUST_RETURN_PUBKEY = p2sh_dust_return_pubkey
        else:
            config.ADDRESSVERSION = config.ADDRESSVERSION_MAINNET
            config.P2SH_ADDRESSVERSION = config.P2SH_ADDRESSVERSION_MAINNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_MAINNET
            config.BURN_START = config.BURN_START_MAINNET
            config.BURN_END = config.BURN_END_MAINNET
            config.UNSPENDABLE = config.UNSPENDABLE_MAINNET
            config.P2SH_DUST_RETURN_PUBKEY = p2sh_dust_return_pubkey

    # Misc
    config.REQUESTS_TIMEOUT = requests_timeout
    config.CHECK_ASSET_CONSERVATION = check_asset_conservation
    config.UTXO_LOCKS_MAX_ADDRESSES = utxo_locks_max_addresses
    config.UTXO_LOCKS_MAX_AGE = utxo_locks_max_age
    transaction.UTXO_LOCKS = None  # reset the UTXO_LOCKS (for tests really)

    if estimate_fee_per_kb is not None:
        config.ESTIMATE_FEE_PER_KB = estimate_fee_per_kb

    logger.info('Running v{} of counterparty-lib.'.format(config.VERSION_STRING))
Example #10
0
def main():
    if os.name == 'nt':
        from counterpartylib.lib import util_windows
        #patch up cmd.exe's "challenged" (i.e. broken/non-existent) UTF-8 logging
        util_windows.fix_win32_unicode()

    # Post installation tasks
    generate_config_files()

    # Parse command-line arguments.
    parser = argparse.ArgumentParser(
        prog=APP_NAME,
        description='Server for the {} protocol'.format(config.XCP_NAME),
        add_help=False)
    parser.add_argument('-h',
                        '--help',
                        dest='help',
                        action='store_true',
                        help='show this help message and exit')
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version="{} v{}; {} v{}".format(
                            APP_NAME, APP_VERSION, 'counterparty-lib',
                            config.VERSION_STRING))
    parser.add_argument('--config-file',
                        help='the path to the configuration file')

    parser = add_config_arguments(parser, CONFIG_ARGS, 'server.conf')

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

    parser_server = subparsers.add_parser('start', help='run the server')

    parser_reparse = subparsers.add_parser(
        'reparse', help='reparse all transactions in the database')

    parser_rollback = subparsers.add_parser('rollback',
                                            help='rollback database')
    parser_rollback.add_argument('block_index',
                                 type=int,
                                 help='the index of the last known good block')

    parser_kickstart = subparsers.add_parser(
        'kickstart',
        help='rapidly build database by reading from Bitcoin Core blockchain')
    parser_kickstart.add_argument('--bitcoind-dir',
                                  help='Bitcoin Core data directory')

    parser_bootstrap = subparsers.add_parser(
        'bootstrap', help='bootstrap database with hosted snapshot')

    args = parser.parse_args()

    log.set_up(logger, verbose=args.verbose)

    logger.info('Running v{} of {}.'.format(APP_VERSION, APP_NAME))

    # Help message
    if args.help:
        parser.print_help()
        sys.exit()

    # Bootstrapping
    if args.action == 'bootstrap':
        bootstrap(testnet=args.testnet)
        sys.exit()

    # Configuration
    if args.action in ['reparse', 'rollback', 'kickstart', 'start']:
        try:
            db = server.initialise(
                database_file=args.database_file,
                log_file=args.log_file,
                api_log_file=args.api_log_file,
                testnet=args.testnet,
                testcoin=args.testcoin,
                backend_name=args.backend_name,
                backend_connect=args.backend_connect,
                backend_port=args.backend_port,
                backend_user=args.backend_user,
                backend_password=args.backend_password,
                backend_ssl=args.backend_ssl,
                backend_ssl_no_verify=args.backend_ssl_no_verify,
                backend_poll_interval=args.backend_poll_interval,
                rpc_host=args.rpc_host,
                rpc_port=args.rpc_port,
                rpc_user=args.rpc_user,
                rpc_password=args.rpc_password,
                rpc_no_allow_cors=args.rpc_no_allow_cors,
                force=args.force,
                verbose=args.verbose)
            #,broadcast_tx_mainnet=args.broadcast_tx_mainnet)
        except TypeError as e:
            if 'unexpected keyword argument' in str(e):
                raise VersionError(
                    'Unsupported Server Parameter. CLI/Library Version Incompatibility.'
                )
            else:
                raise e

    # PARSING
    if args.action == 'reparse':
        server.reparse(db)

    elif args.action == 'rollback':
        server.reparse(db, block_index=args.block_index)

    elif args.action == 'kickstart':
        server.kickstart(db, bitcoind_dir=args.bitcoind_dir)

    elif args.action == 'start':
        server.start_all(db)

    else:
        parser.print_help()
def initialise(
    database_file=None,
    log_file=None,
    api_log_file=None,
    testnet=False,
    testcoin=False,
    backend_name=None,
    backend_connect=None,
    backend_port=None,
    backend_user=None,
    backend_password=None,
    backend_ssl=False,
    backend_ssl_no_verify=False,
    backend_poll_interval=None,
    rpc_host=None,
    rpc_port=None,
    rpc_user=None,
    rpc_password=None,
    rpc_no_allow_cors=False,
    force=False,
    verbose=False,
    requests_timeout=config.DEFAULT_REQUESTS_TIMEOUT,
    rpc_batch_size=config.DEFAULT_RPC_BATCH_SIZE,
    check_asset_conservation=config.DEFAULT_CHECK_ASSET_CONSERVATION,
    backend_ssl_verify=None,
    rpc_allow_cors=None,
):

    # Data directory
    data_dir = appdirs.user_data_dir(appauthor=config.XCP_NAME, appname=config.APP_NAME, roaming=True)
    if not os.path.isdir(data_dir):
        os.makedirs(data_dir, mode=0o755)

    # testnet
    if testnet:
        config.TESTNET = testnet
    else:
        config.TESTNET = False

    # testcoin
    if testcoin:
        config.TESTCOIN = testcoin
    else:
        config.TESTCOIN = False

    network = ""
    if config.TESTNET:
        network += ".testnet"
    if config.TESTCOIN:
        network += ".testcoin"

    # Database
    if database_file:
        config.DATABASE = database_file
    else:
        filename = "{}{}.db".format(config.APP_NAME, network)
        config.DATABASE = os.path.join(data_dir, filename)

    # Log directory
    log_dir = appdirs.user_log_dir(appauthor=config.XCP_NAME, appname=config.APP_NAME)
    if not os.path.isdir(log_dir):
        os.makedirs(log_dir, mode=0o755)

    # Log
    if log_file:
        config.LOG = log_file
    else:
        filename = "server{}.log".format(network)
        config.LOG = os.path.join(log_dir, filename)
    logger.debug("Writing server log to file: `{}`".format(config.LOG))

    if api_log_file:
        config.API_LOG = api_log_file
    else:
        filename = "server{}.access.log".format(network)
        config.API_LOG = os.path.join(log_dir, filename)
    logger.debug("Writing API accesses log to file: `{}`".format(config.API_LOG))

    # Set up logging.
    root_logger = logging.getLogger()  # Get root logger.
    log.set_up(root_logger, verbose=verbose, logfile=config.LOG)
    # Log unhandled errors.
    def handle_exception(exc_type, exc_value, exc_traceback):
        logger.error("Unhandled Exception", exc_info=(exc_type, exc_value, exc_traceback))

    sys.excepthook = handle_exception

    ##############
    # THINGS WE CONNECT TO

    # Backend name
    if backend_name:
        config.BACKEND_NAME = backend_name
    else:
        config.BACKEND_NAME = "addrindex"
    if config.BACKEND_NAME == "jmcorgan":
        config.BACKEND_NAME = "addrindex"

    # Backend RPC host (Bitcoin Core)
    if backend_connect:
        config.BACKEND_CONNECT = backend_connect
    else:
        config.BACKEND_CONNECT = "localhost"

    # Backend Core RPC port (Bitcoin Core)
    if backend_port:
        config.BACKEND_PORT = backend_port
    else:
        if config.TESTNET:
            if config.BACKEND_NAME == "btcd":
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_TESTNET_BTCD
            else:
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_TESTNET
        else:
            if config.BACKEND_NAME == "btcd":
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_BTCD
            else:
                config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT

    try:
        config.BACKEND_PORT = int(config.BACKEND_PORT)
        if not (int(config.BACKEND_PORT) > 1 and int(config.BACKEND_PORT) < 65535):
            raise ConfigurationError("invalid backend API port number")
    except:
        raise ConfigurationError("Please specific a valid port number backend-port configuration parameter")

    # Backend Core RPC user (Bitcoin Core)
    if backend_user:
        config.BACKEND_USER = backend_user
    else:
        config.BACKEND_USER = "******"

    # Backend Core RPC password (Bitcoin Core)
    if backend_password:
        config.BACKEND_PASSWORD = backend_password
    else:
        raise ConfigurationError(
            "backend RPC password not set. (Use configuration file or --backend-password=PASSWORD)"
        )

    # Backend Core RPC SSL
    if backend_ssl:
        config.BACKEND_SSL = backend_ssl
    else:
        config.BACKEND_SSL = False  # Default to off.

    # Backend Core RPC SSL Verify
    if backend_ssl_verify is not None:
        logger.warning("The server parameter `backend_ssl_verify` is deprecated. Use `backend_ssl_no_verify` instead.")
        config.BACKEND_SSL_NO_VERIFY = not backend_ssl_verify
    else:
        if backend_ssl_no_verify:
            config.BACKEND_SSL_NO_VERIFY = backend_ssl_no_verify
        else:
            config.BACKEND_SSL_NO_VERIFY = False  # Default to on (don't support self‐signed certificates)

    # Backend Poll Interval
    if backend_poll_interval:
        config.BACKEND_POLL_INTERVAL = backend_poll_interval
    else:
        config.BACKEND_POLL_INTERVAL = 0.5

    # Construct backend URL.
    config.BACKEND_URL = (
        config.BACKEND_USER
        + ":"
        + config.BACKEND_PASSWORD
        + "@"
        + config.BACKEND_CONNECT
        + ":"
        + str(config.BACKEND_PORT)
    )
    if config.BACKEND_SSL:
        config.BACKEND_URL = "https://" + config.BACKEND_URL
    else:
        config.BACKEND_URL = "http://" + config.BACKEND_URL

    ##############
    # THINGS WE SERVE

    # Server API RPC host
    if rpc_host:
        config.RPC_HOST = rpc_host
    else:
        config.RPC_HOST = "localhost"

    # The web root directory for API calls, eg. localhost:14000/rpc/
    config.RPC_WEBROOT = "/rpc/"

    # Server API RPC port
    if rpc_port:
        config.RPC_PORT = rpc_port
    else:
        if config.TESTNET:
            if config.TESTCOIN:
                config.RPC_PORT = config.DEFAULT_RPC_PORT_TESTNET + 1
            else:
                config.RPC_PORT = config.DEFAULT_RPC_PORT_TESTNET
        else:
            if config.TESTCOIN:
                config.RPC_PORT = config.DEFAULT_RPC_PORT + 1
            else:
                config.RPC_PORT = config.DEFAULT_RPC_PORT
    try:
        config.RPC_PORT = int(config.RPC_PORT)
        if not (int(config.RPC_PORT) > 1 and int(config.RPC_PORT) < 65535):
            raise ConfigurationError("invalid server API port number")
    except:
        raise ConfigurationError("Please specific a valid port number rpc-port configuration parameter")

    # Server API RPC user
    if rpc_user:
        config.RPC_USER = rpc_user
    else:
        config.RPC_USER = "******"

    # Server API RPC password
    if rpc_password:
        config.RPC_PASSWORD = rpc_password
        config.RPC = (
            "http://"
            + urlencode(config.RPC_USER)
            + ":"
            + urlencode(config.RPC_PASSWORD)
            + "@"
            + config.RPC_HOST
            + ":"
            + str(config.RPC_PORT)
            + config.RPC_WEBROOT
        )
    else:
        config.RPC = "http://" + config.RPC_HOST + ":" + str(config.RPC_PORT) + config.RPC_WEBROOT

    # RPC CORS
    if rpc_allow_cors is not None:
        logger.warning("The server parameter `rpc_allow_cors` is deprecated. Use `rpc_no_allow_cors` instead.")
        config.RPC_NO_ALLOW_CORS = not rpc_allow_cors
    else:
        if rpc_no_allow_cors:
            config.RPC_NO_ALLOW_CORS = rpc_no_allow_cors
        else:
            config.RPC_NO_ALLOW_CORS = False

    config.REQUESTS_TIMEOUT = requests_timeout
    config.RPC_BATCH_SIZE = rpc_batch_size
    config.CHECK_ASSET_CONSERVATION = check_asset_conservation

    ##############
    # OTHER SETTINGS

    # skip checks
    if force:
        config.FORCE = force
    else:
        config.FORCE = False

    # Encoding
    if config.TESTCOIN:
        config.PREFIX = b"XX"  # 2 bytes (possibly accidentally created)
    else:
        config.PREFIX = b"CNTRPRTY"  # 8 bytes

    # (more) Testnet
    if config.TESTNET:
        config.MAGIC_BYTES = config.MAGIC_BYTES_TESTNET
        if config.TESTCOIN:
            config.ADDRESSVERSION = config.ADDRESSVERSION_TESTNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_TESTNET_TESTCOIN
            config.BURN_START = config.BURN_START_TESTNET_TESTCOIN
            config.BURN_END = config.BURN_END_TESTNET_TESTCOIN
            config.UNSPENDABLE = config.UNSPENDABLE_TESTNET
        else:
            config.ADDRESSVERSION = config.ADDRESSVERSION_TESTNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_TESTNET
            config.BURN_START = config.BURN_START_TESTNET
            config.BURN_END = config.BURN_END_TESTNET
            config.UNSPENDABLE = config.UNSPENDABLE_TESTNET
    else:
        config.MAGIC_BYTES = config.MAGIC_BYTES_MAINNET
        if config.TESTCOIN:
            config.ADDRESSVERSION = config.ADDRESSVERSION_MAINNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_MAINNET_TESTCOIN
            config.BURN_START = config.BURN_START_MAINNET_TESTCOIN
            config.BURN_END = config.BURN_END_MAINNET_TESTCOIN
            config.UNSPENDABLE = config.UNSPENDABLE_MAINNET
        else:
            config.ADDRESSVERSION = config.ADDRESSVERSION_MAINNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_MAINNET
            config.BURN_START = config.BURN_START_MAINNET
            config.BURN_END = config.BURN_END_MAINNET
            config.UNSPENDABLE = config.UNSPENDABLE_MAINNET

    logger.info("Running v{} of counterparty-lib.".format(config.VERSION_STRING))

    if config.FORCE:
        logger.warning("THE OPTION `--force` IS NOT FOR USE ON PRODUCTION SYSTEMS.")

    # Lock
    if not config.FORCE:
        get_lock()

    # Database
    logger.info("Connecting to database.")
    db = database.get_connection(read_only=False)

    util.CURRENT_BLOCK_INDEX = blocks.last_db_index(db)

    return db
Example #12
0
def initialise(database_file=None,
               log_file=None,
               api_log_file=None,
               testnet=False,
               testcoin=False,
               backend_name=None,
               backend_connect=None,
               backend_port=None,
               backend_user=None,
               backend_password=None,
               backend_ssl=False,
               backend_ssl_verify=True,
               backend_poll_interval=None,
               rpc_host=None,
               rpc_port=None,
               rpc_user=None,
               rpc_password=None,
               rpc_allow_cors=None,
               force=False,
               verbose=False):

    # Data directory
    data_dir = appdirs.user_data_dir(appauthor=config.XCP_NAME,
                                     appname=config.APP_NAME,
                                     roaming=True)
    if not os.path.isdir(data_dir):
        os.makedirs(data_dir, mode=0o755)

    # testnet
    if testnet:
        config.TESTNET = testnet
    else:
        config.TESTNET = False

    # testcoin
    if testcoin:
        config.TESTCOIN = testcoin
    else:
        config.TESTCOIN = False

    network = ''
    if config.TESTNET:
        network += '.testnet'
    if config.TESTCOIN:
        network += '.testcoin'

    # Database
    if database_file:
        config.DATABASE = database_file
    else:
        filename = '{}{}.db'.format(config.APP_NAME, network)
        config.DATABASE = os.path.join(data_dir, filename)

    # Log directory
    log_dir = appdirs.user_log_dir(appauthor=config.XCP_NAME,
                                   appname=config.APP_NAME)
    if not os.path.isdir(log_dir):
        os.makedirs(log_dir, mode=0o755)

    # Log
    if log_file:
        config.LOG = log_file
    else:
        filename = 'server{}.log'.format(network)
        config.LOG = os.path.join(log_dir, filename)
    logger.debug('Writing server log to file: `{}`'.format(config.LOG))

    if api_log_file:
        config.API_LOG = api_log_file
    else:
        filename = 'server{}.api.log'.format(network)
        config.API_LOG = os.path.join(log_dir, filename)
    logger.debug('Writing API log to file: `{}`'.format(config.API_LOG))

    ##############
    # THINGS WE CONNECT TO

    # Backend name
    if backend_name:
        config.BACKEND_NAME = backend_name
    else:
        config.BACKEND_NAME = 'addrindex'
    if config.BACKEND_NAME == 'jmcorgan':
        config.BACKEND_NAME = 'addrindex'

    # Backend RPC host (Bitcoin Core)
    if backend_connect:
        config.BACKEND_CONNECT = backend_connect
    else:
        config.BACKEND_CONNECT = 'localhost'

    # Backend Core RPC port (Bitcoin Core)
    if backend_port:
        config.BACKEND_PORT = backend_port
    else:
        if config.TESTNET:
            config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT_TESTNET
        else:
            config.BACKEND_PORT = config.DEFAULT_BACKEND_PORT
    try:
        config.BACKEND_PORT = int(config.BACKEND_PORT)
        if not (int(config.BACKEND_PORT) > 1
                and int(config.BACKEND_PORT) < 65535):
            raise ConfigurationError('invalid backend API port number')
    except:
        raise ConfigurationError(
            "Please specific a valid port number backend-port configuration parameter"
        )

    # Backend Core RPC user (Bitcoin Core)
    if backend_user:
        config.BACKEND_USER = backend_user
    else:
        config.BACKEND_USER = '******'

    # Backend Core RPC password (Bitcoin Core)
    if backend_password:
        config.BACKEND_PASSWORD = backend_password
    else:
        raise ConfigurationError(
            'backend RPC password not set. (Use configuration file or --backend-password=PASSWORD)'
        )

    # Backend Core RPC SSL
    if backend_ssl:
        config.BACKEND_SSL = backend_ssl
    else:
        config.BACKEND_SSL = False  # Default to off.

    # Backend Core RPC SSL Verify
    if backend_ssl_verify is not None:
        config.BACKEND_SSL_VERIFY = backend_ssl_verify
    else:
        config.BACKEND_SSL_VERIFY = True  # Default to on (don't support self‐signed certificates)

    # Backend Poll Interval
    if backend_poll_interval:
        config.BACKEND_POLL_INTERVAL = backend_poll_interval
    else:
        config.BACKEND_POLL_INTERVAL = 2.0

    # Construct backend URL.
    config.BACKEND_URL = config.BACKEND_USER + ':' + config.BACKEND_PASSWORD + '@' + config.BACKEND_CONNECT + ':' + str(
        config.BACKEND_PORT)
    if config.BACKEND_SSL:
        config.BACKEND_URL = 'https://' + config.BACKEND_URL
    else:
        config.BACKEND_URL = 'http://' + config.BACKEND_URL

    ##############
    # THINGS WE SERVE

    # counterpartyd API RPC host
    if rpc_host:
        config.RPC_HOST = rpc_host
    else:
        config.RPC_HOST = 'localhost'

    # counterpartyd API RPC port
    if rpc_port:
        config.RPC_PORT = rpc_port
    else:
        if config.TESTNET:
            if config.TESTCOIN:
                config.RPC_PORT = config.DEFAULT_RPC_PORT_TESTNET + 1
            else:
                config.RPC_PORT = config.DEFAULT_RPC_PORT_TESTNET
        else:
            if config.TESTCOIN:
                config.RPC_PORT = config.DEFAULT_RPC_PORT + 1
            else:
                config.RPC_PORT = config.DEFAULT_RPC_PORT
    try:
        config.RPC_PORT = int(config.RPC_PORT)
        if not (int(config.RPC_PORT) > 1 and int(config.RPC_PORT) < 65535):
            raise ConfigurationError('invalid counterpartyd API port number')
    except:
        raise ConfigurationError(
            "Please specific a valid port number rpc-port configuration parameter"
        )

    #  counterpartyd API RPC user
    if rpc_user:
        config.RPC_USER = rpc_user
    else:
        config.RPC_USER = '******'

    #  counterpartyd API RPC password
    if rpc_password:
        config.RPC_PASSWORD = rpc_password
    else:
        raise ConfigurationError(
            'RPC password not set. (Use configuration file or --rpc-password=PASSWORD)'
        )

    config.RPC = 'http://' + urlencode(config.RPC_USER) + ':' + urlencode(
        config.RPC_PASSWORD) + '@' + config.RPC_HOST + ':' + str(
            config.RPC_PORT)

    # RPC CORS
    if rpc_allow_cors is not None:
        config.RPC_ALLOW_CORS = rpc_allow_cors
    else:
        config.RPC_ALLOW_CORS = True

    ##############
    # OTHER SETTINGS

    # skip checks
    if force:
        config.FORCE = force
    else:
        config.FORCE = False

    # Encoding
    if config.TESTCOIN:
        config.PREFIX = b'XX'  # 2 bytes (possibly accidentally created)
    else:
        config.PREFIX = b'CNTRPRTY'  # 8 bytes

    # (more) Testnet
    if config.TESTNET:
        config.MAGIC_BYTES = config.MAGIC_BYTES_TESTNET
        if config.TESTCOIN:
            config.ADDRESSVERSION = config.ADDRESSVERSION_TESTNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_TESTNET_TESTCOIN
            config.BURN_START = config.BURN_START_TESTNET_TESTCOIN
            config.BURN_END = config.BURN_END_TESTNET_TESTCOIN
            config.UNSPENDABLE = config.UNSPENDABLE_TESTNET
        else:
            config.ADDRESSVERSION = config.ADDRESSVERSION_TESTNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_TESTNET
            config.BURN_START = config.BURN_START_TESTNET
            config.BURN_END = config.BURN_END_TESTNET
            config.UNSPENDABLE = config.UNSPENDABLE_TESTNET
    else:
        config.MAGIC_BYTES = config.MAGIC_BYTES_MAINNET
        if config.TESTCOIN:
            config.ADDRESSVERSION = config.ADDRESSVERSION_MAINNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_MAINNET_TESTCOIN
            config.BURN_START = config.BURN_START_MAINNET_TESTCOIN
            config.BURN_END = config.BURN_END_MAINNET_TESTCOIN
            config.UNSPENDABLE = config.UNSPENDABLE_MAINNET
        else:
            config.ADDRESSVERSION = config.ADDRESSVERSION_MAINNET
            config.BLOCK_FIRST = config.BLOCK_FIRST_MAINNET
            config.BURN_START = config.BURN_START_MAINNET
            config.BURN_END = config.BURN_END_MAINNET
            config.UNSPENDABLE = config.UNSPENDABLE_MAINNET

    # Set up logging.
    root_logger = logging.getLogger()  # Get root logger.
    log.set_up(root_logger, verbose=verbose, logfile=config.LOG)

    # Log unhandled errors.
    def handle_exception(exc_type, exc_value, exc_traceback):
        logger.error("Unhandled Exception",
                     exc_info=(exc_type, exc_value, exc_traceback))

    sys.excepthook = handle_exception

    logger.info('Running v{} of counterparty-lib.'.format(
        config.VERSION_STRING))

    if config.FORCE:
        logger.warning(
            'THE OPTION `--force` IS NOT FOR USE ON PRODUCTION SYSTEMS.')

    # Lock
    if not config.FORCE:
        get_lock()

    # Database
    logger.info('Connecting to database.')
    db = database.get_connection(read_only=False)

    util.CURRENT_BLOCK_INDEX = blocks.last_db_index(db)

    return db
def setup_logging():
    print("")  # for --verbose output this makes sure the logs start on a newline
    log.set_up(log.ROOT_LOGGER, verbose=True, console_logfilter=os.environ.get('COUNTERPARTY_LOGGING', None))
Example #14
0
import collections
import logging
import binascii
from datetime import datetime
from dateutil.tz import tzlocal
import argparse
import configparser
import appdirs
import tarfile
import urllib.request
import shutil
import codecs

from counterpartylib.lib import log
logger = logging.getLogger(__name__)
log.set_up(logger)

D = decimal.Decimal

from counterpartylib import server
from counterpartylib.lib import config
from counterpartylib.lib.util import value_input, value_output

rpc_sessions = {}

json_print = lambda x: print(json.dumps(x, sort_keys=True, indent=4))

class RPCError(Exception):
    pass

def rpc(url, method, params=None, ssl_verify=False):